From 3238eedcf7017293cf25796f0d3c880746ccafd2 Mon Sep 17 00:00:00 2001 From: David Huu Pham Date: Thu, 27 Aug 2026 16:11:01 -0700 Subject: [PATCH] build(nix): fix vendorHash + sandbox tests, automate hash upkeep nix build failed with a vendorHash mismatch (go.sum drifted), and once past that, four cmd/strike eval tests failed because they mkdir under $HOME, which is the unwritable /homeless-shelter in the Nix sandbox. - flake.nix: update vendorHash; set HOME to a tmpdir in preCheck - scripts/update-nix-vendor-hash.sh + `make nix-vendor-hash`: recompute the hash by building only .#default.goModules (the fixed-output module derivation), no compile - .github/workflows/nix-vendor-hash.yml: run on pushes to main touching go.mod/go.sum/go.work*/flake.*, push a fixup commit on drift Files: flake.nix, Makefile, scripts/update-nix-vendor-hash.sh, .github/workflows/nix-vendor-hash.yml Co-Authored-By: Claude Fable 5 --- .github/workflows/nix-vendor-hash.yml | 54 +++++++++++++++++++++++++++ Makefile | 5 +++ flake.nix | 6 ++- scripts/update-nix-vendor-hash.sh | 52 ++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/nix-vendor-hash.yml create mode 100755 scripts/update-nix-vendor-hash.sh diff --git a/.github/workflows/nix-vendor-hash.yml b/.github/workflows/nix-vendor-hash.yml new file mode 100644 index 00000000..5535d43f --- /dev/null +++ b/.github/workflows/nix-vendor-hash.yml @@ -0,0 +1,54 @@ +name: Nix Vendor Hash + +# Keep flake.nix's buildGoModule vendorHash in sync after dependency-bearing +# changes land on main. Only the go-modules fixed-output derivation is built +# (no compile), so this is cheap. Pushes a fixup commit on drift. +on: + push: + branches: [main] + paths: + - "go.mod" + - "go.sum" + - "go.work" + - "go.work.sum" + - "flake.nix" + - "flake.lock" + - "Makefile" + - "scripts/update-nix-vendor-hash.sh" + - ".github/workflows/nix-vendor-hash.yml" + workflow_dispatch: + +concurrency: + group: nix-vendor-hash-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + +jobs: + update: + name: update vendorHash + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@33c9ab3ef95cd57c164d9d6eb1f9a46338538d41 # main + + - name: Update vendorHash + run: make nix-vendor-hash + + - name: Commit updated vendorHash + run: | + set -euo pipefail + if git diff --quiet -- flake.nix; then + echo "vendorHash already current" + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add flake.nix + git commit -m "chore(nix): update vendorHash" + git push origin "HEAD:${GITHUB_REF_NAME}" diff --git a/Makefile b/Makefile index c2fa13e2..9bf51d6c 100644 --- a/Makefile +++ b/Makefile @@ -139,3 +139,8 @@ container-smoke: build clean: rm -f strike $(COVER_PROFILE) rm -rf web/dist web/node_modules + +# Recompute flake.nix vendorHash after go.mod/go.sum changes (CI also does this). +.PHONY: nix-vendor-hash +nix-vendor-hash: + ./scripts/update-nix-vendor-hash.sh diff --git a/flake.nix b/flake.nix index 7de0258f..9d07cda0 100644 --- a/flake.nix +++ b/flake.nix @@ -18,12 +18,16 @@ src = self; proxyVendor = true; - vendorHash = "sha256-ax5mSaryrwb+vSoqm6+Brl6RnA/2WZm+z+eEdxubhtQ="; + vendorHash = "sha256-kEJmV3MQt8k5KuXBjYoUy7+ZZrD3aTljpBziaRndJcU="; subPackages = [ "cmd/strike" ]; preBuild = '' go generate ./internal/frontend/tui/app ''; + # eval tests write under $HOME; the sandbox HOME (/homeless-shelter) is unwritable + preCheck = '' + export HOME="$(mktemp -d)" + ''; ldflags = [ "-s" "-w" diff --git a/scripts/update-nix-vendor-hash.sh b/scripts/update-nix-vendor-hash.sh new file mode 100755 index 00000000..da92aff7 --- /dev/null +++ b/scripts/update-nix-vendor-hash.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Recompute flake.nix's buildGoModule vendorHash after go.mod/go.sum change. +# Only realises the go-modules fixed-output derivation (.#default.goModules), +# never compiles strike, so it's cheap. Prints the old -> new hash on change. +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +flake="${repo_root}/flake.nix" + +current_hash="$( + sed -nE 's/^[[:space:]]*vendorHash = "([^"]+)";[[:space:]]*$/\1/p' "${flake}" | head -n1 +)" + +if [[ -z "${current_hash}" ]]; then + echo "could not find quoted vendorHash in ${flake}" >&2 + exit 1 +fi + +restore_current_hash() { + # NOTE: | delimiter because vendor hashes are base64 and may contain /, + # which would terminate an s/// substitution early. + perl -0pi -e "s|vendorHash = nixpkgs\\.lib\\.fakeHash;|vendorHash = \"${current_hash}\";|" "${flake}" +} + +perl -0pi -e 's/vendorHash = "[^"]+";/vendorHash = nixpkgs.lib.fakeHash;/' "${flake}" +trap restore_current_hash EXIT + +set +e +build_output="$(cd "${repo_root}" && nix build .#default.goModules --no-link 2>&1)" +build_status=$? +set -e + +new_hash="$( + printf '%s\n' "${build_output}" | + sed -nE 's/^[[:space:]]*got:[[:space:]]*(sha256-[A-Za-z0-9+/=]+)[[:space:]]*$/\1/p' | + tail -n1 +)" + +if [[ -z "${new_hash}" ]]; then + printf '%s\n' "${build_output}" >&2 + echo "nix did not report a replacement vendorHash" >&2 + exit "${build_status}" +fi + +trap - EXIT +perl -0pi -e "s|vendorHash = nixpkgs\\.lib\\.fakeHash;|vendorHash = \"${new_hash}\";|" "${flake}" + +if [[ "${new_hash}" == "${current_hash}" ]]; then + echo "vendorHash already current: ${current_hash}" +else + echo "updated vendorHash: ${current_hash} -> ${new_hash}" +fi