Repository navigation
fix(image): pin musl in the runtime apk transaction so the image builds reproducibly - #197
Merged
Merged
Conversation
…ds reproducibly `apk add --upgrade` upgrades the dependencies of every package it names. libcrypto3, libssl3, libuuid and su-exec all depend on musl, which was not named, so musl floated with the Alpine v3.24 index. Alpine published musl 1.2.6-r3 around 2026-10-26, the runtime layer picked it up in place of the base image's 1.2.6-r2, and the image digest moved with no Dockerfile change (sha256:e9b799a7… on every PR, against the locked sha256:20295012…). Name musl=1.2.6-r3 so every package the transaction changes carries an exact version, assert it in TestRuntimeDockerfilePinsReproducibleBuildInputs, and record the whole-transaction rule in the runtime-image-relock skill. runtime-image.json moves in the next commit, once CI has published this candidate by digest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI published the candidate for 5e8b184 by digest and built sha256:1d7680adb926a17a378b4f56e4b33ed98b64c8dabf39f2301b6d5d71ff5c75e3, the same digest two local --no-cache builds produce with CI's buildkit and flags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke
Since 2026-10-26 every PR (#194, #195, #196) has failed
imageat "Verify runtime image candidate". All three built the same digest,sha256:e9b799a7…, against the lockedsha256:20295012…, andciwas skipped. None of them touches the Dockerfile.Root cause
The two indexes differ in exactly one layer per platform: the runtime stage's
apk add --no-cache --upgradelayer. The pgvectorCOPYlayer and every base layer are byte-identical, so the builder stage andbuild-baseare not the cause. Inside that layer the only difference inlib/apk/db/installedis:The new layer also carries
lib/ld-musl-*.so.1.apk add --upgradeupgrades the dependencies of every package it names. libcrypto3, libssl3, libuuid and su-exec all depend on musl, and musl was not named, so it floated with the Alpine v3.24 index. When Alpine published musl1.2.6-r3, it replaced the base image's1.2.6-r2.apk add --simulateagainst the pinned base confirms that musl is the only unnamed package the transaction changes.Fix
apk addchanges is now named at an exact version:musl=1.2.6-r3joins libcrypto3, libssl3, libuuid and su-exec. If Alpine rebuilds musl again, the build fails with "unable to select packages" instead of drifting silently. This is the same failure mode the other pins already have.TestRuntimeDockerfilePinsReproducibleBuildInputsasserts the new pin.runtime-image-relockskill now says to pin the whole transaction and shows how to list it (apk add --simulate).runtime-image.jsonis re-locked through the skill's loop: CI publishes the candidate by digest, then the lock takes the built digest. The tag string does not change (postgres 17.10, pgvector 0.8.5, alpine 3.24).Classification: fix, at the place that owns the behaviour (the runtime image's package pins). It is not a digest bump: the input that moved is now pinned. Reused: the repo's existing pin test, its relock loop and CI's own reproducible build flags. No new mechanism.
Evidence
moby/buildkit@sha256:2f5adac4…, docker-container driver), using the same flags as the candidate publish (SOURCE_DATE_EPOCH=0,rewrite-timestamp=true, no provenance or SBOM, linux/amd64+arm64):mainunchanged givessha256:e9b799a7…, exactly what CI built on feat(runtime): share local Postgres through a server dependency #194–feat(runtime): one native Postgres server per run, a database and an owner per service #196. The local method reproduces CI.--no-cachebuilds, givessha256:1d7680adb926a17a378b4f56e4b33ed98b64c8dabf39f2301b6d5d71ff5c75e3both times.Not verified / remaining risk
build-base/clang21/llvm21-dev(gcc, binutils, musl-dev, …). They also moved on 2026-10-26, and the.socame out byte-identical, so they did not cause this break. Their output is still not pinned, though. If a toolchain rebuild ever changes the pgvector bytes, this same check will catch it.🤖 Generated with Claude Code