Dockerfile installs prerequisites inline instead of running script/bootstrap #42
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Surfaced by re-vendoring the policy doc in #20 — this requirement was among the 40 lines the stale copy was missing, so nothing in the repo was checking it.
Canonical
REPO_POLICIES.md:97requires: "Dockerfiles install development prerequisites by runningscript/bootstraprather than duplicating installs inline; COPYscript/and the dependency manifests before running it so the bootstrap layer stays cached until dependencies change."The
Dockerfiledoes the opposite. The build stage runsRUN apk add --no-cache makeinline, never invokesscript/bootstrap, and never copiesscript/alongsidego.mod/go.sum.This has teeth beyond tidiness, and #24 is exactly why.
script/bootstrapis now the thing that pins the golangci-lint version and verifies the install actually took effect against whatPATHresolves. A Dockerfile that bypasses it maintains a second, independent notion of the toolchain — which is precisely the local-versus-CI divergence #24 existed to close, reintroduced one layer down. Today the build stage borrows the linter binary from the lint stage viaCOPY --from=lint, so the versions happen to agree; nothing enforces that they continue to.Definition of done
script/plusgo.modandgo.sum, then runsscript/bootstrapin place of the inlineapk add --no-cache make.ARG CHECK_EPOCHcache-buster added in #32, so the bootstrap layer stays cached while the gate layers still go cold on every build. Verify both properties still hold after the change — gates execute every run, dependency and bootstrap layers stay cached.COPY --from=lint /usr/bin/golangci-lint. Ifscript/bootstrapnow installs the pinned linter in the build stage, that copy may be redundant — but it also currently serves as the BuildKit stage dependency that forces the lint stage to complete first. Do not remove it without replacing that dependency, or the fail-fast design silently dies. This is the trap in this issue.builderuser beforemake check, andTestScanHardlinkRunFailsTogethermust remain genuinely exercised. Verify by running the suite in the image as--user 0:0and confirming it fails — if it passes as root, the test is no longer testing anything.script/bootstrapmust work under Alpine'sshand itsapkbranch. It is POSIXshalready, but it has never actually been executed in this image.make checkgreen andmake dockergreen with the gates demonstrably executing (see #32 and #39).Plan.
Build stage becomes:
COPY --from=lint /usr/bin/golangci-lint /usr/local/bin/golangci-lintstays, and moves to sit before bootstrap. It is the BuildKit stage dependency that forces lint to finish first (item 3), so it is not removed. Placing it first also closes the gap the issue names:script/bootstrapversion-checks whateverPATHresolves, so the copied binary is now compared against the pin on every build and the two toolchains can no longer silently diverge.RUN apk add --no-cache makeandRUN go mod downloadare replaced byCOPY script/ script/,COPY go.mod go.sum ./,RUN script/bootstrap(bootstrap ends ingo mod download).ENV PATHgains$GOPATH/binso that if the copied linter ever stops matching the pin, bootstrap'sgo installlands somewherePATHresolves instead of failing its own verification.ARG CHECK_EPOCH(item 2);chown+USER builderstill precedemake check(item 4).Verification I will run and report: gates execute on every build and bootstrap/dependency layers
CACHEDon a second run; planted lint finding fails the build before the build stage'smake checkstarts; suite run in the image as--user 0:0FAILSTestScanHardlinkRunFailsTogether;make checkandmake dockergreen; build wall time against the five-minute ceiling.