From d00afb027b6ab618cab03b44e884bf466449ecae Mon Sep 17 00:00:00 2001 From: Mike Rosseel Date: Wed, 29 Jul 2026 20:48:08 +0200 Subject: [PATCH] ci(nixos): write the manifest from the PR's base, not the default branch The update-manifest job used a bare actions/checkout. Under pull_request_target that lands on the repository's DEFAULT branch, not the PR's base, so the job runs whatever .github/scripts/ the default branch happens to carry. Today that works here by coincidence: both main and release carry the scripts. Two ways it bites anyway. It is silently the wrong tooling. A PR based on main has its manifest entry written by release's copy of update_manifest.py. While the two agree that is invisible; the moment the manifest schema moves on one branch it is a mismatch nobody is looking for. And it is fragile against a branch that carries the workflow but not the scripts -- the workflow file has to be on a branch for pull_request_target to fire there at all, so registering it somewhere new is exactly the thing that sets this off. Downstream we hit precisely that: a successful 19-minute build, then bash: .github/scripts/publish_manifest.sh: No such file or directory The image was built and pushed to Attic; no device could ever see it, because the manifest was never written. A green build and an unreachable artifact is about the worst shape a failure can take. Check out the PR's base branch instead. It is the branch this workflow file itself came from, so its scripts are always beside it, and it stays maintainer-controlled. The PR head is deliberately not an option here: this job holds contents:write and the Attic token. --- .github/workflows/nixos-pr-build.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/nixos-pr-build.yml b/.github/workflows/nixos-pr-build.yml index 19e74b444..9e92335fc 100644 --- a/.github/workflows/nixos-pr-build.yml +++ b/.github/workflows/nixos-pr-build.yml @@ -169,7 +169,18 @@ jobs: group: manifest-write cancel-in-progress: false steps: + # Check out the PR's BASE branch explicitly. A bare checkout under + # pull_request_target lands on the repository's default branch, which + # may carry this workflow (so the event fires) without carrying the + # scripts below -- the job then dies after a successful build, leaving + # an image in Attic that no device can reach because the manifest was + # never written. The base branch is the branch this workflow file itself + # came from, so the scripts are always beside it, and it stays + # maintainer-controlled: never check out the PR head here, which would + # run contributor code with contents:write and the Attic token. - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.ref }} - name: Update generated manifest branch env: