Make the pinned golangci-lint actually reach the host (closes #28)
All checks were successful
check / check (push) Successful in 7s
All checks were successful
check / check (push) Successful in 7s
REPO_POLICIES.md now carries the canonical script/bootstrap snippet for Go repos alongside the .golangci.yml bullet, where the pinned linter version already lives. The guard it replaces, `if missing golangci-lint; then go install ...; fi`, tests PATH presence and never version, so on any already-provisioned machine the pin is inert and a version bump is a no-op. The Dockerfile installs unconditionally into a clean image, so CI and local then disagree about what the linter is: a local `make check` green while `make docker` rejects the same commit, and a container run surfacing findings the host run cannot see. Comparing versions alone is not enough. `go install` writes to GOBIN (or GOPATH/bin) while callers resolve through PATH, so a shadowing binary earlier in PATH lets the install succeed and change nothing a caller ever sees, while bootstrap prints success. The canonical form therefore compares the installed version against the pin, re-resolves through PATH after installing and asserts the pin, failing non-zero and naming the shadowing path when it does not, and treats any unparseable --version output as a mismatch so the failure direction is a redundant install rather than a skipped one. The policy text states each of those as a requirement rather than leaving them implicit in the code, records why the commit-pinned `go install` ref satisfies the hash-pinning rule (a commit hash is not a mutable tag, and the go command verifies the module against the checksum database), and requires that any change to this logic be validated with a negative control run against a shadowing binary, because a control without one passes against the naive implementation too. The node and yarn handling described earlier in the document is untouched. Verified by extracting the snippet to a scratch harness with fake `go` and both fake and real golangci-lint binaries: shadowing fails loudly and names the path while the naive compare-then-install form reports success with the stale 2.7.2 still resolved; a wrong version at the install target is replaced; garbage, empty and non-zero --version output all reinstall; the matching case runs zero installs. The block in the document is byte-identical to the one exercised.
This commit is contained in:
8
TODO.md
8
TODO.md
@@ -21,6 +21,14 @@ fmt-check, and commit.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-08-09: Made the pinned golangci-lint actually propagate: REPO_POLICIES.md
|
||||
now carries the canonical `script/bootstrap` snippet for Go repos, which
|
||||
installs when the installed version does not match the pin (the old
|
||||
`if missing` guard tested PATH presence only, so pins were inert on any
|
||||
provisioned machine and CI silently disagreed with local) and then re-resolves
|
||||
the binary through `PATH` and fails loudly, naming the shadowing path, when
|
||||
the install did not take effect — the failure mode the naive
|
||||
compare-then-install fix leaves behind while reporting success.
|
||||
- 2026-08-09: Fixed the false green in the canonical CI gate: `script/cibuild`
|
||||
and `script/docker` now pass a per-invocation `CHECK_EPOCH` nonce, and the
|
||||
`Dockerfile` (plus the Go multistage template in REPO_POLICIES.md, in both its
|
||||
|
||||
Reference in New Issue
Block a user