diff options
| -rwxr-xr-x | ci/buildserver-build.sh | 34 | ||||
| -rw-r--r-- | ci/buildserver-config.sh | 26 | ||||
| -rw-r--r-- | ci/linux-repository-builder/build-linux-repositories-config.sh | 32 | ||||
| -rwxr-xr-x | ci/linux-repository-builder/build-linux-repositories.sh | 182 | ||||
| -rw-r--r-- | ci/linux-repository-builder/build-linux-repositories@.service | 24 | ||||
| -rw-r--r-- | ci/linux-repository-builder/build-linux-repositories@.timer | 9 | ||||
| -rwxr-xr-x | ci/linux-repository-builder/prepare-apt-repository.sh (renamed from ci/prepare-apt-repository.sh) | 50 | ||||
| -rwxr-xr-x | ci/linux-repository-builder/prepare-rpm-repository.sh | 102 | ||||
| -rw-r--r-- | ci/mullvad-browser/download-mullvad-browser.service | 17 | ||||
| -rwxr-xr-x | ci/mullvad-browser/download-mullvad-browser.sh | 113 | ||||
| -rw-r--r-- | ci/mullvad-browser/download-mullvad-browser.timer | 10 | ||||
| -rw-r--r-- | ci/mullvad-browser/tor-browser-developers-signing-key.asc | 283 | ||||
| -rwxr-xr-x | ci/prepare-rpm-repository.sh | 46 | ||||
| -rwxr-xr-x | ci/publish-app-to-repositories.sh | 121 | ||||
| -rwxr-xr-x | ci/publish-linux-repositories.sh | 128 |
15 files changed, 950 insertions, 227 deletions
diff --git a/ci/buildserver-build.sh b/ci/buildserver-build.sh index a730ad100d..9e8b1eb04f 100755 --- a/ci/buildserver-build.sh +++ b/ci/buildserver-build.sh @@ -16,6 +16,9 @@ shopt -s nullglob SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" BUILD_DIR="$SCRIPT_DIR/mullvadvpn-app" +# All non-dev builds have their artifacts placed under this directory +ARTIFACT_DIR="$SCRIPT_DIR/artifacts" +# Keeps track of which git commit hashes has been built, to not build them again LAST_BUILT_DIR="$SCRIPT_DIR/last-built" BRANCHES_TO_BUILD=("origin/main") @@ -44,27 +47,19 @@ case "$(uname -s)" in ;; esac + +# Automatically copy artifacts to the inbox of the repository builder service +# for dev and staging (production is pushed manually) function publish_linux_repositories { local artifact_dir=$1 local version=$2 - local deb_repo_dir="$SCRIPT_DIR/deb/$version" - echo "Preparing Apt repository in $deb_repo_dir" - "$SCRIPT_DIR/prepare-apt-repository.sh" "$artifact_dir" "$version" "$deb_repo_dir" - - local rpm_repo_dir="$SCRIPT_DIR/rpm/$version" - echo "Preparing RPM repository in $rpm_repo_dir" - "$SCRIPT_DIR/prepare-rpm-repository.sh" "$artifact_dir" "$version" "$rpm_repo_dir" + "$SCRIPT_DIR/publish-app-to-repositories.sh" --dev "$artifact_dir" "$version" - "$SCRIPT_DIR/publish-linux-repositories.sh" --dev "$version" \ - --deb "$deb_repo_dir" \ - --rpm "$rpm_repo_dir" # If this is a release build, also push to staging. # Publishing to production is done manually. if [[ $version != *"-dev-"* ]]; then - "$SCRIPT_DIR/publish-linux-repositories.sh" --staging "$version" \ - --deb "$deb_repo_dir" \ - --rpm "$rpm_repo_dir" + "$SCRIPT_DIR/publish-app-to-repositories.sh" --staging "$artifact_dir" "$version" fi } @@ -86,9 +81,9 @@ function upload { sha256sum "${files[@]}" > "$checksums_path" case "$(uname -s)" in - # Linux is both the build and upload server. Just move directly to target dir + # Linux is both the build and upload server. Just copy directly to target dir Linux*) - mv "${files[@]}" "$checksums_path" "$UPLOAD_DIR/" + cp "${files[@]}" "$checksums_path" "$UPLOAD_DIR/" ;; # Other platforms need to transfer their artifacts to the Linux build machine. Darwin*|MINGW*|MSYS_NT*) @@ -192,7 +187,7 @@ function build_ref { local version="" version="$(run_in_build_env cargo run -q --bin mullvad-version | tr -d "\r" || return 1)" - local artifact_dir="dist/$version" + local artifact_dir="$ARTIFACT_DIR/$version" mkdir -p "$artifact_dir" local build_args=(--optimize --sign) @@ -240,8 +235,11 @@ function build_ref { publish_linux_repositories "$artifact_dir" "$version" fi (cd "$artifact_dir" && upload "$version") || return 1 - # shellcheck disable=SC2216 - yes | rm -r "$artifact_dir" + # Remove artifacts from dev builds. They are not really needed and take up lots of space. + if [[ $version == *"-dev-"* ]]; then + # shellcheck disable=SC2216 + yes | rm -r "$artifact_dir" + fi touch "$LAST_BUILT_DIR/$current_hash" diff --git a/ci/buildserver-config.sh b/ci/buildserver-config.sh index 4420a11300..00f770dbeb 100644 --- a/ci/buildserver-config.sh +++ b/ci/buildserver-config.sh @@ -3,29 +3,13 @@ # Buildserver configuration. Runtime values are defined here instead of # the scripts where they are used. -# Which gpg key to sign things with -export CODE_SIGNING_KEY_FINGERPRINT="A1198702FC3E0A09A9AE5B75D5A1D4F266DE8DDF" - -# Debian codenames we support. -SUPPORTED_DEB_CODENAMES=("sid" "testing" "bookworm" "bullseye") -# Ubuntu codenames we support (latest two LTS) ... -SUPPORTED_DEB_CODENAMES+=("noble" "jammy" "focal") -# ... + latest non-LTS Ubuntu. We officially only support the latest non-LTS. -# But to not cause too much disturbance just when Ubuntu is released, we keep -# the last two codenames working in the repository. -SUPPORTED_DEB_CODENAMES+=("mantic") -export SUPPORTED_DEB_CODENAMES - -export SUPPORTED_RPM_ARCHITECTURES=("x86_64" "aarch64") - -# Servers to upload Linux deb/rpm repositories and all other build artifacts to. -export DEV_UPLOAD_SERVERS=("cdn.devmole.eu") -export STAGING_UPLOAD_SERVERS=("cdn.stagemole.eu") +# Servers to upload build artifacts to. export PRODUCTION_UPLOAD_SERVERS=("cdn.mullvad.net") -export DEV_LINUX_REPOSITORY_PUBLIC_URL="https://repository.devmole.eu" -export STAGING_LINUX_REPOSITORY_PUBLIC_URL="https://repository.stagemole.eu" -export PRODUCTION_LINUX_REPOSITORY_PUBLIC_URL="https://repository.mullvad.net" +# Where to publish new app artifact notification files to, so that +# build-linux-repositories picks it up. +# Keep in sync with build-linux-repositories-config.sh +#export LINUX_REPOSITORY_INBOX_DIR_BASE="PLEASE CONFIGURE ME" # What container volumes cargo should put caches in. # Specify differently if running multiple builds in parallel on one machine, diff --git a/ci/linux-repository-builder/build-linux-repositories-config.sh b/ci/linux-repository-builder/build-linux-repositories-config.sh new file mode 100644 index 0000000000..bed015f5c0 --- /dev/null +++ b/ci/linux-repository-builder/build-linux-repositories-config.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# The directory to use as inbox. This is where .src files are read +#export LINUX_REPOSITORY_INBOX_DIR_BASE="PLEASE CONFIGURE ME" + +# GPG key to sign the repositories with +export CODE_SIGNING_KEY_FINGERPRINT="A1198702FC3E0A09A9AE5B75D5A1D4F266DE8DDF" + +# Debian codenames we support. +SUPPORTED_DEB_CODENAMES=("sid" "testing" "bookworm" "bullseye") +# Ubuntu codenames we support. Latest two LTS. But when adding a new +# don't immediately remove the oldest one. Allow for some transition period +# with the last three. +SUPPORTED_DEB_CODENAMES+=("noble" "jammy" "focal") +# ... + latest non-LTS Ubuntu. We officially only support the latest non-LTS. +# But to not cause too much disturbance just when Ubuntu is released, we keep +# the last two codenames working in the repository. +SUPPORTED_DEB_CODENAMES+=("mantic") +export SUPPORTED_DEB_CODENAMES + +export SUPPORTED_RPM_ARCHITECTURES=("x86_64" "aarch64") + +export REPOSITORIES=("stable" "beta") + +export PRODUCTION_LINUX_REPOSITORY_PUBLIC_URL="https://repository.mullvad.net" +export STAGING_LINUX_REPOSITORY_PUBLIC_URL="https://repository.stagemole.eu" +export DEV_LINUX_REPOSITORY_PUBLIC_URL="https://repository.devmole.eu" + +# Servers to upload Linux deb/rpm repositories to +export PRODUCTION_REPOSITORY_SERVER="cdn.mullvad.net" +export STAGING_REPOSITORY_SERVER="cdn.stagemole.eu" +export DEV_REPOSITORY_SERVER="cdn.devmole.eu" diff --git a/ci/linux-repository-builder/build-linux-repositories.sh b/ci/linux-repository-builder/build-linux-repositories.sh new file mode 100755 index 0000000000..418183485b --- /dev/null +++ b/ci/linux-repository-builder/build-linux-repositories.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env bash +# +# Builds linux deb and rpm repositories and uploads them to a repository server. +# One instance of this script targets *one* server environment. +# This means that if you want to publish to development, staging and production servers, +# you need to run three instances of this script. +# +# This script works on an $inbox_dir. In this directory it expects one directory per repository. +# For each repository it will read all files having the .src extension +# These files are expected to contain a single line, a path to some directory where +# it can read new artifacts for that product. +# All deb and rpm files from that directory will be signed and moved over to a folder with +# the same name as the .src file, but with a .latest extension instead. +# So artifacts read from `app.src` will be moved to `app.latest/`. +# +# Then the deb and rpm repositories will be generated and all deb and rpm files in +# $inbox_dir/$repository/*.latest/ will be added to the repository. These repositories are then synced +# to `$repository_server_upload_domain respectively. + +set -eu +# nullglob is needed to produce expected results when globing an empty directory +shopt -s nullglob + +function usage() { + echo "Usage: $0 <environment>" + echo + echo "Example usage: ./build-linux-repositories.sh production" + echo + echo "This script reads an inbox folder for the corresponding server environment." + echo "It then generates and uploads new Linux repositories for all" + echo "the latest artifacts" + echo + echo "Options:" + echo " -h | --help Show this help message and exit." + exit 1 +} + +if [[ "$#" == 0 || $1 == "-h" || $1 == "--help" ]]; then + usage +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source=ci/linux-repository-builder/build-linux-repositories-config.sh +source "$SCRIPT_DIR/build-linux-repositories-config.sh" + +environment="$1" +case "$environment" in + "production") + repository_server_upload_domain="$PRODUCTION_REPOSITORY_SERVER" + repository_server_public_url="$PRODUCTION_LINUX_REPOSITORY_PUBLIC_URL" + ;; + "staging") + repository_server_upload_domain="$STAGING_REPOSITORY_SERVER" + repository_server_public_url="$STAGING_LINUX_REPOSITORY_PUBLIC_URL" + ;; + "dev") + repository_server_upload_domain="$DEV_REPOSITORY_SERVER" + repository_server_public_url="$DEV_LINUX_REPOSITORY_PUBLIC_URL" + ;; + *) + echo "Unknown environment. Specify production, staging or dev" >&2 + exit 1 + ;; +esac + +inbox_dir="$LINUX_REPOSITORY_INBOX_DIR_BASE/$environment" + +if [[ ! -d "$inbox_dir" ]]; then + echo "Inbox $inbox_dir does not exist" 1>&2 + exit 1 +fi + +# Process all .src files in the given inbox dir. +# Signs and moves all found artifacts into .latest directories +# Returns 0 if everything went well and there are new artifacts for a product. +# Returns 1 if no new artifacts were found +function process_inbox { + local inbox_dir=$1 + echo "[#] Processing inbox at $inbox_dir" + + local found_new_artifacts="false" + # Read all notify files and move the artifacts they point to into a local .latest copy + for notify_file in "$inbox_dir"/*.src; do + if [[ ! -f "$notify_file" ]]; then + echo "Ignoring non-file $notify_file" 1>&2 + continue + fi + echo "Processing notify file $notify_file" + + local src_dir + src_dir=$(cat "$notify_file") + if [[ ! -d "$src_dir" ]]; then + echo "Artifact source dir $src_dir from notify file $notify_file does not exist" 1>&2 + continue + fi + + # Removing the file before we move the artifacts out of where it points. + # This ensures we don't get stuck in a loop processing it over and over + # if the signing and moving fails. + rm "$notify_file" + + local artifact_dir=${notify_file/%.src/.latest} + # Recreate the artifact dir, cleaning it + rm -rf "$artifact_dir" && mkdir -p "$artifact_dir" || exit 1 + + # The fact that we have processed one .src file is enough tro trigger a repository + # rebuild. Because if a product would like to publish "no artifacts" they should + # be able to create a .src file pointing to an empty directory + found_new_artifacts="true" + + echo "Moving artifacts from $src_dir to $artifact_dir" + # Move all deb and rpm files into the .latest dir + for src_deb in "$src_dir"/*.deb; do + echo "Signing and moving $src_deb into $artifact_dir/" + dpkg-sig --sign builder "$src_deb" + mv "$src_deb" "$artifact_dir/" + done + for src_rpm in "$src_dir"/*.rpm; do + echo "Signing and moving $src_rpm into $artifact_dir/" + rpm --addsign "$src_rpm" + mv "$src_rpm" "$artifact_dir/" + done + rm -r "$src_dir" || echo "Failed to remove src dir $src_dir" + done + + if [[ $found_new_artifacts == "false" ]]; then + return 1 + fi + return 0 +} + +function rsync_repo { + local local_repo_dir=$1 + local remote_repo_dir=$2 + + echo "Syncing to $repository_server_upload_domain:$remote_repo_dir" + rsync -av --delete --mkpath --rsh='ssh -p 1122' \ + "$local_repo_dir"/ \ + build@"$repository_server_upload_domain":"$remote_repo_dir" +} + +for repository in "${REPOSITORIES[@]}"; do + deb_remote_repo_dir="deb/$repository" + rpm_remote_repo_dir="rpm/$repository" + + repository_inbox_dir="$inbox_dir/$repository" + if ! process_inbox "$repository_inbox_dir"; then + echo "Nothing new in inbox at $repository_inbox_dir" + continue + fi + + # Read all .latest artifact dirs into array + readarray -d '' artifact_dirs < <(find "$repository_inbox_dir" -maxdepth 1 -name "*.latest" -type d -print0) + if [ "${#artifact_dirs[@]}" -lt 1 ]; then + echo "No artifact directories in $repository_inbox_dir to generate repositories from" >&2 + continue + fi + + echo "Generating repositories from these artifact directories: ${artifact_dirs[*]}" + + # Generate deb repository from all the .latest artifacts + + deb_repo_dir="$repository_inbox_dir/repos/deb" + rm -rf "$deb_repo_dir" && mkdir -p "$deb_repo_dir" || exit 1 + "$SCRIPT_DIR/prepare-apt-repository.sh" "$deb_repo_dir" "${artifact_dirs[@]}" + + # Generate rpm repository from all the .latest artifacts + + rpm_repo_dir="$repository_inbox_dir/repos/rpm" + rm -rf "$rpm_repo_dir" && mkdir -p "$rpm_repo_dir" || exit 1 + "$SCRIPT_DIR/prepare-rpm-repository.sh" "$rpm_repo_dir" \ + "$repository_server_public_url" "$rpm_remote_repo_dir" "$repository" "${artifact_dirs[@]}" + + # rsync repositories to repository server + + echo "[#] Syncing deb repository to $deb_remote_repo_dir" + rsync_repo "$deb_repo_dir" "$deb_remote_repo_dir" + echo "[#] Syncing rpm repository to $rpm_remote_repo_dir" + rsync_repo "$rpm_repo_dir" "$rpm_remote_repo_dir" + +done diff --git a/ci/linux-repository-builder/build-linux-repositories@.service b/ci/linux-repository-builder/build-linux-repositories@.service new file mode 100644 index 0000000000..e4b8d78a23 --- /dev/null +++ b/ci/linux-repository-builder/build-linux-repositories@.service @@ -0,0 +1,24 @@ +# Create separate services with instance names being set to "$server_environment". +# See the build-linux-repositories.sh script for details. +# +# For example: +# * build-linux-repositories@production.service +# * build-linux-repositories@staging.service +# * build-linux-repositories@dev.service +# +# To install this service, do the following: +# +# * Log in to the user with `sudo machinectl shell <build account>@` to get a proper shell +# * Copy this service file and corresponding timer file to ~/.config/systemd/user +# * Edit `ExecStart` path to point to absolute path to script +# * Reload systemd: `systemctl --user daemon-reload` +# * Start the timers: +# $ systemctl --user enable --now build-linux-repositories@production.timer +# ... Repeat for other environments. + +[Unit] +Description=Mullvad Linux repository generation and upload service + +[Service] +Type=oneshot +ExecStart=./build-linux-repositories.sh %i diff --git a/ci/linux-repository-builder/build-linux-repositories@.timer b/ci/linux-repository-builder/build-linux-repositories@.timer new file mode 100644 index 0000000000..b4f4aaa202 --- /dev/null +++ b/ci/linux-repository-builder/build-linux-repositories@.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Run Mullvad Linux repository generation and upload service periodically + +[Timer] +OnCalendar=*-*-* *:*:30 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/ci/prepare-apt-repository.sh b/ci/linux-repository-builder/prepare-apt-repository.sh index 5f4eee9746..18a2d5bdf9 100755 --- a/ci/prepare-apt-repository.sh +++ b/ci/linux-repository-builder/prepare-apt-repository.sh @@ -1,20 +1,40 @@ #!/usr/bin/env bash -# -# Usage: ./prepare-apt-repository.sh <artifact dir> <app version> <repository dir> -# -# Will create a deb repository in <repository dir> and add all .deb files from -# <artifact dir> matching <app version> to the repository. set -eu +# nullglob is needed to produce expected results when globing an empty directory +shopt -s nullglob + +function usage() { + echo "Usage: $0 <repository dir> <artifact dirs...>" + echo + echo "Will create a deb repository in <repository dir> and add all .deb files from all <artifact dirs>" + echo + echo "Options:" + echo " -h | --help Show this help message and exit." + exit 1 +} + +if [[ "$#" == 0 || $1 == "-h" || $1 == "--help" ]]; then + usage +fi SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -# shellcheck source=ci/buildserver-config.sh -source "$SCRIPT_DIR/buildserver-config.sh" +# shellcheck source=ci/linux-repository-builder/build-linux-repositories-config.sh +source "$SCRIPT_DIR/build-linux-repositories-config.sh" -artifact_dir=$1 -version=$2 -repo_dir=$3 +repo_dir=${1:?"Specify the output repository directory as the first argument"} + +artifact_dirs=() +while [ "$#" -gt 1 ]; do + artifact_dirs+=("$2") + shift +done + +if [ "${#artifact_dirs[@]}" -lt 1 ]; then + echo "No artifact directories given" >&2 + exit 1 +fi function generate_repository_configuration { local codename=$1 @@ -51,10 +71,12 @@ echo "Writing repository configuration to $repo_dir/conf/distributions" generate_deb_distributions_content > "$repo_dir/conf/distributions" echo "" -for deb_path in "$artifact_dir"/MullvadVPN-"$version"*.deb; do - for codename in "${SUPPORTED_DEB_CODENAMES[@]}"; do - add_deb_to_repo "$deb_path" "$codename" +for artifact_dir in "${artifact_dirs[@]}"; do + for deb_path in "$artifact_dir"/*.deb; do + for codename in "${SUPPORTED_DEB_CODENAMES[@]}"; do + add_deb_to_repo "$deb_path" "$codename" + echo "" + done echo "" done - echo "" done diff --git a/ci/linux-repository-builder/prepare-rpm-repository.sh b/ci/linux-repository-builder/prepare-rpm-repository.sh new file mode 100755 index 0000000000..4e258dedb4 --- /dev/null +++ b/ci/linux-repository-builder/prepare-rpm-repository.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash + +set -eu +# nullglob is needed to produce expected results when globing an empty directory +shopt -s nullglob + +function usage() { + echo "Usage: $0 <repository dir> <repository server url> <remote repo dir> <stable_or_beta> <artifact dirs...>" + echo + echo "Example: $0 ./repos/rpm https://cdn.mullvad.net/ rpm/stable stable inbox/app.latest inbox/browser.latest" + echo + echo "Will create an rpm repository in <repository dir> and add all .rpm files from all <artifact dirs> to it." + echo + echo "Options:" + echo " -h | --help Show this help message and exit." + exit 1 +} + +if [[ "$#" == 0 || $1 == "-h" || $1 == "--help" ]]; then + usage +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source=ci/linux-repository-builder/build-linux-repositories-config.sh +source "$SCRIPT_DIR/build-linux-repositories-config.sh" + +repo_dir=${1:?"Specify the output repository directory as the first argument"} +repository_server_url=${2:?"Give repository server URL as second argument (needed for repository metadata generation)"} +remote_repo_dir=${3:?"Give remote repo dir as third argument"} +stable_or_beta=${4:?"Give 'stable' or 'beta' as fourth argument"} +shift 4 + +artifact_dirs=() +while [ "$#" -gt 0 ]; do + artifact_dirs+=("$1") + shift +done + +if [[ "$stable_or_beta" != "beta" && "$stable_or_beta" != "stable" ]]; then + echo "<stable or beta> argument must be 'stable' or 'beta'" + exit 1 +fi +if [ "${#artifact_dirs[@]}" -lt 1 ]; then + echo "No artifact directories given" >&2 + exit 1 +fi + +# Writes the mullvad.repo config file to the repository root. +# This needs to contain the absolute url and path to the repository. +# As such, it depends on what server we upload to as well as if it's stable or beta. +function generate_rpm_repository_configuration { + local repository_dir=$1 + local repository_server_url=$2 + local remote_repo_dir=$3 + local stable_or_beta=$4 + + local repository_name="Mullvad VPN" + if [[ "$stable_or_beta" == "beta" ]]; then + repository_name+=" (beta)" + fi + + echo -e "[mullvad-$stable_or_beta] +name=$repository_name +baseurl=$repository_server_url/$remote_repo_dir/\$basearch +type=rpm +enabled=1 +gpgcheck=1 +gpgkey=$repository_server_url/rpm/mullvad-keyring.asc" > "$repository_dir/mullvad.repo" +} + +for artifact_dir in "${artifact_dirs[@]}"; do + for arch in "${SUPPORTED_RPM_ARCHITECTURES[@]}"; do + arch_repo_dir="$repo_dir/$arch" + for rpm_path in "$artifact_dir"/*"$arch".rpm; do + mkdir -p "$arch_repo_dir" + echo "[#] Copying $rpm_path to $arch_repo_dir/" + cp "$rpm_path" "$arch_repo_dir"/ + done + done +done + +for arch in "${SUPPORTED_RPM_ARCHITECTURES[@]}"; do + arch_repo_dir="$repo_dir/$arch" + if [[ ! -d "$arch_repo_dir" ]]; then + echo "No $arch repository in $repo_dir" >&2 + continue + fi + + echo "Generating architecture repository metadata for $arch_repo_dir" + + # Generate repository metadata files (containing among other things checksums + # for the rpm files in it) + createrepo_c "$arch_repo_dir" + + # Sign repository metadata (created by createrepo_c above) + gpg --detach-sign --armor "$arch_repo_dir/repodata/repomd.xml" +done + +echo "Generating global repository configuration in $repo_dir" +generate_rpm_repository_configuration "$repo_dir" "$repository_server_url" "$remote_repo_dir" "$stable_or_beta" + diff --git a/ci/mullvad-browser/download-mullvad-browser.service b/ci/mullvad-browser/download-mullvad-browser.service new file mode 100644 index 0000000000..3b6b8a9b98 --- /dev/null +++ b/ci/mullvad-browser/download-mullvad-browser.service @@ -0,0 +1,17 @@ +# To install this do the following: +# +# * Create a directory for the browser GPG keyring (used to verify downloaded artifacts) +# * Import the key there: `GNUPGHOME=/the/gpg/home gpg --import ./tor-browser-developers-signing-key.asc` +# * Copy this service file and corresponding timer file to ~/.config/systemd/user +# * Edit `Environment` below to point `GNUPGHOME` to the path you created above +# * Edit `ExecStart` path to point to absolute path to download script +# * Reload systemd: `systemctl --user daemon-reload` +# * Start the timer: `systemctl --user enable --now download-mullvad-browser.timer` + +[Unit] +Description=Mullvad Browser download service + +[Service] +Type=oneshot +Environment="GNUPGHOME=..." +ExecStart=./download-mullvad-browser.sh diff --git a/ci/mullvad-browser/download-mullvad-browser.sh b/ci/mullvad-browser/download-mullvad-browser.sh new file mode 100755 index 0000000000..5c09ac21cf --- /dev/null +++ b/ci/mullvad-browser/download-mullvad-browser.sh @@ -0,0 +1,113 @@ +#!/usr/bin/bash -e + +set -eu + +# TODO: Uncomment when alpha is to be released +# BROWSER_RELEASES=("alpha" "stable") +BROWSER_RELEASES=("stable") +REPOSITORIES=("stable" "beta") +TMP_DIR=$(mktemp -qdt mullvad-browser-tmp-XXXXXXX) +WORKDIR=/tmp/mullvad-browser-download +NOTIFY_DIR=/tmp/linux-repositories/production + + +function usage() { + echo "Usage: $0" + echo + echo "This script downloads, verifies, and notifies about Mullvad browser packages." + echo + echo "Options:" + echo " -h | --help Show this help message and exit." + exit 1 +} + + +function main() { + local package_filename_base=$1 + local extension=$2 + PACKAGE_FILENAME="$package_filename_base.$extension" + + PACKAGE_URL=https://cdn.mullvad.net/browser/$PACKAGE_FILENAME + SIGNATURE_URL=$PACKAGE_URL.asc + + echo "[#] Downloading $PACKAGE_FILENAME" + if ! wget --quiet --show-progress "$PACKAGE_URL"; then + echo "[!] Failed to download $PACKAGE_URL" + exit 1 + fi + + echo "[#] Downloading $PACKAGE_FILENAME.asc" + if ! wget --quiet --show-progress "$SIGNATURE_URL"; then + echo "[!] Failed to download $SIGNATURE_URL" + exit 1 + fi + + echo "[#] Verifying $PACKAGE_FILENAME signature" + if ! gpg --verify "$PACKAGE_FILENAME".asc; then + echo "[!] Failed to verify signature" + exit 1 + fi + rm "$PACKAGE_FILENAME.asc" + + # Hack to get the architecture into the filename + local filename_with_arch="${package_filename_base}_x86_64.$extension" + mv "$PACKAGE_FILENAME" "$filename_with_arch" + PACKAGE_FILENAME="$filename_with_arch" + + # Check if the deb package has changed since last time + # Handle the bootstrap problem by checking if the "output file" even exists and just moving on if it doesn't + if [[ -f "$WORKDIR/$PACKAGE_FILENAME" ]] && cmp "$PACKAGE_FILENAME" "$WORKDIR/$PACKAGE_FILENAME"; then + echo "[#] $PACKAGE_FILENAME has not changed" + rm "$PACKAGE_FILENAME" + return + fi + + echo "[#] $PACKAGE_FILENAME has changed" + ln "$PACKAGE_FILENAME" $WORKDIR/ +} + +if [[ ${1:-} == "-h" ]] || [[ ${1:-} == "--help" ]]; then + usage +fi + + +if ! [[ -d $NOTIFY_DIR ]]; then + echo "[!] $NOTIFY_DIR does not exist" + exit 1 +fi + + +if ! [[ -d $WORKDIR ]]; then + echo "[#] Creating $WORKDIR" + mkdir -p $WORKDIR +fi + + +pushd "$TMP_DIR" > /dev/null + + +echo "[#] Configured releases are: ${BROWSER_RELEASES[*]}" +for release in "${BROWSER_RELEASES[@]}"; do + main "mullvad-browser-$release" "deb" + main "mullvad-browser-$release" "rpm" +done + +if [[ -z "$(ls -A "$TMP_DIR")" ]]; then + echo "[#] No new browser build(s) exist" + exit +fi + +echo "[#] New browser build(s) exist" +for repository in "${REPOSITORIES[@]}"; do + inbox_dir="$NOTIFY_DIR/$repository" + + REPOSITORY_TMP_ARTIFACT_DIR=$(mktemp -qdt mullvad-browser-tmp-XXXXXXX) + cp "$TMP_DIR"/* "$REPOSITORY_TMP_ARTIFACT_DIR" + + repository_notify_file="$inbox_dir/browser.src" + echo "[#] Notifying $repository_notify_file" + echo "$REPOSITORY_TMP_ARTIFACT_DIR" > "$repository_notify_file" +done + +# Remove our temporary working directory +rm -r "$TMP_DIR" diff --git a/ci/mullvad-browser/download-mullvad-browser.timer b/ci/mullvad-browser/download-mullvad-browser.timer new file mode 100644 index 0000000000..699192eeae --- /dev/null +++ b/ci/mullvad-browser/download-mullvad-browser.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Run Mullvad Browser download service periodically + +[Timer] +# Run every fifteen minutes +OnCalendar=*:0,15,30,45 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/ci/mullvad-browser/tor-browser-developers-signing-key.asc b/ci/mullvad-browser/tor-browser-developers-signing-key.asc new file mode 100644 index 0000000000..2994a84ad1 --- /dev/null +++ b/ci/mullvad-browser/tor-browser-developers-signing-key.asc @@ -0,0 +1,283 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=QHmJ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/ci/prepare-rpm-repository.sh b/ci/prepare-rpm-repository.sh deleted file mode 100755 index 22616c591f..0000000000 --- a/ci/prepare-rpm-repository.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -# -# Usage: ./prepare-rpm-repository.sh <artifact dir> <app version> <repository dir> -# -# Will create an rpm repository in <repository dir> and add all .rpm files from -# <artifact dir> matching <app version> to the repository. - -set -eu - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# shellcheck source=ci/buildserver-config.sh -source "$SCRIPT_DIR/buildserver-config.sh" - -artifact_dir=$1 -version=$2 -repo_dir=$3 - -function create_repository { - local arch_repo_dir=$1 - local rpm_path=$2 - - mkdir -p "$arch_repo_dir" - - # Copy RPM file into repository - cp "$rpm_path" "$arch_repo_dir"/ - - # Generate repository metadata files (containing among other things checksums - # for the above artifact) - createrepo_c "$arch_repo_dir" - - # Sign repository metadata (created by createrepo_c above) - # --yes is passed to automatically overwrite existing files - # in the case where the build server re-builds something we already - # have built. - gpg --detach-sign --armor --yes "$arch_repo_dir/repodata/repomd.xml" -} - -for arch in "${SUPPORTED_RPM_ARCHITECTURES[@]}"; do - rpm_path="$artifact_dir"/MullvadVPN-"$version"_"$arch".rpm - if [[ ! -e "$rpm_path" ]]; then - echo "RPM at $rpm_path does not exist" >&2 - exit 1 - fi - create_repository "$repo_dir/$arch" "$rpm_path" -done diff --git a/ci/publish-app-to-repositories.sh b/ci/publish-app-to-repositories.sh new file mode 100755 index 0000000000..0a05e48a21 --- /dev/null +++ b/ci/publish-app-to-repositories.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +set -eu +# nullglob is needed to produce expected results when globing an empty directory +shopt -s nullglob + +function usage() { + echo "Usage: $0 [--production/--staging/--dev] <artifact dir> <app version>" + echo + echo "Copies app deb and rpm artifacts over to the repository building service inbox directory." + echo "Makes that service publish the new artifacts to the corresponding repository server." + echo + echo "Options:" + echo " -h | --help Show this help message and exit." + echo " --production Publish app to production environment" + echo " --staging Publish app to staging environment" + echo " --dev Publish app to development environment" + echo "" + echo "Arguments:" + echo " <artifact dir> Directory to copy from. Will copy all app deb/rpms matching <version>" + echo " <version> App version to copy. If <artifact dir> has apps for multiple versions" + echo " only apps matching this version will be copied" + exit 1 +} + +if [[ "$#" == 0 || $1 == "-h" || $1 == "--help" ]]; then + usage +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source=ci/buildserver-config.sh +source "$SCRIPT_DIR/buildserver-config.sh" + +while [ "$#" -gt 0 ]; do + case "$1" in + "--production") + environment="production" + ;; + "--staging") + environment="staging" + ;; + "--dev") + environment="dev" + ;; + -*) + echo "Unknown option \"$1\"" >&2 + exit 1 + ;; + *) + if [[ -z ${artifact_dir+x} ]]; then + artifact_dir=$1 + elif [[ -z ${version+x} ]]; then + version=$1 + else + echo "Too many arguments" >&2 + exit 1 + fi + ;; + esac + shift +done + +if [[ -z ${environment+x} ]]; then + echo "Pass either --dev, --staging or --production to select target servers" >&2 + exit 1 +fi +if [[ -z ${artifact_dir+x} ]]; then + echo "Please give the artifact directory as an argument to this script" >&2 + exit 1 +fi +if [[ -z ${version+x} ]]; then + echo "Please give the release version as an argument to this script" >&2 + exit 1 +fi + +function copy_linux_artifacts_to_dir { + local src_dir=$1 + local version=$2 + local dst_dir=$3 + + for deb_path in "$src_dir"/MullvadVPN-"$version"*.deb; do + echo "Copying $deb_path into $dst_dir/" + cp "$deb_path" "$dst_dir/" + done + for rpm_path in "$src_dir"/MullvadVPN-"$version"*.rpm; do + echo "Copying $rpm_path into $dst_dir/" + cp "$rpm_path" "$dst_dir/" + done +} + +function notify_repository_service { + local artifact_dir=$1 + local version=$2 + local repository_inbox_dir=$3 + + local tmp_notify_file + tmp_notify_file=$(mktemp -p "$repository_inbox_dir") + local notify_file="$repository_inbox_dir/app.src" + + # Temporarily write the file to a different path and then move it. + # As long as the tmp dir and destination dir is on the same filesystem, + # this is guaranteed to be atomic, preventing partial reads by the consuming + # repository building service. + echo "$artifact_dir" > "$tmp_notify_file" + echo "Writing notify file $notify_file" + mv "$tmp_notify_file" "$notify_file" +} + +stable_or_beta="stable" +if [[ $version == *"-beta"* ]]; then + stable_or_beta="beta" +fi +repository_inbox_dir="$LINUX_REPOSITORY_INBOX_DIR_BASE/$environment/$stable_or_beta" +repository_tmp_store_dir="$(mktemp -qdt "mullvadvpn-app-$version-tmp-XXXXXXX")" + +echo "Copying app artifacts for $version from $artifact_dir to $repository_tmp_store_dir" +copy_linux_artifacts_to_dir "$artifact_dir" "$version" "$repository_tmp_store_dir" + +echo "Notifying repository building service in $repository_inbox_dir" +notify_repository_service "$repository_tmp_store_dir" "$version" "$repository_inbox_dir" diff --git a/ci/publish-linux-repositories.sh b/ci/publish-linux-repositories.sh deleted file mode 100755 index 76d09c33d9..0000000000 --- a/ci/publish-linux-repositories.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env bash -# -# Usage: ./publish-linux-repositories.sh [--production/--staging/--dev] <app version> [--deb <deb repository dir>] [--rpm <rpm repository dir>] -# -# Rsyncs a locally prepared and stored apt and/or rpm repository to the dev/staging/production -# repository servers. - -set -eu - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# shellcheck source=ci/buildserver-config.sh -source "$SCRIPT_DIR/buildserver-config.sh" - -while [ "$#" -gt 0 ]; do - case "$1" in - "--production") - repository_servers=("${PRODUCTION_UPLOAD_SERVERS[@]}") - repository_server_url="$PRODUCTION_LINUX_REPOSITORY_PUBLIC_URL" - ;; - "--staging") - repository_servers=("${STAGING_UPLOAD_SERVERS[@]}") - repository_server_url="$STAGING_LINUX_REPOSITORY_PUBLIC_URL" - ;; - "--dev") - repository_servers=("${DEV_UPLOAD_SERVERS[@]}") - repository_server_url="$DEV_LINUX_REPOSITORY_PUBLIC_URL" - ;; - "--deb") - deb_repo_dir=$2 - shift - ;; - "--rpm") - rpm_repo_dir=$2 - shift - ;; - -*) - echo "Unknown option \"$1\"" >&2 - exit 1 - ;; - *) - if [[ -z ${version+x} ]]; then - version=$1 - else - echo "Too many arguments" >&2 - exit 1 - fi - ;; - esac - shift -done - -if [[ -z ${version+x} ]]; then - echo "Please give the release version as an argument to this script" >&2 - exit 1 -fi -if [[ -z ${deb_repo_dir+x} && -z ${rpm_repo_dir+x} ]]; then - echo "Please specify at least one of --deb or --rpm" >&2 - exit 1 -fi -if [[ -z ${repository_servers+x} ]]; then - echo "Pass either --dev, --staging or --production to select target servers" >&2 - exit 1 -fi - -function rsync_repo { - local local_repo_dir=$1 - local remote_repo_dir=$2 - - for server in "${repository_servers[@]}"; do - echo "Syncing to $server:$remote_repo_dir" - rsync -av --delete --mkpath --rsh='ssh -p 1122' \ - "$local_repo_dir"/ \ - build@"$server":"$remote_repo_dir" - done -} - -# Writes the mullvad.repo config file to the repository -# root. This needs to contain the absolute url and path -# to the repository. As such, it depends on what server -# we upload to as well as if it's stable or beta. That's -# why we need to do it just before upload. -function generate_rpm_repository_configuration { - local repository_dir=$1 - local stable_or_beta=$2 - - local repository_name="Mullvad VPN" - if [[ "$stable_or_beta" == "beta" ]]; then - repository_name+=" (beta)" - fi - - echo -e "[mullvad-$stable_or_beta] -name=$repository_name -baseurl=$repository_server_url/rpm/$stable_or_beta/\$basearch -type=rpm -enabled=1 -gpgcheck=1 -gpgkey=$repository_server_url/rpm/mullvad-keyring.asc" > "$repository_dir/mullvad.repo" -} - -if [[ -n ${deb_repo_dir+x} ]]; then - echo "Publishing deb repository from $deb_repo_dir" - if [[ ! -d "$deb_repo_dir" ]]; then - echo "$deb_repo_dir does not exist" >&2 - exit 1 - fi - - rsync_repo "$deb_repo_dir" "deb/beta" - if [[ $version != *"-beta"* ]]; then - rsync_repo "$deb_repo_dir" "deb/stable" - fi -fi - -if [[ -n ${rpm_repo_dir+x} ]]; then - echo "Publishing rpm repository from $rpm_repo_dir" - if [[ ! -d "$rpm_repo_dir" ]]; then - echo "$rpm_repo_dir does not exist" >&2 - exit 1 - fi - - generate_rpm_repository_configuration "$rpm_repo_dir" "beta" - rsync_repo "$rpm_repo_dir" "rpm/beta" - if [[ $version != *"-beta"* ]]; then - generate_rpm_repository_configuration "$rpm_repo_dir" "stable" - rsync_repo "$rpm_repo_dir" "rpm/stable" - fi -fi - |
