Shipping reproducible binaries on github: repro-env
kpcyrd
kpcyrd at archlinux.org
Sat Jul 8 21:18:11 UTC 2023
hello,
my initial interest in reproducible builds was "how do I distribute
pre-compiled binaries on github without people raising security concerns
about them".
I've cycled back to this original problem about 5 years later and built
a tool that is meant to address this:
https://github.com/kpcyrd/repro-env
It works by adding two more files into your git repository that work
together like Cargo.toml/Cargo.lock or package.json/package-lock.json:
- **repro-env.toml**: this describes the environment you're aiming for,
eg. "the latest debian bookworm, with rust and gcc installed, everything
fully upgraded"
- **repro-env.lock**: this is the resolved state from back then, with a
list of .deb files, their version and sha256
The repro-env.lock is very similiar to buildinfo files in eg. Arch Linux
or Debian.
For the operating system base it's using **podman** internally (with
unprivileged user namespaces) and **repro-env.lock** also tracks a
container image by its `@sha256:`.
The build directory is always mounted to /build/, most other things are
provided by the pinned container image, eg the username or any
environment variables.
Additional packages can be installed from these two archive services:
- https://archive.archlinux.org
- https://snapshot.debian.org
For example for repro-env itself the **repro-env.toml** looks like this
(I found this environment works slightly better for static binaries than
docker.io/library/rust, which of course can also be used):
```
[container]
image = "docker.io/library/archlinux"
[packages]
system = "archlinux"
dependencies = ["make", "musl", "rust-musl"]
```
The resolved dependency-lock file then may look something like this:
```
[container]
image =
"docker.io/library/archlinux at sha256:6568d3f1f278827a4a7d8537f80c2ae36982829a0c6bccff4cec081774025472"
[[package]]
name = "binutils"
version = "2.40-6"
system = "archlinux"
url =
"https://archive.archlinux.org/packages/b/binutils/binutils-2.40-6-x86_64.pkg.tar.zst"
sha256 = "b65fd16001578e10b602e577a8031cbfffc1164caf47ed9ba00c60d804519430"
signature =
"iNUEABYKAH0WIQQFx3danouXdAf+COadTFqhVCbaCgUCZG6Rg18UgAAAAAAuAChpc3N1ZXItZnByQG5vdGF0aW9ucy5vcGVucGdwLmZpZnRoaG9yc2VtYW4ubmV0MDVDNzc3NUE5RThCOTc3NDA3RkUwOEU2OUQ0QzVBQTE1NDI2REEwQQAKCRCdTFqhVCbaCge2AQD/LGBeHRaeO8xh4E/bAYfqd1O/OFqk2DrQBJ73cdKl2gD9EC8p4U/cXQK8V774m6LSS50usH5pxcQWEq/H0SF+FgM="
# [...]
[[package]]
name = "rust"
version = "1:1.69.0-3"
system = "archlinux"
url =
"https://archive.archlinux.org/packages/r/rust/rust-1%3A1.69.0-3-x86_64.pkg.tar.zst"
sha256 = "b8eb31a2eb80efab27bb68beab80436ed3e1d235a217c3e24ba973936c95839e"
signature =
"iIsEABYIADMWIQQGaHodnU+rCLUP2Ss7lKgOUKR3xwUCZExVKBUcaGVmdGlnQGFyY2hsaW51eC5vcmcACgkQO5SoDlCkd8fQkAD6AudRi2qP3WxSn38OOkSRSITciqRevPaVJgrz03JUBEAA/12h9z8dReD07Lqnltx9QTa3Cxppbv7VpJlTCQuavoMG"
```
This is usually sufficient to achieve reproducible builds. This tool, of
course, does not prevent you from doing something silly that breaks
reproducible builds, like recording `uname` output, the current time, or
the order the kernel responds to readdir() syscalls. *wink*
There are 4 example projects here, with Rust, Golang and C twice:
https://github.com/kpcyrd/repro-env/tree/main/examples
The overall concept works so well, github actions CI always builds all 4
projects for every commit and verifies the sha256 still matches:
https://github.com/kpcyrd/repro-env/blob/786e23e4f49e48bb42a2c911a0dfd870b8cf98ac/.github/workflows/rust.yml#L73-L88
The sha256 of repro-env v0.2.0 for x86_64 Linux is:
b78727a7b2f635504ab780bfa5dd7e7bbcfb9255607eaf815762e0893aad5663
It can be downloaded here:
https://github.com/kpcyrd/repro-env/releases/download/v0.2.0/repro-env
It can be built from this git commit:
0c8e630af20f6d7cee0949e1b78d3ea9c9e358fa
Let me know what you think. 🌈
cheers,
kpcyrd
More information about the rb-general
mailing list