Fix the Nix flake, and stop the hash check reporting false success - #606
Conversation
v0.8.0 shipped a flake that cannot build at all:
go: go.mod requires go >= 1.26.5 (running go 1.26.4; GOTOOLCHAIN=local)
#533 raised go.mod to 1.26.5 on 2026-07-13, but flake.lock still pinned a
nixpkgs from 2026-06-28 carrying 1.26.4, and release prep never updates the
lock. Every `nix build` user has been broken since, across two releases.
Nothing caught it because every check that could have was blind:
- update-nix-flake.sh ran `nix build ... || true`, then treated the presence of
`building '...basecamp-0.8.0-go-modules.drv'` as proof of success. That string
is printed when the build *starts*, so a hard failure reported "vendorHash:
verified (build succeeded)".
- nix-verify was continue-on-error, so it could not fail a run — and it only
runs on tags, weeks after the drift is introduced.
Update the lock to a nixpkgs with 1.26.5, which then surfaces a second defect
the Go error had been masking: the recorded vendorHash was stale too. Both
fixed; `nix build` now succeeds and the resulting binary reports its version.
Make the release-time check fail closed. It reads the real exit status, and a
failure that is not a hash mismatch is now fatal rather than shrugged off. When
it does update a hash it rebuilds to prove the new one works, which the old code
never did.
Make nix-verify blocking, and add a path-filtered flake build to PR CI so a Go
bump that outpaces the lock fails its own PR instead of surfacing three weeks
later at release time.
Sensitive Change Detection (shadow mode)This PR modifies control-plane files:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2e18571a4e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR fixes the broken Nix flake that shipped in v0.8.0 and closes the two independent gaps that let it ship. When #533 raised go.mod to Go 1.26.5, flake.lock still pinned a nixpkgs carrying 1.26.4, and the recorded vendorHash was also stale, so nix build failed for every user. The release-time hash check masked this by treating the "build starting" log line as success, and the tag-only nix-verify job was continue-on-error and never ran. The fix updates the lock and hash, makes the hash script read the real exit status and rebuild to prove the corrected hash, makes nix-verify blocking, and adds a path-filtered PR job so a Go bump that outpaces the lock fails its own PR.
Changes:
- Update
flake.lockto a nixpkgs revision with Go 1.26.5 and correctnix/package.nix'svendorHash. - Rewrite
scripts/update-nix-flake.shto use the realnix buildexit status (via a trailingNIX_BUILD_EXIT=marker), fail closed on non-hash failures, and rebuild to verify an updated hash. - Harden CI: remove
continue-on-errorfrom releasenix-verify, and add a path-filterednix-buildjob intest.ymlforgo.mod/go.sum/flake.*/nix/**changes.
Tip
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
scripts/update-nix-flake.sh |
Replaces the || true + log-heuristic with a real exit-status check, fail-closed error handling, and a rebuild-to-verify step after updating the hash. |
nix/package.nix |
Updates the stale vendorHash to the value produced by the corrected build. |
flake.lock |
Bumps the pinned nixpkgs revision to one carrying Go 1.26.5. |
.github/workflows/test.yml |
Adds a path-filtered nix-build PR job that builds the flake and runs the binary when flake-relevant files change. |
.github/workflows/release.yml |
Makes nix-verify blocking by removing continue-on-error. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The script now fails closed, but three paths still bypassed that. make update-nix-hash ran the script under `|| true`, converting the new exit 1 straight back into success — the manual entrypoint undid the fix for anyone not going through release.sh. Preserve 0 (updated) and 2 (nothing to do); propagate everything else. The script's Docker-unavailable message pointed at that same target as a workaround, which was circular; it now says to install Docker, because a release must not ship an unverified flake. The Docker build sat entirely inside the deps-changed branch, so a stable release that touched neither go.mod nor go.sum skipped it. That is exactly the shape of the failure it exists to catch: a Go toolchain bump outpacing flake.lock changes neither file. Build unconditionally; the deps comparison now only chooses the wording. Grant pull-requests: read for dorny/paths-filter, matching installer-bash32. The filter did work without it on this repo — public repos can enumerate PR files unauthenticated — but the action documents the permission as required, so relying on that is relying on an accident. Add exit-status regression tests with a stubbed docker. The PR-time flake build proves the current flake compiles; it cannot prove the script distinguishes a passing build from a failing one, which is the defect that actually shipped. The stub reproduces the v0.8.0 log shape exactly: nix announcing it is building basecamp, then dying on the Go version.
|
Pushed P1 — The script's Docker-unavailable message also pointed at that same Make target as a workaround — P2 — validation was conditional. The Docker build sat entirely inside the deps-changed P2 — Regression tests for exit-status classification ( On refreshing
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 70d0260db6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Matching a bare `got:` was far too loose. Any failing build whose log happens to contain one — a Go test assertion printing `got: 42` — had its second field written straight into vendorHash. The rebuild then failed, so nothing shipped, but nix/package.nix was left corrupted and the run reported a hash problem when the real failure was something else entirely. Making the build unconditional widened the exposure: more failures now reach this parse than when it only ran on dependency changes. Require both signals before touching the file — nix must have reported a fixed-output hash mismatch, and the captured value must be SRI-shaped. The new BATS case fails against the old parse and passes against this one, so it pins the behaviour rather than merely describing it.
v0.8.0 shipped a flake that cannot build
#533 raised
go.modto 1.26.5 on 2026-07-13.flake.lockstill pinned anixpkgs from 2026-06-28 carrying 1.26.4, and release prep never updates the
lock. Every
nix builduser has been broken since, across two releases.Why nothing caught it
Both safeguards were blind, independently:
update-nix-flake.shreported success on failure. It rannix build ... || true, then treated the presence ofbuilding '...basecamp-0.8.0-go-modules.drv'as proof of success. Nix prints thatwhen the build starts — so a hard failure printed
vendorHash: verified (build succeeded). It said exactly that during the v0.8.0release, which is how a broken flake got through a pre-tag check that existed to
prevent this.
nix-verifycould not fail the run.continue-on-error: true, and it only runson tags — weeks after the drift is introduced. For v0.8.0 it never ran at all,
because the AUR outage reddened
releaseand skipped everyneeds: [release]job.The fix
Lock + hash. Updating nixpkgs to one carrying 1.26.5 surfaced a second defect the
Go error had been masking — the recorded
vendorHashwas stale as well:Both corrected.
nix buildnow exits 0 and the resulting binary reportsbasecamp version 0.8.0.Fail closed. The release-time check now reads the real exit status. A failure that
is not a hash mismatch is fatal instead of shrugged off, and when it does update a
hash it rebuilds to prove the new one works — which the old code never did.
Catch it at the source.
nix-verifyis no longercontinue-on-error, and apath-filtered
nix-buildjob runs on PRs touchinggo.mod,go.sum,flake.*ornix/**, so a Go bump that outpaces the lock fails its own PR.Verification
Run against the real Docker path, not reasoned about:
vendorHash: verified (build succeeded), exit 0vendorHash: verified (build succeeded), exit 2nix buildon this branchbin/ciexit 0,actionlintclean,zizmorno findings.Consequence for the queue
0.8.1 cannot be a bare manifest bump — it has to carry this first, or it repeats the
broken Nix release. Let
release.shstamp both plugin manifests as part of thatrelease rather than bumping them standalone.
Summary by cubic
Fixes the broken Nix flake by updating
flake.lockto anixpkgswith Go 1.26.5 and correcting the GovendorHash. Makes the hash check accurate and fail-closed so a flake that can’t build can’t ship again.Bug Fixes
flake.lockto a revision with Go 1.26.5.nix/package.nixvendorHash.vendorHashwhennixreports a fixed-output hash mismatch and the captured value is SRI-shaped; then rebuild to verify.CI
nix-verifyblocking (removecontinue-on-error).nix buildexit code, build unconditionally, update the hash only on mismatch, andmake update-nix-hashnow propagates real failures (RC 0=updated, 2=no-op).nix-buildjob in PR CI for changes togo.mod,go.sum,flake.*, andnix/**.Written for commit e508d3d. Summary will update on new commits.