Make the pinned golangci-lint actually reach the host (closes #28)
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:
clawbot
2026-08-09 15:23:50 +00:00
parent 51c394552e
commit 07129f0ec1
2 changed files with 116 additions and 0 deletions

View File

@@ -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