From d4ac94089c9fcf1e8a0be7b47a93c2d5a56cf260 Mon Sep 17 00:00:00 2001 From: mintaka Date: Tue, 25 Aug 2026 17:11:33 -0400 Subject: [PATCH 1/3] feat(renovate): auto-refresh pinned Nix FOD hashes on dep bump (RIG-2727) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A Renovate dependency bump moves a pinned Nix fixed-output-derivation (FOD) hash, but nothing regenerates it — so the bump PR fails CI on `hash mismatch in fixed-output derivation` and can't land without a manual hand-fix. PR #579 (`golang.org/x/net` → v0.56.0 security bump) hit exactly this: its `Gates (moon + pgtest)` job failed building `compass-guestd-go-modules.drv` because the gomod change moved the Go module set but left `guest-image/default.nix`'s pinned `vendorHash` stale. Compass pins exactly two FOD hashes outside the vendored `forks/` trees: - Go `vendorHash` (buildGoModule compass-guestd) in `guest-image/default.nix` — moved by a `go/go.mod` | `go/go.sum` bump (gomod manager). - bun `outputHash` (recursive FOD of `bun install`) in `agent-image/entrypoint.nix` — moved by a `bun.lock` bump (bun/catalog manager). Neither is a URL hash `nix store prefetch-file` can recompute (that is `refresh-toolchain-hashes.ts`'s job for the vendored-binary pins). A `vendorHash`/`outputHash` is only knowable by realising the derivation. `tools/renovate/refresh-fod-hashes.ts` self-gates per FOD on its trigger manifest, fakes the pin to force the mismatch, builds the guest-image rootfs vehicle (which realises both FODs, failing fast at the FOD before the heavy compile/pack), parses the reported `got:` SRI for that derivation, and writes it back — so the bump PR lands green. Wired at two sites to survive Renovate's winner-take-all per-branch task slot: top-level `postUpgradeTasks` (branch mode — gomod and bun/npm-first branches) and the catalog `packageRule` (update mode — catalog-first branches, where the collapsed branch config evicts the top-level branch task). One command string → one anchored `allowedCommands` entry. Guarded by `config.test.ts` (command↔allowlist coupling, both-site wiring, fileFilters coverage) and a `refresh-fod-hashes.test.ts` regression suite. Verified end-to-end against real nix: the shipped script recomputes both hashes to their exact committed values. Spec-impact: none. Refs #579. Refs RIG-2727 Co-authored-by: Matt Wilkinson --- tools/renovate/bot-config.json5 | 15 +- tools/renovate/config.json5 | 89 +++++- tools/renovate/config.test.ts | 85 +++++- tools/renovate/refresh-fod-hashes.test.ts | 343 ++++++++++++++++++++++ tools/renovate/refresh-fod-hashes.ts | 248 ++++++++++++++++ 5 files changed, 753 insertions(+), 27 deletions(-) create mode 100644 tools/renovate/refresh-fod-hashes.test.ts create mode 100755 tools/renovate/refresh-fod-hashes.ts diff --git a/tools/renovate/bot-config.json5 b/tools/renovate/bot-config.json5 index f4ac838f9..13f468653 100644 --- a/tools/renovate/bot-config.json5 +++ b/tools/renovate/bot-config.json5 @@ -56,7 +56,7 @@ // addon, so the workflow sets RENOVATE_X_IGNORE_RE2=true to take the RegExp path // quietly.) // - // Three entries, all load-bearing: + // Four entries, all load-bearing: // 1. the toolchain-hash refresh, which re-prefetches the vendored-binary // sha256 pins a tools/toolchain/versions/*.nix bump invalidates; // 2. the catalog lockfile regeneration. Renovate's custom.regex manager exports @@ -68,11 +68,20 @@ // 3. the devenv-nixpkgs lockstep, which re-locks devenv.lock at a new channel // rev and rewrites the biome catalog pin to the version that rev bakes, // keeping dev-shell baked==catalog parity. - // (1) and (3) are `bun