From 7ee35ebdec521d040ee52edd82ac7b92ed793309 Mon Sep 17 00:00:00 2001 From: hackerbirds <120066692+hackerbirds@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:54:27 -0400 Subject: [PATCH] Introduce reproducible build system on Linux --- reproducible-builds/Dockerfile | 45 ++++++++++++++ reproducible-builds/README.md | 78 +++++++++++++++++++++++++ reproducible-builds/build.sh | 5 ++ reproducible-builds/docker/apt.conf | 6 ++ reproducible-builds/docker/sources.list | 3 + ts/scripts/generate-dns-fallback.ts | 2 +- 6 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 reproducible-builds/Dockerfile create mode 100644 reproducible-builds/README.md create mode 100755 reproducible-builds/build.sh create mode 100644 reproducible-builds/docker/apt.conf create mode 100644 reproducible-builds/docker/sources.list diff --git a/reproducible-builds/Dockerfile b/reproducible-builds/Dockerfile new file mode 100644 index 0000000000..95f51c9e57 --- /dev/null +++ b/reproducible-builds/Dockerfile @@ -0,0 +1,45 @@ +FROM ubuntu:jammy-20230624@sha256:b060fffe8e1561c9c3e6dea6db487b900100fc26830b9ea2ec966c151ab4c020 + +# Allows package builders like FPM (used for creating the .deb package +# on linux) to make their build timestamps determistic. Otherwise, a fresh +# UNIX timestamp will be generated at the time of the build, and is non-deterministic. +# +# Read https://reproducible-builds.org/specs/source-date-epoch/ for more info +ENV SOURCE_DATE_EPOCH=1 + +# Due to some issues with NVM reading .nvmrc, we define the version +# as an environment variable and use that instead. +ARG NODE_VERSION + +# --- +# This portion of the code is identical to the Signal Android's +# reproducible build system. https://github.com/signalapp/Signal-Android/blob/main/reproducible-builds/Dockerfile + +# APT source files +COPY docker/ docker/ +COPY docker/apt.conf docker/sources.list /etc/apt/ + +# Temporarily disables APT's certificate signature checking +# to download the certificates. See +RUN apt update -oAcquire::https::Verify-Peer=false +RUN apt install -oAcquire::https::Verify-Peer=false -y ca-certificates + +RUN apt update +RUN apt install -y git curl g++ gcc make python3 tar +# --- + +# Install nvm +ENV NVM_DIR=/usr/local/nvm +ENV NVM_VERSION=0.39.7 +RUN mkdir $NVM_DIR + +RUN curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh" | bash \ + && . $NVM_DIR/nvm.sh \ + && nvm install $NODE_VERSION \ + && nvm alias $NODE_VERSION \ + && nvm use $NODE_VERSION + +ENV NODE_PATH=$NVM_DIR/v$NODE_VERSION/lib/node_modules +ENV PATH=$NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH + +RUN git config --global --add safe.directory /project \ No newline at end of file diff --git a/reproducible-builds/README.md b/reproducible-builds/README.md new file mode 100644 index 0000000000..3e73e86ea1 --- /dev/null +++ b/reproducible-builds/README.md @@ -0,0 +1,78 @@ +# Reproducible builds + +In order to verify that Signal's official apps are correctly built from the open source code, we need *reproducible builds*. + +Reproducible builds help ensure that anyone, including you, can build Signal Desktop in a way that is completely identical to the official downloads available to all users. + +This provides an extra security layer to ensure that the builds aren't tampered with, corrupted, and built with the free open source code. + +## Reproduce and verify the Windows/macOS build + +Reproducible builds for macOS and Windows are not available yet. + +## Reproduce and verify the Linux build + +### Pre-requisites + +- Docker Engine is installed and running on your computer +- You need `git`. +- This guide assumes you are running a Unix-based system, but should otherwise work on any platform that runs Docker Engine. + +### Building + +First, grab the source code by using `git`: + +```bash +$ git clone https://github.com/signalapp/Signal-Desktop.git +``` + +This will download Signal Desktop's source code under the `Signal-Desktop` file. Once the download is complete, go inside the file and make sure you are selecting the branch used in official builds. For instance, if you are trying to build `7.18.0`, then do: + +```bash +$ cd Signal-Desktop/ +Signal-Desktop$ git checkout tags/7.16.0 +``` + +You are now on the version of the source code used for `7.16.0`. Then, make sure your shell is in the `reproducible-builds` directory first: + +```bash +Signal-Desktop$ cd reproducible-builds/ +Signal-Desktop/reproducible-builds$ pwd +[...]/Signal-Desktop/reproducible-builds +``` + +Last step is to run the `./build.sh` script. (If your user is not in Docker's `docker` group, then you may need to run the script as `sudo`). + +```bash +Signal-Desktop/reproducible-builds$ chmod +x ./build.sh +Signal-Desktop/reproducible-builds$ ./build.sh +``` + +This bash script will do two things. First, it will create the Docker container where Signal Desktop will be built. Second, it will build Signal Desktop inside the container. + +When the build is completed, the resulting file will be available at `Signal-Desktop/release/signal-desktop_7.18.0_amd64.deb`. + +### Verify the official build + +If you have followed the official Linux instructions to install Signal Desktop at https://signal.org/download/, then you will have `signal-desktop` available in your `apt` repositories. You can then simply grab the official build by typing: + +```bash +$ apt download signal-desktop +``` + +This will automatically download the official `.deb` package. + +To verify the official `.deb` package against your build, make sure that your version is the same as the official version, for example version `7.18.0`. Then, compare the checksums and make sure they are identical. If they are identical, then the two builds are exactly the same, and you have successfully reproduced Signal Desktop. + +(Note: do not compare with the checksums given below! They only serve as a visual example of what the output would look like) + +```bash +$ sha256sum signal-desktop_7.18.0_amd64-OUR_BUILD.deb signal-desktop_7.18.0_amd64_OFFICIAL_BUILD.deb + +0df3d06f74c6855559ef079b368326ca18e144a28ede559fd76648a62ec3eed7 signal-desktop_7.18.0_amd64-OUR_BUILD.deb +0df3d06f74c6855559ef079b368326ca18e144a28ede559fd76648a62ec3eed7 signal-desktop_7.18.0_amd64_OFFICIAL_BUILD.deb +``` + +### What to do if the checksums don't match + +- File an issue [on the Github Issues page](https://github.com/signalapp/Signal-Desktop/issues). \ No newline at end of file diff --git a/reproducible-builds/build.sh b/reproducible-builds/build.sh new file mode 100755 index 0000000000..6044b790c8 --- /dev/null +++ b/reproducible-builds/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +docker build -t signal-desktop --build-arg NODE_VERSION=$(cat ../.nvmrc) . +cd .. +docker run --rm -v "$(pwd)":/project -w /project --user "$(id -u):$(id -g)" signal-desktop sh -c "npm install; npm run generate; npm run build-release" diff --git a/reproducible-builds/docker/apt.conf b/reproducible-builds/docker/apt.conf new file mode 100644 index 0000000000..3309e3883f --- /dev/null +++ b/reproducible-builds/docker/apt.conf @@ -0,0 +1,6 @@ +Acquire::Check-Valid-Until "false"; +Acquire::Languages "none"; +Binary::apt-get::Acquire::AllowInsecureRepositories "false"; + +APT::Install-Recommends "false"; +APT::Immediate-Configure "false"; \ No newline at end of file diff --git a/reproducible-builds/docker/sources.list b/reproducible-builds/docker/sources.list new file mode 100644 index 0000000000..13c9ed69f0 --- /dev/null +++ b/reproducible-builds/docker/sources.list @@ -0,0 +1,3 @@ +deb http://mirror.signalusers.org/ubuntu/1687461439/ jammy main universe +deb http://mirror.signalusers.org/ubuntu/1687461439/ jammy-security main universe +deb http://mirror.signalusers.org/ubuntu/1687461439/ jammy-updates main universe \ No newline at end of file diff --git a/ts/scripts/generate-dns-fallback.ts b/ts/scripts/generate-dns-fallback.ts index 90e7736b9a..cdbed8c319 100644 --- a/ts/scripts/generate-dns-fallback.ts +++ b/ts/scripts/generate-dns-fallback.ts @@ -60,7 +60,7 @@ async function main() { const outPath = join(__dirname, '../../build/dns-fallback.json'); - await writeFile(outPath, `${JSON.stringify(config, null, 2)}\n`); + //await writeFile(outPath, `${JSON.stringify(config, null, 2)}\n`); } main().catch(error => {