Reproducible builds
🔁 Reproducible builds
Section titled “🔁 Reproducible builds”Dependency pinning guarantees the build always starts from the same sources. Reproducible builds guarantee the next step: that those sources always produce the same binary. This is the property that makes a SolarWinds-style attack detectable.
🎯 Why it matters
Section titled “🎯 Why it matters”In the SolarWinds attack (2020), the source code was never modified: the implant was injected during compilation, on the build server. Code review could not see anything, and the binary was signed with the legitimate certificate.
The only structural defense is reproducibility:
If two independent compilations of the same commit produce the same binary bit for bit, then any published binary that differs from an independent rebuild is proof of an injection.
Reproducibility turns “trust us” into “verify for yourself”.
🧩 Sources of non-determinism
Section titled “🧩 Sources of non-determinism”A naive build is not reproducible because several elements vary from one compilation to the next:
| Source of variation | Effect on the binary |
|---|---|
| Build timestamp | different embedded dates |
| Absolute project path | /home/alice/... vs /home/bob/... baked into the binary |
| Compilation order / parallelism | reordered sections |
| Linker metadata (Windows) | variable PE timestamps |
SONAR neutralizes these sources at the build entry point, identically in CI,
locally, and during reproducibility checks, through a shared script:
security/repro-env.ts.
🛠 What SONAR fixes
Section titled “🛠 What SONAR fixes”SOURCE_DATE_EPOCH
Section titled “SOURCE_DATE_EPOCH”A stable timestamp is injected into the environment. Build tools that honor it (compilers, packagers) use it instead of “the current time”, which makes embedded dates deterministic.
Path remapping (--remap-path-prefix)
Section titled “Path remapping (--remap-path-prefix)”By default Rust bakes absolute source paths into the binary (panic messages,
debug info). The --remap-path-prefix flag rewrites the project root path to a
neutral value: no local path leaks, and two developers on two different
machines get the same binary.
/Brepro flag (Windows / MSVC)
Section titled “/Brepro flag (Windows / MSVC)”The MSVC linker inserts a timestamp into the PE executable header by default.
The /Brepro flag forces a reproducible value.
🔬 Reproducibility then trust: don’t mix them
Section titled “🔬 Reproducibility then trust: don’t mix them”A subtle but essential point: signatures and attestations are not part of the reproducible binary.
- The reproducible payload is the unsigned binary.
- Signatures, attestations, SBOM and hashes are added after the build, as detached files.
Why? Because signing a file changes its bytes. If we compared signed binaries, they would always differ (each signature is unique). So we verify reproducibility on the unsigned artifact, then layer trust on top without touching the payload.
1. Verify reproducibility of the UNSIGNED binary ← determinism2. Build the binaries and native bundles3. Generate SHA256 hashes4. Generate provenance attestations5. Sign the artifacts (Sigstore/cosign, detached signatures)6. Publish hashes + signatures + attestations + SBOM✅ Verify it yourself
Section titled “✅ Verify it yourself”As a maintainer, before release
Section titled “As a maintainer, before release”./security/repro-check.shThe script compiles the binary twice and compares the SHA256 hashes. In CI,
the publish.yml workflow contains a blocking job (verify unsigned
reproducible binary): publication fails if the binary is not reproducible.
As an external auditor
Section titled “As an external auditor”- Check out the tagged commit of the release.
- Rebuild the binary with the same environment (
security/repro-env.ts). - Compare the resulting SHA256 with the SHA256 published in the release.
A mismatch = a red flag to investigate.
⚠️ Known limitations
Section titled “⚠️ Known limitations”- Reproducibility currently covers the binary, not yet all native installers (MSI, NSIS, DEB, RPM, DMG), which embed variable metadata. Those remain covered by hash + attestation + signature.
- Post-release verification is still a documented manual step.
See also
Section titled “See also”- Release trust — verify hash, provenance and signature
- Reproducibility matrix