Reproducible Builds

Stella Ops releases are reproducible: given the same source code and build environment, anyone can produce byte-identical artifacts.

Overview

Reproducible builds provide:

  1. Verifiability - Anyone can verify that released binaries match source code
  2. Trust - No need to trust the build infrastructure
  3. Auditability - Build process can be independently audited
  4. Security - Compromised builds can be detected

How It Works

SOURCE_DATE_EPOCH

All timestamps in build outputs use the SOURCE_DATE_EPOCH environment variable instead of the current time. This is set to the git commit timestamp:

export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)

Deterministic Build Settings

The following MSBuild properties ensure deterministic .NET builds:

<!-- src/Directory.Build.props -->
<PropertyGroup>
  <Deterministic>true</Deterministic>
  <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
  <PathMap>$(MSBuildProjectDirectory)=/src/</PathMap>
  <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

Pinned Dependencies

All dependencies are pinned to exact versions in Directory.Packages.props:

<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />

Containerized Builds

Release builds run in containerized environments with:

Reproducing a Build

Prerequisites

Steps

  1. Clone the repository
git clone https://git.stella-ops.org/stella-ops.org/git.stella-ops.org.git
cd git.stella-ops.org
  1. Checkout the release tag
git checkout v1.2.3
  1. Set SOURCE_DATE_EPOCH

Get the value from the release evidence pack manifest.json:

export SOURCE_DATE_EPOCH=1705315800

Or compute from git:

export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)
  1. Build
# Using make
make release

# Or using dotnet directly
dotnet publish src/Cli/StellaOps.Cli/StellaOps.Cli.csproj \
  --configuration Release \
  --runtime linux-x64 \
  --self-contained true \
  /p:Deterministic=true \
  /p:ContinuousIntegrationBuild=true \
  /p:SourceRevisionId=$(git rev-parse HEAD)
  1. Compare checksums
sha256sum dist/stella-* | diff - path/to/evidence-pack/checksums/SHA256SUMS

CI Verification

The CI pipeline automatically verifies reproducibility:

  1. Builds artifacts twice with the same SOURCE_DATE_EPOCH
  2. Compares checksums between builds
  3. Fails if checksums don’t match

See .gitea/workflows/verify-reproducibility.yml.

What Can Cause Non-Reproducibility

Timestamps

Path Information

Random Values

Unordered Collections

External Resources

Compiler/Tool Versions

Debugging Non-Reproducible Builds

Compare binaries

# Install diffoscope
pip install diffoscope

# Compare two builds
diffoscope build1/stella.dll build2/stella.dll

Check for timestamps

# Look for embedded timestamps
strings stella.dll | grep -E '20[0-9]{2}-[0-9]{2}'

Check PDB content

# Examine PDB for path information
dotnet tool install -g dotnet-symbol
dotnet symbol --symbols stella.dll

Verification in Evidence Pack

The Release Evidence Pack includes:

  1. SOURCE_DATE_EPOCH in manifest.json
  2. Source commit for exact source checkout
  3. Checksums for comparison
  4. Build instructions in VERIFY.md