feat(ci): add reusable nix-hash-autofix workflow#153
feat(ci): add reusable nix-hash-autofix workflow#153JacobPEvans wants to merge 1 commit intomainfrom
Conversation
Renovate's regex manager bumps version strings in .nix files but cannot update fetchFromGitHub hashes or vendorHash. This workflow runs nix-update with --version=skip on Renovate PRs to fix hashes and pushes a fixup commit. Callers pass a list of package attribute names to update. Only runs on Renovate bot PRs (jacobpevans-github-actions[bot]). (claude)
|
Note Gemini is unable to generate a summary for this pull request due to the file types involved not being currently supported. |
There was a problem hiding this comment.
Pull request overview
Adds a new reusable GitHub Actions workflow to automatically recalculate and commit updated Nix fetch/vendor hashes after Renovate bumps versions in .nix files, reducing CI breakages from stale hashes.
Changes:
- Introduces reusable workflow
_nix-hash-autofix.ymlcallable viaworkflow_call - Installs Nix and runs
nix-update --version=skipfor specified flake package attributes - Commits and pushes a fixup commit when hash-related diffs are produced
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| on: | ||
| workflow_call: | ||
| inputs: | ||
| packages: | ||
| description: "Space-separated list of flake package attributes to update (e.g., 'gh-aw git-flow-next')" | ||
| required: true | ||
| type: string | ||
|
|
||
| permissions: {} | ||
|
|
||
| concurrency: | ||
| group: nix-hash-autofix-${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| autofix: | ||
| name: Fix Nix Hashes | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: read | ||
| steps: | ||
| - name: Generate GitHub App Token | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v3 | ||
| with: | ||
| app-id: ${{ secrets.GH_ACTION_JACOBPEVANS_APP_ID }} | ||
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | ||
|
|
||
| - name: Checkout PR branch | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ github.head_ref }} | ||
| token: ${{ steps.app-token.outputs.token }} | ||
|
|
There was a problem hiding this comment.
This workflow checks out and runs commands against the PR branch using inherited secrets, but it does not enforce that it’s running in a safe context (e.g., a same-repo pull_request from the expected bot). If a caller accidentally invokes this via pull_request_target or for a fork PR, this would run untrusted code with write-capable credentials. Add an explicit guard (job-level if: or an early step that fails) to require github.event_name == 'pull_request', github.event.pull_request.head.repo.full_name == github.repository, and (optionally) the expected PR author/actor before generating the app token/checkout.
| # Usage in ci-gate.yml: | ||
| # nix-hash-autofix: | ||
| # needs: changes | ||
| # if: needs.changes.outputs.nix == 'true' && github.event.pull_request.user.login == 'jacobpevans-github-actions[bot]' | ||
| # uses: JacobPEvans/.github/.github/workflows/_nix-hash-autofix.yml@main | ||
| # with: | ||
| # packages: "gh-aw" | ||
| # secrets: inherit |
There was a problem hiding this comment.
The header "Usage" example indicates secrets: inherit, but the workflow implicitly requires GH_ACTION_JACOBPEVANS_APP_ID and GH_APP_PRIVATE_KEY to exist in the caller repo/org. Please document these required secrets (and what permissions the app needs) in the header, or expose them as explicit workflow_call.secrets entries so callers get a clearer validation/error message.
| uses: actions/create-github-app-token@v3 | ||
| with: | ||
| app-id: ${{ secrets.GH_ACTION_JACOBPEVANS_APP_ID }} | ||
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} |
There was a problem hiding this comment.
actions/create-github-app-token is invoked without scoping token permissions. In this repo, _release-please.yml uses permission-contents, permission-pull-requests, etc. to least-privilege the generated token; consider doing the same here (contents: write, pull-requests: read) to reduce blast radius if the token is misused/exposed.
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | |
| private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} | |
| permission-contents: write | |
| permission-pull-requests: read |
| for pkg in $PACKAGES; do | ||
| echo "::group::Updating $pkg" | ||
| # nix-update recalculates src hash and vendorHash | ||
| # --version=skip keeps Renovate's version bump, only fixes hashes | ||
| if nix run nixpkgs#nix-update -- --flake "$pkg" --version=skip 2>&1; then | ||
| echo "Updated $pkg" | ||
| else | ||
| echo "::warning::Failed to update $pkg (may already be correct)" | ||
| fi | ||
| echo "::endgroup::" | ||
| done | ||
| if [ -n "$(git diff --name-only)" ]; then | ||
| echo "changed=true" >> "$GITHUB_OUTPUT" | ||
| fi |
There was a problem hiding this comment.
The update loop converts any nix-update failure into a warning and still exits 0. If nix-update fails due to a real error (evaluation failure, network, etc.), the workflow will report success but won’t fix the hashes, leaving CI broken. Track failures and fail the job when one or more requested packages could not be updated (or at least fail when all updates fail and no diff is produced).
|
Closing — switching to simpler approach: daily nix-update + remove Renovate annotations for fetchFromGitHub packages. No new workflow needed. |
Summary
New reusable workflow
_nix-hash-autofix.ymlthat automatically fixes Nix packagehashes on Renovate PRs.
Problem
Renovate's regex custom manager can bump version strings in
.nixfiles (via# renovate:annotations) but cannot updatefetchFromGitHubhashes orvendorHash.This causes every Renovate version bump for Go/Rust packages to break CI.
Example: gh-aw v0.65.4 hash mismatch broke nix-darwin CI (PR #955) when GitHub
regenerated the tarball.
Solution
A reusable workflow that:
nix-update --version=skipfor specified packages (keeps Renovate's version, fixes hashes)Test plan
🤖 Generated with Claude Code