From c4b98ef2589c01e2925133f4f6bb298dcba9f816 Mon Sep 17 00:00:00 2001 From: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com> Date: Fri, 3 Oct 2025 07:25:58 -0700 Subject: [PATCH] Reproduce linux build with github action --- .github/workflows/reproducible-builds.yml | 148 ++++++++++++++++++++++ reproducible-builds/build.sh | 6 +- 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/reproducible-builds.yml diff --git a/.github/workflows/reproducible-builds.yml b/.github/workflows/reproducible-builds.yml new file mode 100644 index 0000000000..9a68192109 --- /dev/null +++ b/.github/workflows/reproducible-builds.yml @@ -0,0 +1,148 @@ +# Copyright 2024 Signal Messenger, LLC +# SPDX-License-Identifier: AGPL-3.0-only + +name: Reproducible Builds +on: + workflow_dispatch: + inputs: + package: + description: 'Package name' + required: true + default: 'signal-desktop' + type: choice + options: + - signal-desktop + - signal-desktop-beta + version_tag: + description: 'Version tag (e.g. v1.2.3 or v2.0.0-beta.1)' + required: true + type: string +jobs: + linux: + name: Linux deb + runs-on: ubuntu-latest + steps: + - name: Get system specs + run: lsb_release -a + - name: Get other system specs + run: uname -a + + - name: Get version info + id: app_info + run: | + echo "PACKAGE_NAME=${{ inputs.package }}" >> "$GITHUB_ENV" + + echo "git_ref=${{ inputs.version_tag }}" >> $GITHUB_OUTPUT + + PARSED_VERSION=$(echo "${{ inputs.version_tag }}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+.*' | tr '-' '~') + echo "PACKAGE_VERSION=$PARSED_VERSION" >> "$GITHUB_ENV" + + echo "# Reproducing ${{ inputs.package }} Linux deb" >> $GITHUB_STEP_SUMMARY + echo "## Version: ${{ inputs.version_tag }}" >> $GITHUB_STEP_SUMMARY + + - name: Add signal desktop signing key and apt repo + run: | + wget -O- https://updates.signal.org/desktop/apt/keys.asc | gpg --dearmor > signal-desktop-keyring.gpg + cat signal-desktop-keyring.gpg | sudo tee /usr/share/keyrings/signal-desktop-keyring.gpg > /dev/null + + wget -O signal-desktop.sources https://updates.signal.org/static/desktop/apt/signal-desktop.sources + cat signal-desktop.sources | sudo tee /etc/apt/sources.list.d/signal-desktop.sources > /dev/null + sudo apt-get update + + # Note: For beta versions, the APT version is separated by tilde e.g. v1.2.3~beta.1 + # However the download URI has a dash e.g. v1.2.3-beta.1 + # Thus after apt-get download we need to use the filename of the actual download + - name: Download latest deb + id: download + run: | + DOWNLOAD_URI=$(apt-get download --print-uris "$PACKAGE_NAME=$PACKAGE_VERSION" | cut -d"'" -f2) + EXPECTED_SHA512=$(apt-get download --print-uris "$PACKAGE_NAME=$PACKAGE_VERSION" | grep -oP 'SHA512:\K\s*\S+') + echo "expected_sha512=$EXPECTED_SHA512" >> $GITHUB_OUTPUT + + apt-get download "$PACKAGE_NAME=$PACKAGE_VERSION" + DEB_FILE=$(ls | grep deb | tail -1) + echo "deb_file=$DEB_FILE" >> $GITHUB_OUTPUT + + DOWNLOAD_SHA512=$(sha512sum $DEB_FILE | cut -d' ' -f1) + echo "Verifying $DEB_FILE" + echo "Expected SHA512: $EXPECTED_SHA512" + echo "Actual SHA512: $DOWNLOAD_SHA512" + + echo "### Download from apt" >> $GITHUB_STEP_SUMMARY + echo "Verifying $DEB_FILE" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Expected SHA512: $EXPECTED_SHA512" >> $GITHUB_STEP_SUMMARY + echo "Actual SHA512: $DOWNLOAD_SHA512" >> $GITHUB_STEP_SUMMARY + + if [ "$DOWNLOAD_SHA512" == "$EXPECTED_SHA512" ]; then + echo "✅ Download checksum verification successful" + echo "✅ Download checksum verification successful" >> $GITHUB_STEP_SUMMARY + else + echo "❌ Download checksum verification failed!" + echo "❌ Download checksum verification failed!" >> $GITHUB_STEP_SUMMARY + exit 1 + fi + + - name: Clone Desktop git repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + ref: ${{ steps.app_info.outputs.git_ref }} + + - name: Get node version for docker build arg + id: node_version + run: | + NODE_VERSION=$(cat .nvmrc) + echo "version=$NODE_VERSION" >> $GITHUB_OUTPUT + + - name: Set up docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build docker image + uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_RECORD_UPLOAD: false + with: + context: ./reproducible-builds + file: ./reproducible-builds/Dockerfile + tags: signal-desktop:latest + load: true + push: false + build-args: | + SOURCE_DATE_EPOCH=1 + NODE_VERSION=${{ steps.node_version.outputs.version }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build Linux deb + id: build + run: | + cd reproducible-builds + ./build.sh public + + cd ../release + BUILT_FILE=$(ls | grep deb | tail -1) + ACTUAL_SHA512=$(sha512sum $BUILT_FILE | cut -d' ' -f1) + echo "actual_sha512=$ACTUAL_SHA512" >> $GITHUB_OUTPUT + env: + SKIP_DOCKER_BUILD: true + + - name: Compare checksums + run: | + ACTUAL_SHA512="${{ steps.build.outputs.actual_sha512 }}" + EXPECTED_SHA512="${{ steps.download.outputs.expected_sha512 }}" + echo "Verifying ${{ steps.download.outputs.deb_file }}" + echo "" >> $GITHUB_STEP_SUMMARY + echo "Expected SHA512: $EXPECTED_SHA512" + echo "Actual SHA512: $ACTUAL_SHA512" + + echo "### Build and verify" >> $GITHUB_STEP_SUMMARY + echo "Verifying ${{ steps.download.outputs.deb_file }}" >> $GITHUB_STEP_SUMMARY + echo "Build SHA512: $ACTUAL_SHA512" >> $GITHUB_STEP_SUMMARY + + if [ "$ACTUAL_SHA512" == "$EXPECTED_SHA512" ]; then + echo "✅ Build checksum verification successful" + echo "✅ Build checksum verification successful" >> $GITHUB_STEP_SUMMARY + else + echo "❌ Build checksum verification failed!" + echo "❌ Build checksum verification failed!" >> $GITHUB_STEP_SUMMARY + exit 1 + fi diff --git a/reproducible-builds/build.sh b/reproducible-builds/build.sh index 8d8d83dd40..e4667aa1d9 100755 --- a/reproducible-builds/build.sh +++ b/reproducible-builds/build.sh @@ -8,7 +8,11 @@ # First we prepare the docker container in which our build scripts will run. This container includes # all build dependencies at specific versions. # We set SOURCE_DATE_EPOCH to make system build timestamps deterministic. -docker build -t signal-desktop --build-arg SOURCE_DATE_EPOCH=1 --build-arg NODE_VERSION=$(cat ../.nvmrc) . +if [ -z "${SKIP_DOCKER_BUILD}" ]; then + docker build -t signal-desktop --build-arg SOURCE_DATE_EPOCH=1 --build-arg NODE_VERSION=$(cat ../.nvmrc) . +else + echo "Skipping docker build step because SKIP_DOCKER_BUILD was set" +fi # Before performing the actual build, go to the project root. cd ..