diff options
| author | Oskar <oskar@mullvad.net> | 2025-10-28 09:33:33 +0100 |
|---|---|---|
| committer | Oskar <oskar@mullvad.net> | 2025-10-28 09:33:33 +0100 |
| commit | 9e3e825e8c20870457410fd1a9568a4899ad93d8 (patch) | |
| tree | 3c078834ddd21250cf3c931cb108f42c0cf53102 | |
| parent | bbb3ffea3df68d5e08bed6dd7e5c4fc8bdc05129 (diff) | |
| parent | eae849668022e5a9e478a71746e5b896b9aaac1f (diff) | |
| download | mullvadvpn-ios-min-17.tar.xz mullvadvpn-ios-min-17.zip | |
Merge branch 'run-release-utilities-from-repo'ios-min-17
| -rw-r--r-- | .github/CODEOWNERS | 3 | ||||
| -rwxr-xr-x | desktop/scripts/release/1-prepare-release | 13 | ||||
| -rwxr-xr-x | desktop/scripts/release/2-create-and-push-tag | 3 | ||||
| -rwxr-xr-x | desktop/scripts/release/3-verify-build | 3 | ||||
| -rwxr-xr-x | desktop/scripts/release/4-make-release | 39 | ||||
| -rwxr-xr-x | desktop/scripts/release/5-update-and-publish-metadata | 77 | ||||
| -rwxr-xr-x | desktop/scripts/release/6-modify-rollout | 63 | ||||
| -rwxr-xr-x | desktop/scripts/release/download-release-artifacts | 9 | ||||
| -rw-r--r-- | desktop/scripts/release/release-config.sh | 9 | ||||
| -rwxr-xr-x | desktop/scripts/release/verify-version-is-release | 8 | ||||
| -rw-r--r-- | mullvad-update/mullvad-release/src/main.rs | 11 | ||||
| -rw-r--r-- | mullvad-update/mullvad-release/src/platform.rs | 15 | ||||
| -rwxr-xr-x | scripts/utils/commit-verification | 14 |
13 files changed, 141 insertions, 126 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 513a1d3845..73768f8feb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -18,6 +18,9 @@ /ci/buildserver* @faern @raksooo /ci/linux-repository-builder/ @faern @raksooo +# Desktop release config specifying code signing key fingerprint +/desktop/scripts/release/release-config.sh + # Cargo deny config must be approved by tech lead or desktop team lead **/deny.toml @faern @raksooo diff --git a/desktop/scripts/release/1-prepare-release b/desktop/scripts/release/1-prepare-release index b76487d5cb..1a0fc302bb 100755 --- a/desktop/scripts/release/1-prepare-release +++ b/desktop/scripts/release/1-prepare-release @@ -10,10 +10,11 @@ cd "$SCRIPT_DIR" REPO_ROOT=../../../ +$REPO_ROOT/scripts/utils/commit-verification + source $REPO_ROOT/scripts/utils/log source $REPO_ROOT/scripts/utils/print-and-run - for argument in "$@"; do case "$argument" in -*) @@ -48,15 +49,6 @@ function checks { fi } -function check_commit_signature { - if ! git verify-commit HEAD; then - log_error \ - "Current commit lacks valid signature. Releases can only be made from signed commits." - exit 1 - fi - echo "" -} - function check_changelog { previous_version=$(grep -oP '## \[\K[^\]]+' $changelog_path | head -2 | tail -1) @@ -104,7 +96,6 @@ function update_product_version { } checks -check_commit_signature check_changelog update_changelog update_copyright_year diff --git a/desktop/scripts/release/2-create-and-push-tag b/desktop/scripts/release/2-create-and-push-tag index 17ff71edd6..eebec4e4e2 100755 --- a/desktop/scripts/release/2-create-and-push-tag +++ b/desktop/scripts/release/2-create-and-push-tag @@ -12,6 +12,8 @@ PRODUCT_VERSION_PATH=$REPO_ROOT/dist-assets/desktop-product-version.txt PRODUCT_VERSION=$(cat $PRODUCT_VERSION_PATH) BASE_URL="https://releases.mullvad.net/desktop/releases/$PRODUCT_VERSION" +$REPO_ROOT/scripts/utils/commit-verification + source $REPO_ROOT/scripts/utils/print-and-run source $REPO_ROOT/scripts/utils/log @@ -53,7 +55,6 @@ function wait_for_build { log_success "\nAll artifacts are now available" } -git verify-commit HEAD push_tag log_success "Follow build progress here: $BASE_URL" diff --git a/desktop/scripts/release/3-verify-build b/desktop/scripts/release/3-verify-build index f5156b2420..f9f07f24e9 100755 --- a/desktop/scripts/release/3-verify-build +++ b/desktop/scripts/release/3-verify-build @@ -14,6 +14,9 @@ PRODUCT_VERSION_PATH=$REPO_ROOT/dist-assets/desktop-product-version.txt PRODUCT_VERSION=$(cat $PRODUCT_VERSION_PATH) $REPO_ROOT/scripts/utils/gh-ready-check +$REPO_ROOT/scripts/utils/commit-verification +"$SCRIPT_DIR/verify-version-is-release" + source $REPO_ROOT/scripts/utils/log WAIT="false" diff --git a/desktop/scripts/release/4-make-release b/desktop/scripts/release/4-make-release index 7274e50056..9766223ec0 100755 --- a/desktop/scripts/release/4-make-release +++ b/desktop/scripts/release/4-make-release @@ -8,43 +8,30 @@ set -eu SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" -if [ $# -ne 1 ]; then - echo "Please provide the following arguments:" - echo " $(basename "$0") \\" - echo " <product version>" - exit 1 -fi +REPO_ROOT=../../../ +PRODUCT_VERSION_PATH=$REPO_ROOT/dist-assets/desktop-product-version.txt +PRODUCT_VERSION=$(cat $PRODUCT_VERSION_PATH) +CHANGELOG_PATH=$REPO_ROOT/CHANGELOG.md -# Duplicated from /scripts/utils/gh-ready-check -if ! command -v gh > /dev/null; then - echo "gh (GitHub CLI) is required to run this script" - exit 1 -fi -if ! gh auth status > /dev/null; then - echo "Authentication through gh (GitHub CLI) is required to run this script" - exit 1 -fi - -PRODUCT_VERSION=$1 +$REPO_ROOT/scripts/utils/gh-ready-check +$REPO_ROOT/scripts/utils/commit-verification +"$SCRIPT_DIR/verify-version-is-release" # shellcheck source=desktop/scripts/release/release-config.sh source "$SCRIPT_DIR/release-config.sh" +source $REPO_ROOT/scripts/utils/log rm -rf "$ARTIFACT_DIR" && mkdir -p "$ARTIFACT_DIR" || exit 1 function publish_release { - echo ">>> Downloading changelog" - local changelog_path - changelog_path=$(mktemp) - curl -o "$changelog_path" --progress-bar \ - "https://raw.githubusercontent.com/mullvad/mullvadvpn-app/refs/tags/$PRODUCT_VERSION/CHANGELOG.md" + log_header "Downloading changelog" changelog_end_version_pattern="20[0-9]\{2\}\.[0-9]\{1,2\}" if [[ $PRODUCT_VERSION == *-beta* ]]; then changelog_end_version_pattern=".*" fi - changelog_extract=$(sed -n "/^## \[$PRODUCT_VERSION\]/,/^## \[$changelog_end_version_pattern\]/p" "$changelog_path") + changelog_extract=$(sed -n "/^## \[$PRODUCT_VERSION\]/,/^## \[$changelog_end_version_pattern\]/p" "$CHANGELOG_PATH") changelog=$(echo "$changelog_extract" | sed '$d' | \ awk 'NF { last = last ? last ORS $0 : $0 } END { print last }') @@ -75,14 +62,12 @@ function publish_release { body+="\n$changelog" - echo "" - echo ">>> Creating GitHub release" + log_header "Creating GitHub release" # shellcheck disable=SC2059 # shellcheck disable=SC2046 printf "$body" | gh release create "${release_flags[@]}" "$PRODUCT_VERSION" $(printf "%s " "$ARTIFACT_DIR"/*) - echo "" - echo "The above URL contains the text \"untagged\", but don't worry it is tagged properly and everything will look correct once it's published." + log_success "\nThe above URL contains the text \"untagged\", but don't worry it is tagged properly and everything will look correct once it's published." } ./download-release-artifacts "$PRODUCT_VERSION" "$ARTIFACT_DIR" diff --git a/desktop/scripts/release/5-update-and-publish-metadata b/desktop/scripts/release/5-update-and-publish-metadata index 0da2bde1ec..0805ff7c7b 100755 --- a/desktop/scripts/release/5-update-and-publish-metadata +++ b/desktop/scripts/release/5-update-and-publish-metadata @@ -10,10 +10,16 @@ set -eu SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" -if [ $# -ne 3 ]; then +REPO_ROOT=../../../ +PRODUCT_VERSION_PATH=$REPO_ROOT/dist-assets/desktop-product-version.txt +PRODUCT_VERSION=$(cat $PRODUCT_VERSION_PATH) + +$REPO_ROOT/scripts/utils/commit-verification +"$SCRIPT_DIR/verify-version-is-release" + +if [ $# -ne 2 ]; then echo "Please provide the following arguments:" echo " $(basename "$0") \\" - echo " <product version> \\" echo " <build server SSH destination> \\" echo " <metadata server SSH destination>" echo "" @@ -21,72 +27,67 @@ if [ $# -ne 3 ]; then exit 1 fi -PRODUCT_VERSION=$1 # The hostname (can be the alias in your ~/.ssh/config) of the build server -BUILDSERVER_HOST=$2 +BUILDSERVER_HOST=$1 # The server to upload the metadata to *from* the build server (argument above) -METADATA_SERVER_HOST=$3 +METADATA_SERVER_HOST=$2 # shellcheck source=desktop/scripts/release/release-config.sh source "$SCRIPT_DIR/release-config.sh" +source $REPO_ROOT/scripts/utils/log function publish_metadata { local platforms platforms=(windows macos linux) - local signed_dir="signed/" - local work_dir="work/" - local published_dir="currently_published/" - local upload_dir="upload/" - local latest_path="latest.json" + local signed_dir="$DATA_DIR/signed/" + local work_dir="$DATA_DIR/work/" + local published_dir="$DATA_DIR/currently_published/" + local upload_dir="$DATA_DIR/upload/" + local latest_filename="latest.json" + + local mullvad_release="cargo run -q --package mullvad-release --" rm -rf "$signed_dir" rm -rf "$work_dir" rm -rf "$published_dir" rm -rf "$upload_dir" - echo ">>> Fetching current version metadata" - mullvad-release pull --assume-yes --latest-file "${platforms[@]}" - echo "" + mkdir -p "$DATA_DIR" - echo ">>> Backing up released data" - cp -r $signed_dir $published_dir - cp "$latest_path" "$published_dir" - echo "" + log_header "Fetching current version metadata" + $mullvad_release pull --assume-yes --latest-file "${platforms[@]}" + + log_header "Backing up released data" + cp -r "$signed_dir" "$published_dir" + cp "$DATA_DIR/$latest_filename" "$published_dir" - echo ">>> Replacing $work_dir directory with latest published data" + log_header "Replacing $work_dir directory with latest published data" cp -rf "$signed_dir" "$work_dir" - echo "" - echo ">>> Adding new release $PRODUCT_VERSION (rollout = 1)" - mullvad-release add-release "$PRODUCT_VERSION" --rollout 1 "${platforms[@]}" - echo "" + log_header "Adding new release $PRODUCT_VERSION (rollout = 1)" + $mullvad_release add-release "$PRODUCT_VERSION" --rollout 1 "${platforms[@]}" - echo ">>> Signing $PRODUCT_VERSION metadata. Reading signing key from clipboard" - xclip -sensitive | mullvad-release sign "${platforms[@]}" - echo "" + log_header "Signing $PRODUCT_VERSION metadata. Reading signing key from clipboard" + xclip -sensitive | $mullvad_release sign "${platforms[@]}" - echo ">>> Verifying signed metadata" - mullvad-release verify "${platforms[@]}" - echo "" + log_header "Verifying signed metadata" + $mullvad_release verify "${platforms[@]}" - echo ">>> Creating upload dir" + log_header "Creating upload dir" cp -rf "$signed_dir" "$upload_dir" - echo "" - echo ">>> Generating $latest_path for current version metadata" - mullvad-release query-latest "${platforms[@]}" > "$upload_dir/$latest_path" - echo "" + log_header "Generating $latest_filename for current version metadata" + $mullvad_release query-latest "${platforms[@]}" > "$upload_dir/$latest_filename" - echo ">>> New metadata including $PRODUCT_VERSION" - git --no-pager diff --no-index -- $published_dir $upload_dir || true - echo "" + log_header "New metadata including $PRODUCT_VERSION" + git --no-pager diff --no-index -- "$published_dir" "$upload_dir" || true read -rp "Press enter to upload if the diffs look good " - ./publish-metadata-to-api $upload_dir "$BUILDSERVER_HOST" "$METADATA_SERVER_HOST" + ./publish-metadata-to-api "$upload_dir" "$BUILDSERVER_HOST" "$METADATA_SERVER_HOST" } function remove_release_artifacts { - echo ">>> Cleaning up $ARTIFACT_DIR" + log_header "Cleaning up $ARTIFACT_DIR" rm -r "$ARTIFACT_DIR" } diff --git a/desktop/scripts/release/6-modify-rollout b/desktop/scripts/release/6-modify-rollout index b3993f50dc..8278dabe16 100755 --- a/desktop/scripts/release/6-modify-rollout +++ b/desktop/scripts/release/6-modify-rollout @@ -12,6 +12,9 @@ set -eu SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" +REPO_ROOT=../../../ +$REPO_ROOT/scripts/utils/commit-verification + if [ $# -lt 5 ]; then echo "Please provide the following arguments:" echo " $(basename "$0") \\" @@ -39,61 +42,55 @@ PLATFORMS=("$@") # shellcheck source=desktop/scripts/release/release-config.sh source "$SCRIPT_DIR/release-config.sh" +source $REPO_ROOT/scripts/utils/log function modify_rollout { - local signed_dir="signed/" - local work_dir="work/" - local published_dir="currently_published/" - local upload_dir="upload/" - local latest_file="latest.json" + local signed_dir="$DATA_DIR/signed/" + local work_dir="$DATA_DIR/work/" + local published_dir="$DATA_DIR/currently_published/" + local upload_dir="$DATA_DIR/upload/" + local latest_filename="latest.json" local all_platforms=(linux macos windows) + local mullvad_release="cargo run -q --package mullvad-release --" + rm -rf "$signed_dir" rm -rf "$work_dir" rm -rf "$published_dir" rm -rf "$upload_dir" - echo ">>> Platforms:" "${PLATFORMS[@]}" + log_info "Platforms:" "${PLATFORMS[@]}" - echo ">>> Fetching current version metadata" - mullvad-release pull --latest-file --assume-yes "${all_platforms[@]}" - echo "" + log_header "Fetching current version metadata" + $mullvad_release pull --latest-file --assume-yes "${all_platforms[@]}" - echo ">>> Backing up released data" - cp -r $signed_dir $published_dir - mv "./$latest_file" "$published_dir/$latest_file" - echo "" + log_header "Backing up released data" + cp -r "$signed_dir" "$published_dir" + mv "$DATA_DIR/$latest_filename" "$published_dir/$latest_filename" - echo ">>> Replacing $work_dir directory with latest published data" + log_header "Replacing $work_dir directory with latest published data" cp -rf "$signed_dir" "$work_dir" - echo "" - echo ">>> Setting rollout = $ROLLOUT for $PRODUCT_VERSION" - mullvad-release modify-release "$PRODUCT_VERSION" --rollout "$ROLLOUT" "${PLATFORMS[@]}" - echo "" + log_header "Setting rollout = $ROLLOUT for $PRODUCT_VERSION" + $mullvad_release modify-release "$PRODUCT_VERSION" --rollout "$ROLLOUT" "${PLATFORMS[@]}" - echo ">>> Signing $PRODUCT_VERSION metadata. Reading signing key from clipboard" - xclip -sensitive | mullvad-release sign "${PLATFORMS[@]}" - echo "" + log_header "Signing $PRODUCT_VERSION metadata. Reading signing key from clipboard" + xclip -sensitive | $mullvad_release sign "${PLATFORMS[@]}" - echo ">>> Verifying signed metadata" - mullvad-release verify "${all_platforms[@]}" - echo "" + log_header "Verifying signed metadata" + $mullvad_release verify "${all_platforms[@]}" - echo ">>> Creating upload dir" + log_header "Creating upload dir" cp -rf "$signed_dir" "$upload_dir" - echo "" - echo ">>> Generating $latest_file for current version metadata" - mullvad-release query-latest "${all_platforms[@]}" > "$upload_dir/$latest_file" - echo "" + log_header "Generating $latest_filename for current version metadata" + $mullvad_release query-latest "${all_platforms[@]}" > "$upload_dir/$latest_filename" - echo ">>> New metadata including $PRODUCT_VERSION" - git --no-pager diff --no-index -- $published_dir $upload_dir || true - echo "" + log_header "New metadata including $PRODUCT_VERSION" + git --no-pager diff --no-index -- "$published_dir" "$upload_dir" || true read -rp "Press enter to upload if the diffs look good " - ./publish-metadata-to-api $upload_dir "$BUILDSERVER_HOST" "$METADATA_SERVER_HOST" + ./publish-metadata-to-api "$upload_dir" "$BUILDSERVER_HOST" "$METADATA_SERVER_HOST" } modify_rollout diff --git a/desktop/scripts/release/download-release-artifacts b/desktop/scripts/release/download-release-artifacts index aec0fbfe3e..4a83ac672f 100755 --- a/desktop/scripts/release/download-release-artifacts +++ b/desktop/scripts/release/download-release-artifacts @@ -22,10 +22,13 @@ ARTIFACT_DIR=$2 URL_BASE="https://releases.mullvad.net/desktop/releases" +# shellcheck source-path=desktop/scripts/release +source ./release-config.sh + mkdir -p "$ARTIFACT_DIR" -# The signer key file "mullvad-code-signing-key.asc" is expected to exist in the current working directory. -SIGNER_KEY_FILE="./mullvad-code-signing-key.asc" +fingerprint_in_file=$(sq keyring list "$MULLVAD_CODE_SIGNING_KEY_PATH" | awk '{print $2}') +test "$fingerprint_in_file" = "$MULLVAD_CODE_SIGNING_KEY_FINGERPRINT" for ext in .exe _arm64.exe _x64.exe _amd64.deb _arm64.deb _x86_64.rpm _aarch64.rpm .pkg; do pkg_filename="MullvadVPN-${PRODUCT_VERSION}${ext}" @@ -50,7 +53,7 @@ for ext in .exe _arm64.exe _x64.exe _amd64.deb _arm64.deb _x86_64.rpm _aarch64.r echo ">>> Verifying integrity of $pkg_filename" # We prefer sqv for PGP key verification as it a strict and easy-to-use implementation of PGP. # gpg is also not suitable for use in scripting. - if ! sqv --keyring "$SIGNER_KEY_FILE" "$pkg_path.asc" "$pkg_path"; then + if ! sqv --keyring "$MULLVAD_CODE_SIGNING_KEY_PATH" "$pkg_path.asc" "$pkg_path"; then echo "" echo "!!! INTEGRITY CHECKING FAILED !!!" rm "$pkg_path" "$pkg_path.asc" diff --git a/desktop/scripts/release/release-config.sh b/desktop/scripts/release/release-config.sh index 3e053da880..3b412f35f7 100644 --- a/desktop/scripts/release/release-config.sh +++ b/desktop/scripts/release/release-config.sh @@ -2,7 +2,14 @@ # Configuration variables shared between the release scripts in this directory. +# Where the release scripts and programs store temporary data +export DATA_DIR="$HOME/.local/share/mullvad-release" + # Where to download app installers locally during the release process. # This value is also hardcoded into the `mullvad-release` binary and # has to be in sync with that value -export ARTIFACT_DIR="artifacts" +export ARTIFACT_DIR="$DATA_DIR/artifacts" + +# Mullvad code signing key and fingerprint +export MULLVAD_CODE_SIGNING_KEY_PATH="../../../ci/keys/1.mullvad_signing.pub" +export MULLVAD_CODE_SIGNING_KEY_FINGERPRINT="A1198702FC3E0A09A9AE5B75D5A1D4F266DE8DDF" diff --git a/desktop/scripts/release/verify-version-is-release b/desktop/scripts/release/verify-version-is-release new file mode 100755 index 0000000000..80fa12ec60 --- /dev/null +++ b/desktop/scripts/release/verify-version-is-release @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -eu + +version=$(cargo run -q --bin mullvad-version) +if [[ "$version" == *-dev-* ]]; then + exit 1 +fi diff --git a/mullvad-update/mullvad-release/src/main.rs b/mullvad-update/mullvad-release/src/main.rs index 5089dbeb09..e9692d2577 100644 --- a/mullvad-update/mullvad-release/src/main.rs +++ b/mullvad-update/mullvad-release/src/main.rs @@ -5,7 +5,7 @@ use anyhow::{Context, bail}; use clap::Parser; -use std::{path::Path, str::FromStr}; +use std::{path::PathBuf, str::FromStr}; use tokio::fs; use config::Config; @@ -172,7 +172,8 @@ async fn main() -> anyhow::Result<()> { if latest_file { match HttpVersionInfoProvider::get_latest_versions_file().await { Ok(json_str) => { - let path = Path::new(LATEST_FILENAME); + let path_buf = get_data_dir().join(LATEST_FILENAME); + let path = path_buf.as_path(); if !assume_yes && path.exists() { let msg = format!( @@ -336,3 +337,9 @@ fn all_platforms_if_empty(platforms: Vec<Platform>) -> Vec<Platform> { } platforms } + +pub fn get_data_dir() -> PathBuf { + std::env::home_dir() + .expect("No home dir found") + .join(".local/share/mullvad-release") +} diff --git a/mullvad-update/mullvad-release/src/platform.rs b/mullvad-update/mullvad-release/src/platform.rs index d7114e484a..caa81c7b81 100644 --- a/mullvad-update/mullvad-release/src/platform.rs +++ b/mullvad-update/mullvad-release/src/platform.rs @@ -8,17 +8,12 @@ use mullvad_update::{ MIN_VERIFY_METADATA_VERSION, Rollout, VersionArchitecture, VersionInfo, VersionParameters, }, }; -use std::{ - cmp::Ordering, - fmt, - path::{Path, PathBuf}, - str::FromStr, -}; +use std::{cmp::Ordering, fmt, path::PathBuf, str::FromStr}; use strum::IntoEnumIterator; use tokio::{fs, io}; use crate::{ - artifacts, + artifacts, get_data_dir, io_util::{create_dir_and_write, wait_for_confirm}, }; @@ -76,17 +71,17 @@ impl Platform { /// Path to WIP file in `work/` for this platform pub fn work_path(&self) -> PathBuf { - Path::new("work").join(self.local_filename()) + get_data_dir().join("work").join(self.local_filename()) } /// Path to signed file in `signed/` for this platform pub fn signed_path(&self) -> PathBuf { - Path::new("signed").join(self.local_filename()) + get_data_dir().join("signed").join(self.local_filename()) } /// Expected artifacts in `artifacts/` directory pub fn artifact_filenames(&self, version: &mullvad_version::Version) -> Artifacts { - let artifacts_dir = Path::new("artifacts"); + let artifacts_dir = get_data_dir().join("artifacts"); match self { Platform::Windows => Artifacts { x86_artifacts: vec![artifacts_dir.join(format!("MullvadVPN-{version}_x64.exe"))], diff --git a/scripts/utils/commit-verification b/scripts/utils/commit-verification new file mode 100755 index 0000000000..ffd38043fd --- /dev/null +++ b/scripts/utils/commit-verification @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -eu + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +# shellcheck disable=SC1091 +source ./log + +if ! git verify-commit HEAD; then + log_error "Current commit failed signature check" + exit 1 +fi |
