Policy: "ALL external references must be pinned by cryptographic hash...
Version tags are server-mutable and therefore remote code execution
vulnerabilities... There are zero exceptions to this rule."
The Dockerfile and the Gitea workflow comply. The developer-facing install
path does not:
script/bootstrap:141-143 installs golangci-lint from whatever the OS
package manager offers — nix, apt, brew, or apk — with no version
constraint at all. This is not merely unpinned, it is unversioned.
Makefile:36: go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
— mutable tag.
Makefile:51 (devprereqs): go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
— mutable tag, and a second, weaker source of truth competing with script/bootstrap.
script/bootstrap never installs gofumpt or prettier, both of which script/fmt requires. A developer who follows make setup cannot run make fmt.
This is not theoretical. On this machine script/bootstrap produced
golangci-lint v2.10.1 while the repo pins v2.12.2, and the two
disagree by 10 findings. That skew already caused a green PR to look red
locally, and it will keep costing review time until it is fixed.
Definition of done
script/bootstrap installs the exact pinned golangci-lint version the
repo targets, verified by hash, on every supported platform — not
"whatever the package manager has".
gofumpt and prettier are installed by script/bootstrap at pinned
versions, so make fmt works on a fresh clone after make setup.
Makefile:36 and the devprereqs target either install by content hash
or are deleted in favour of script/bootstrap being the single source of
truth. Prefer deletion — two install paths is the actual defect.
Every pinned version carries a # tool vX.Y.Z, YYYY-MM-DD comment, per
policy.
The pinned golangci-lint version appears in exactly one place that the Makefile, Dockerfile, and script/bootstrap all derive from, so they
cannot drift again.
Running script/bootstrap on a machine with a different golangci-lint
already on PATH results in the pinned version being used by script/lint — not the pre-existing one.
make check passes and docker build . succeeds. TODO.md updated in
the same commit.
Implementation requirements
Never curl | sh. Download a specific release archive, verify a hardcoded
sha256 with the existing verify_sha256 helper in script/bootstrap, then
install. That helper already exists and is used for nvm; follow it.
go install pkg@v1.2.3 is not hash pinning — the tag is mutable. If
you keep a go install path, it must resolve through a go.sum-verified
mechanism (a tools.go with the tool as a module dependency, built with
the repo's own go.sum), which is content-verified. Otherwise fetch a
release archive and verify its hash.
script/bootstrap must stay POSIX sh, set -eu, no bashisms, and stay
idempotent — re-running it must not reinstall or fail.
Per-platform hashes are required for a release-archive approach; detect
OS/arch and select the right one. Do not pin only the Linux amd64 hash and
silently fall through to an unverified install elsewhere.
If script/lint should assert the linter version matches the pin, add
that check and make the mismatch message tell the developer to run make bootstrap.
Commit title must end with (closes #68).
## Context
Policy: "ALL external references must be pinned by cryptographic hash...
Version tags are server-mutable and therefore remote code execution
vulnerabilities... There are zero exceptions to this rule."
The `Dockerfile` and the Gitea workflow comply. The developer-facing install
path does not:
- `script/bootstrap:141-143` installs `golangci-lint` from whatever the OS
package manager offers — nix, apt, brew, or apk — with **no version
constraint at all**. This is not merely unpinned, it is unversioned.
- `Makefile:36`: `go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1`
— mutable tag.
- `Makefile:51` (`devprereqs`): `go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2`
— mutable tag, and a second, weaker source of truth competing with
`script/bootstrap`.
- `script/bootstrap` never installs `gofumpt` or `prettier`, both of which
`script/fmt` requires. A developer who follows `make setup` cannot run
`make fmt`.
This is not theoretical. On this machine `script/bootstrap` produced
golangci-lint **v2.10.1** while the repo pins **v2.12.2**, and the two
disagree by 10 findings. That skew already caused a green PR to look red
locally, and it will keep costing review time until it is fixed.
## Definition of done
- `script/bootstrap` installs the exact pinned `golangci-lint` version the
repo targets, verified by hash, on every supported platform — not
"whatever the package manager has".
- `gofumpt` and `prettier` are installed by `script/bootstrap` at pinned
versions, so `make fmt` works on a fresh clone after `make setup`.
- `Makefile:36` and the `devprereqs` target either install by content hash
or are deleted in favour of `script/bootstrap` being the single source of
truth. Prefer deletion — two install paths is the actual defect.
- Every pinned version carries a `# tool vX.Y.Z, YYYY-MM-DD` comment, per
policy.
- The pinned `golangci-lint` version appears in exactly one place that the
`Makefile`, `Dockerfile`, and `script/bootstrap` all derive from, so they
cannot drift again.
- Running `script/bootstrap` on a machine with a different `golangci-lint`
already on `PATH` results in the pinned version being used by
`script/lint` — not the pre-existing one.
- `make check` passes and `docker build .` succeeds. `TODO.md` updated in
the same commit.
## Implementation requirements
- Never `curl | sh`. Download a specific release archive, verify a hardcoded
sha256 with the existing `verify_sha256` helper in `script/bootstrap`, then
install. That helper already exists and is used for nvm; follow it.
- `go install pkg@v1.2.3` is **not** hash pinning — the tag is mutable. If
you keep a `go install` path, it must resolve through a `go.sum`-verified
mechanism (a `tools.go` with the tool as a module dependency, built with
the repo's own `go.sum`), which is content-verified. Otherwise fetch a
release archive and verify its hash.
- `script/bootstrap` must stay POSIX sh, `set -eu`, no bashisms, and stay
idempotent — re-running it must not reinstall or fail.
- Per-platform hashes are required for a release-archive approach; detect
OS/arch and select the right one. Do not pin only the Linux amd64 hash and
silently fall through to an unverified install elsewhere.
- If `script/lint` should assert the linter version matches the pin, add
that check and make the mismatch message tell the developer to run
`make bootstrap`.
- Commit title must end with ` (closes #68)`.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:40:18 +02:00
Scope additions folded in from the PR #88 review, so they are fixed
alongside the bootstrap work they belong with rather than as a separate
issue.
The prettier half of this issue is already done. PR #88 added package.json / yarn.lock pinning prettier 3.9.6 by sha512, and script/bootstrap now installs node, yarn, and the locked JS deps. That
pin is verified enforced, not merely asserted — corrupting the lockfile
hash makes docker build . fail at Integrity check failed for "prettier".
So what remains here is: gofumpt, golangci-lint, and the Makefile Go tool installs. Adjust the definition of done accordingly;
do not redo the prettier work.
Four additional items to fix as part of this issue:
Make the prettier version check a hard failure.script/prettier
currently prefers node_modules/.bin/prettier but falls back to a PATH prettier of unknown version with only a stderr warning. Different
prettier versions format differently, so this is the same version-skew
trap that already cost a review cycle when a local golangci-lint v2.10.1
disagreed with the pinned v2.12.2 by ten findings. Compare the resolved
binary's --version against the pin in package.json and fail hard on
mismatch, naming script/bootstrap in the message.
Apply the identical treatment to gofumpt and golangci-lint in script/fmt, script/fmt-check-go, and script/lint — those are
currently invoked with no version check at all, which is worse. That
consistency is the reason the prettier fallback was not treated as
blocking on #88.
Correct the --frozen-lockfile explanation. The comment in script/bootstrap (and the #88 commit message) states that --frozen-lockfile enforces the integrity hash. It does not — the flag
only guards lockfile-versus-manifest consistency; integrity verification
happens at fetch time regardless. The behaviour is right, the stated
reason is wrong, and a wrong reason in a comment about supply-chain
pinning will mislead the next person to touch it.
Remove the dead make fmt-check-md target, or wire it up. It is
currently unreachable.
Record the Dockerfile lint-stage deviation in TODO.md. The lint
stage runs make fmt-check-go rather than the canonical policy
Dockerfile's make fmt-check, because the golangci/golangci-lint
image has no node and the markdown check lives in its own mdfmt stage.
That is deliberate and correct, but it is a visible divergence from the
template — without a note, a future policy audit will "correct" it back
and silently drop the markdown gate.
Also cosmetic, fix while you are in there: package.json invents "version": "0.1.0" for a private manifest that has no version semantics,
and script/fmt-check prints its "Checking formatting" banner twice.
Scope additions folded in from the PR #88 review, so they are fixed
alongside the bootstrap work they belong with rather than as a separate
issue.
**The prettier half of this issue is already done.** PR #88 added
`package.json` / `yarn.lock` pinning prettier 3.9.6 by `sha512`, and
`script/bootstrap` now installs node, yarn, and the locked JS deps. That
pin is verified enforced, not merely asserted — corrupting the lockfile
hash makes `docker build .` fail at `Integrity check failed for "prettier"`.
So what remains here is: **gofumpt**, **golangci-lint**, and the
**Makefile Go tool installs**. Adjust the definition of done accordingly;
do not redo the prettier work.
Four additional items to fix as part of this issue:
1. **Make the prettier version check a hard failure.** `script/prettier`
currently prefers `node_modules/.bin/prettier` but falls back to a
`PATH` prettier of unknown version with only a stderr warning. Different
prettier versions format differently, so this is the same version-skew
trap that already cost a review cycle when a local golangci-lint v2.10.1
disagreed with the pinned v2.12.2 by ten findings. Compare the resolved
binary's `--version` against the pin in `package.json` and fail hard on
mismatch, naming `script/bootstrap` in the message.
Apply the identical treatment to `gofumpt` and `golangci-lint` in
`script/fmt`, `script/fmt-check-go`, and `script/lint` — those are
currently invoked with no version check at all, which is worse. That
consistency is the reason the prettier fallback was not treated as
blocking on #88.
2. **Correct the `--frozen-lockfile` explanation.** The comment in
`script/bootstrap` (and the #88 commit message) states that
`--frozen-lockfile` enforces the integrity hash. It does not — the flag
only guards lockfile-versus-manifest consistency; integrity verification
happens at fetch time regardless. The behaviour is right, the stated
reason is wrong, and a wrong reason in a comment about supply-chain
pinning will mislead the next person to touch it.
3. **Remove the dead `make fmt-check-md` target**, or wire it up. It is
currently unreachable.
4. **Record the Dockerfile lint-stage deviation in `TODO.md`.** The lint
stage runs `make fmt-check-go` rather than the canonical policy
Dockerfile's `make fmt-check`, because the `golangci/golangci-lint`
image has no node and the markdown check lives in its own `mdfmt` stage.
That is deliberate and correct, but it is a visible divergence from the
template — without a note, a future policy audit will "correct" it back
and silently drop the markdown gate.
Also cosmetic, fix while you are in there: `package.json` invents
`"version": "0.1.0"` for a private manifest that has no version semantics,
and `script/fmt-check` prints its "Checking formatting" banner twice.
The items still open are fixed in #155: gofumpt is now checked against hashes in the repo, prettier refuses any version but the pinned one, and three comment and package.json fixes. The PR body lists every item as satisfied, moot or fixed.
Model: opus-5-5
The items still open are fixed in https://git.eeqj.de/sneak/mfer/pulls/155: gofumpt is now checked against hashes in the repo, prettier refuses any version but the pinned one, and three comment and `package.json` fixes. The PR body lists every item as satisfied, moot or fixed.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context
Policy: "ALL external references must be pinned by cryptographic hash...
Version tags are server-mutable and therefore remote code execution
vulnerabilities... There are zero exceptions to this rule."
The
Dockerfileand the Gitea workflow comply. The developer-facing installpath does not:
script/bootstrap:141-143installsgolangci-lintfrom whatever the OSpackage manager offers — nix, apt, brew, or apk — with no version
constraint at all. This is not merely unpinned, it is unversioned.
Makefile:36:go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1— mutable tag.
Makefile:51(devprereqs):go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2— mutable tag, and a second, weaker source of truth competing with
script/bootstrap.script/bootstrapnever installsgofumptorprettier, both of whichscript/fmtrequires. A developer who followsmake setupcannot runmake fmt.This is not theoretical. On this machine
script/bootstrapproducedgolangci-lint v2.10.1 while the repo pins v2.12.2, and the two
disagree by 10 findings. That skew already caused a green PR to look red
locally, and it will keep costing review time until it is fixed.
Definition of done
script/bootstrapinstalls the exact pinnedgolangci-lintversion therepo targets, verified by hash, on every supported platform — not
"whatever the package manager has".
gofumptandprettierare installed byscript/bootstrapat pinnedversions, so
make fmtworks on a fresh clone aftermake setup.Makefile:36and thedevprereqstarget either install by content hashor are deleted in favour of
script/bootstrapbeing the single source oftruth. Prefer deletion — two install paths is the actual defect.
# tool vX.Y.Z, YYYY-MM-DDcomment, perpolicy.
golangci-lintversion appears in exactly one place that theMakefile,Dockerfile, andscript/bootstrapall derive from, so theycannot drift again.
script/bootstrapon a machine with a differentgolangci-lintalready on
PATHresults in the pinned version being used byscript/lint— not the pre-existing one.make checkpasses anddocker build .succeeds.TODO.mdupdated inthe same commit.
Implementation requirements
curl | sh. Download a specific release archive, verify a hardcodedsha256 with the existing
verify_sha256helper inscript/bootstrap, theninstall. That helper already exists and is used for nvm; follow it.
go install pkg@v1.2.3is not hash pinning — the tag is mutable. Ifyou keep a
go installpath, it must resolve through ago.sum-verifiedmechanism (a
tools.gowith the tool as a module dependency, built withthe repo's own
go.sum), which is content-verified. Otherwise fetch arelease archive and verify its hash.
script/bootstrapmust stay POSIX sh,set -eu, no bashisms, and stayidempotent — re-running it must not reinstall or fail.
OS/arch and select the right one. Do not pin only the Linux amd64 hash and
silently fall through to an unverified install elsewhere.
script/lintshould assert the linter version matches the pin, addthat check and make the mismatch message tell the developer to run
make bootstrap.(closes #68).Scope additions folded in from the PR #88 review, so they are fixed
alongside the bootstrap work they belong with rather than as a separate
issue.
The prettier half of this issue is already done. PR #88 added
package.json/yarn.lockpinning prettier 3.9.6 bysha512, andscript/bootstrapnow installs node, yarn, and the locked JS deps. Thatpin is verified enforced, not merely asserted — corrupting the lockfile
hash makes
docker build .fail atIntegrity check failed for "prettier".So what remains here is: gofumpt, golangci-lint, and the
Makefile Go tool installs. Adjust the definition of done accordingly;
do not redo the prettier work.
Four additional items to fix as part of this issue:
Make the prettier version check a hard failure.
script/prettiercurrently prefers
node_modules/.bin/prettierbut falls back to aPATHprettier of unknown version with only a stderr warning. Differentprettier versions format differently, so this is the same version-skew
trap that already cost a review cycle when a local golangci-lint v2.10.1
disagreed with the pinned v2.12.2 by ten findings. Compare the resolved
binary's
--versionagainst the pin inpackage.jsonand fail hard onmismatch, naming
script/bootstrapin the message.Apply the identical treatment to
gofumptandgolangci-lintinscript/fmt,script/fmt-check-go, andscript/lint— those arecurrently invoked with no version check at all, which is worse. That
consistency is the reason the prettier fallback was not treated as
blocking on #88.
Correct the
--frozen-lockfileexplanation. The comment inscript/bootstrap(and the #88 commit message) states that--frozen-lockfileenforces the integrity hash. It does not — the flagonly guards lockfile-versus-manifest consistency; integrity verification
happens at fetch time regardless. The behaviour is right, the stated
reason is wrong, and a wrong reason in a comment about supply-chain
pinning will mislead the next person to touch it.
Remove the dead
make fmt-check-mdtarget, or wire it up. It iscurrently unreachable.
Record the Dockerfile lint-stage deviation in
TODO.md. The lintstage runs
make fmt-check-gorather than the canonical policyDockerfile's
make fmt-check, because thegolangci/golangci-lintimage has no node and the markdown check lives in its own
mdfmtstage.That is deliberate and correct, but it is a visible divergence from the
template — without a note, a future policy audit will "correct" it back
and silently drop the markdown gate.
Also cosmetic, fix while you are in there:
package.jsoninvents"version": "0.1.0"for a private manifest that has no version semantics,and
script/fmt-checkprints its "Checking formatting" banner twice.The items still open are fixed in #155: gofumpt is now checked against hashes in the repo, prettier refuses any version but the pinned one, and three comment and
package.jsonfixes. The PR body lists every item as satisfied, moot or fixed.Model: opus-5-5