From a31cfca32f3a4b9ec205c5d8a1991f8e07c8cbb5 Mon Sep 17 00:00:00 2001 From: Michele Mancioppi Date: Thu, 2 Jul 2026 06:50:25 +0200 Subject: [PATCH] chore(nix): heal vendorHash on merge instead of on PR branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A dependency bump changes go.mod/go.sum, which makes the buildGoModule vendorHash in nix/package.nix go stale and the Nix build fail. The old `Nix vendorHash` workflow recomputed and pushed the fix from the PR branch, which required a write-scoped PAT in a job that runs untrusted branch code — a poisoned dependency could exfiltrate that token. It was also broken for Dependabot (the PAT is not exposed to Dependabot runs, so checkout failed with "Input required and not supplied: token"). Retire that workflow. Instead: - skip the `nix` build on Dependabot PRs (github.actor guard) so a bump merges without a red check; - add an `update-vendor-hash` job to the Nix workflow that recomputes and commits the fix on push to main, where the code is trusted and the PAT is safe to use. Cost: main's nix build is briefly red between the merge and the fix commit. Releases are cut manually (workflow_dispatch -> tag), so that window cannot silently ship a broken package. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/nix-vendor-hash.yml | 57 --------------------------- .github/workflows/nix.yml | 56 ++++++++++++++++++++++++++ CONTRIBUTING.md | 3 +- nix/update-vendor-hash.sh | 5 ++- 4 files changed, 61 insertions(+), 60 deletions(-) delete mode 100644 .github/workflows/nix-vendor-hash.yml diff --git a/.github/workflows/nix-vendor-hash.yml b/.github/workflows/nix-vendor-hash.yml deleted file mode 100644 index 361edaf..0000000 --- a/.github/workflows/nix-vendor-hash.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Nix vendorHash - -# Keep dependency-bump PRs green automatically: when go.mod / go.sum change, the -# buildGoModule vendorHash in nix/package.nix goes stale and the Nix build -# fails. This recomputes it and commits the fix back to the PR branch, so -# Dependabot (and human) dependency PRs fix their own vendorHash. -# -# Pushing back requires a token with write access. We reuse -# REPOSITORY_FULL_ACCESS_GITHUB_TOKEN (already used by release.yml); using a PAT -# rather than the default GITHUB_TOKEN also makes the follow-up commit -# re-trigger the Nix build workflow. -# -# For this to work on Dependabot PRs, that token must ALSO be registered as a -# Dependabot secret (Settings -> Secrets and variables -> Dependabot), because -# GitHub withholds Actions secrets from Dependabot-triggered pull_request runs. -on: - pull_request: - paths: - - "go.mod" - - "go.sum" - - "nix/package.nix" - - ".github/workflows/nix-vendor-hash.yml" - workflow_dispatch: - -permissions: - contents: read - -jobs: - update-vendor-hash: - # Only same-repo branches (Dependabot branches live in this repo); we can't - # push to a fork's branch. - if: github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest - steps: - - name: Checkout PR branch - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - ref: ${{ github.event.pull_request.head.ref }} - token: ${{ secrets.REPOSITORY_FULL_ACCESS_GITHUB_TOKEN }} - - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 - - - name: Recompute vendorHash - run: ./nix/update-vendor-hash.sh - - - name: Commit and push if changed - run: | - if git diff --quiet -- nix/package.nix; then - echo "vendorHash already correct; nothing to do." - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add nix/package.nix - git commit -m "chore(nix): update vendorHash for dependency change" - git push origin "HEAD:${{ github.event.pull_request.head.ref }}" diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index cd0439f..0e48b6e 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -2,6 +2,19 @@ name: Nix # Keeps the Nix packaging green: builds the flake package and runs the flake # checks (the Home Manager module's assertion and seed-merge unit tests). +# +# vendorHash upkeep: a dependency bump changes go.mod / go.sum, which makes the +# buildGoModule vendorHash in nix/package.nix go stale and the build fail. We do +# NOT auto-fix that on the PR branch: doing so would require a write-scoped PAT +# in a job that runs untrusted branch code (a poisoned dependency could then +# exfiltrate the token). Instead: +# - the `nix` build is skipped on Dependabot PRs (github.actor guard), so the +# bump can merge without a red check; and +# - the `update-vendor-hash` job recomputes and commits the fix on push to +# main, where the code is trusted and the PAT is safe to use. +# Cost: main's nix build is briefly red between the merge and the fix commit. +# Releases are cut manually (workflow_dispatch -> tag), so that window can't +# silently ship a broken package. on: push: branches: @@ -25,8 +38,16 @@ on: - ".github/workflows/nix.yml" workflow_dispatch: +permissions: + contents: read + jobs: nix: + # Skip on Dependabot PRs: the vendorHash is stale until the bump merges and + # `update-vendor-hash` heals it on main. A job-level skip reports a `skipped` + # conclusion, which branch protection treats as passing. Human dependency + # changes still get the full build. + if: github.actor != 'dependabot[bot]' runs-on: ubuntu-latest steps: - name: Checkout repository @@ -40,3 +61,38 @@ jobs: - name: Run flake checks run: nix flake check --print-build-logs + + update-vendor-hash: + # On merge to main, self-heal a stale vendorHash left by a dependency bump + # (Dependabot PRs skip the build above, so the fix lands here). This runs on + # trusted main code, so holding a write-scoped PAT is safe. + # + # We reuse REPOSITORY_FULL_ACCESS_GITHUB_TOKEN (also used by the release + # workflows); using a PAT rather than the default GITHUB_TOKEN also lets the + # follow-up commit re-trigger this workflow, which then finds the hash + # correct and no-ops. + if: github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + token: ${{ secrets.REPOSITORY_FULL_ACCESS_GITHUB_TOKEN }} + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 + + - name: Recompute vendorHash + run: ./nix/update-vendor-hash.sh + + - name: Commit and push if changed + run: | + if git diff --quiet -- nix/package.nix; then + echo "vendorHash already correct; nothing to do." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add nix/package.nix + git commit -m "chore(nix): update vendorHash for dependency change" + git push origin "HEAD:main" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc28148..f97644b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,8 @@ When `go.mod`/`go.sum` change, refresh it: make update-vendor-hash ``` -On pull requests this is automated: the [`Nix vendorHash`](.github/workflows/nix-vendor-hash.yml) workflow recomputes the hash and commits the fix back to the branch, so Dependabot and other dependency PRs heal themselves. +On `main` this is automated: the `update-vendor-hash` job in the [`Nix`](.github/workflows/nix.yml) workflow recomputes the hash and commits the fix after a dependency bump merges. +The Nix build is skipped on Dependabot PRs (the hash is stale until the bump lands), so those PRs merge without a red check and `main` self-heals right after; human dependency PRs should refresh the hash locally with `make update-vendor-hash` before pushing. Note that CI builds the PR's *merge commit*, so a dependency bump landing on `main` can make an unrelated open PR's Nix build go red until its branch is updated. ### Binary distribution (NUR) diff --git a/nix/update-vendor-hash.sh b/nix/update-vendor-hash.sh index 7187fc6..e8c37a3 100755 --- a/nix/update-vendor-hash.sh +++ b/nix/update-vendor-hash.sh @@ -5,8 +5,9 @@ # correct the file is left unchanged. # # Run from the repository root (or via `make update-vendor-hash`). Requires Nix -# with flakes enabled. Used by .github/workflows/nix-vendor-hash.yml to keep -# dependency-bump PRs (Dependabot or human) green automatically. +# with flakes enabled. Used by the `update-vendor-hash` job in +# .github/workflows/nix.yml to self-heal a stale vendorHash on push to main +# after a dependency bump merges. set -euo pipefail pkg="nix/package.nix"