Skip to content

Commit c470234

Browse files
authored
build: improve build reproducibility (#8549)
Remove sources of non-determinism in the build process. ### Changes - Add `-trimpath` to Go builds (strips file paths from binaries) - Use commit timestamp for `BuildTime` ldflags instead of `$(date -u)` - Use commit timestamp for VERSION string instead of `$(date +%s)` - Set `SOURCE_DATE_EPOCH` environment variable - Normalize timestamps in `.deb` packages - Add reproducible tar options (`--mtime`, `--owner`, `--group`, `--sort`) ### What this achieves Builds on the **same OS/toolchain** now produce identical artifacts. Verified by running try-release twice on the same commit—both produced identical SHA256 checksums. ### What this does NOT address Full reproducibility across different build environments would additionally require: - Pinning OS versions (CGO library linkage varies by OS) - Potentially other factors This PR addresses the low-hanging fruit; cross-environment reproducibility is out of scope.
1 parent 19c7ce0 commit c470234

4 files changed

Lines changed: 19 additions & 6 deletions

File tree

Containerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
FROM docker.io/ubuntu:24.04 AS builder
55

66
ARG COMMIT_ID
7+
ARG COMMIT_TIMESTAMP
78
ARG GO_VERSION
89
ARG VERSION
910

1011
ENV DEBIAN_FRONTEND=noninteractive
12+
ENV SOURCE_DATE_EPOCH=${COMMIT_TIMESTAMP}
1113
RUN apt-get --assume-yes --no-install-recommends --update install \
1214
ca-certificates curl gcc git gnupg2 libc6-dev
1315

@@ -22,16 +24,18 @@ WORKDIR /opt/boulder
2224
ENV GOBIN=/opt/boulder/bin/
2325
RUN go install \
2426
-buildvcs=false \
25-
-ldflags="-X \"github.com/letsencrypt/boulder/core.BuildID=${COMMIT_ID}\" -X \"github.com/letsencrypt/boulder/core.BuildTime=$(date -u)\"" \
27+
-trimpath \
28+
-ldflags="-X \"github.com/letsencrypt/boulder/core.BuildID=${COMMIT_ID}\" -X \"github.com/letsencrypt/boulder/core.BuildTime=$(date -u -d @${COMMIT_TIMESTAMP})\"" \
2629
-mod=vendor \
2730
./...
2831

2932
FROM docker.io/ubuntu:24.04
3033

34+
ARG COMMIT_DATE_ISO8601
3135
ARG VERSION
3236

3337
LABEL org.opencontainers.image.authors="Internet Security Research Group, https://letsencrypt.org/"
34-
LABEL org.opencontainers.image.created="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
38+
LABEL org.opencontainers.image.created="${COMMIT_DATE_ISO8601}"
3539
LABEL org.opencontainers.image.description="Boulder is an ACME-compatible X.509 Certificate Authority"
3640
LABEL org.opencontainers.image.documentation="https://github.com/letsencrypt/boulder"
3741
LABEL org.opencontainers.image.licenses="MPL-2.0"

test/ct-test-srv/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ COPY go.mod go.sum vendor ./
99

1010
COPY . .
1111

12-
RUN go build -o /bin/ct-test-srv ./test/ct-test-srv/main.go
12+
RUN go build -trimpath -o /bin/ct-test-srv ./test/ct-test-srv/main.go
1313

1414
FROM ubuntu:24.04
1515

tools/container-build.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,27 @@ fi
2121

2222
ARCH="$(uname -m)"
2323
COMMIT_ID="$(git rev-parse --short=8 HEAD)"
24-
VERSION="${GO_VERSION}.$(date +%s)"
24+
COMMIT_TIMESTAMP="$(git show -s --format=%ct HEAD)"
25+
COMMIT_DATE_ISO8601="$(TZ=UTC0 git show -s --format=%cd --date=format:%Y-%m-%dT%H:%M:%SZ HEAD)"
26+
VERSION="${GO_VERSION}.${COMMIT_TIMESTAMP}"
2527

2628
docker buildx build \
2729
--file Containerfile \
2830
--build-arg "COMMIT_ID=${COMMIT_ID}" \
31+
--build-arg "COMMIT_TIMESTAMP=${COMMIT_TIMESTAMP}" \
32+
--build-arg "COMMIT_DATE_ISO8601=${COMMIT_DATE_ISO8601}" \
2933
--build-arg "GO_VERSION=${GO_VERSION}" \
3034
--build-arg "VERSION=${VERSION}" \
3135
--tag "boulder:${VERSION}" \
3236
--tag "boulder:${COMMIT_ID}" \
3337
--tag boulder \
3438
.
3539

36-
docker run boulder tar -C /opt/boulder -cpz . > "./boulder-${VERSION}-${COMMIT_ID}.${ARCH}.tar.gz" .
40+
docker run boulder tar -C /opt/boulder --mtime="@${COMMIT_TIMESTAMP}" --owner=0 --group=0 --numeric-owner --sort=name -cp . | gzip -n > "./boulder-${VERSION}-${COMMIT_ID}.${ARCH}.tar.gz"
3741
# Produces e.g. boulder-1.25.0.1754519595-591c0545.x86_64.deb
3842
docker run -v .:/boulderrepo \
39-
-e "COMMIT_ID=$(git rev-parse --short=8 HEAD)" \
43+
-e "COMMIT_ID=${COMMIT_ID}" \
4044
-e "VERSION=${VERSION}" \
45+
-e "SOURCE_DATE_EPOCH=${COMMIT_TIMESTAMP}" \
4146
boulder \
4247
/boulderrepo/tools/make-deb.sh

tools/make-deb.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ Homepage: https://github.com/letsencrypt/boulder
2929
Description: Boulder is an ACME-compatible X.509 Certificate Authority
3030
EOF
3131

32+
# Normalize timestamps for reproducible builds (after all files created)
33+
find "${BUILD}" ! -type l -exec touch -d "@${SOURCE_DATE_EPOCH}" {} \;
34+
find "${BUILD}" -type l -exec touch -h -d "@${SOURCE_DATE_EPOCH}" {} \;
35+
3236
dpkg-deb -Zgzip -b "${BUILD}" "boulder-${VERSION}-${COMMIT_ID}.x86_64.deb"

0 commit comments

Comments
 (0)