ci: harden flake-check workflow (explicit GH token + permissions pin)#66
Merged
Conversation
7cee318 to
c287976
Compare
dannyfaris
added a commit
that referenced
this pull request
May 28, 2026
… cold runs (#61) Inserts a cache-nix-action@v7 step between cachix/install-nix-action and nix flake check. Per-arch cache key keyed on hashFiles('flake.lock') so lockfile bumps invalidate cleanly; per-arch restore-prefix lets PR branches restore from default-branch entries (the squash-auto-merge flow seeds each new entry). Amortises the non-niri portion of metis's desktop closure across cold CI runs: Quickshell + Qt6 + DMS (dms-shell) + xwayland-satellite + foot + greetd transitive deps. niri itself comes from niri.cachix.org via the extra-substituters trust added in #59 and doesn't need this; matugen is suppressed via DMS's enableDynamicTheming = false (ADR-028 §History 2026-05-29 / PR #63) so it also doesn't enter the closure. Configuration choices (all per #61's spec verbatim): - @v7 — current major tag (released 2026-01-08); inputs unchanged from v6; matches the floating-major-tag convention used by the other steps in this workflow. - primary-key on hashFiles('flake.lock'); restore-prefixes-first-match per-arch so PR branches fall back to the latest default-branch entry. - gc-max-store-size-linux: 5G — two arch entries fit exactly under GH's 10 GB/repo default cap. Follow-up tracked on #61: revisit after the first two runs if entries land smaller. - 7-day last-accessed purge with primary-key pinned. Hardening edits folded into this commit after PR #66's first CI attempt failed with HTTP 404 on api.github.com tarball endpoints (both arches, ~12s each): 1. Explicit `github_access_token: ${{ secrets.GITHUB_TOKEN }}` on the cachix/install-nix-action step. v31's docs claim GITHUB_TOKEN-from-env auto-pickup, but the symptom (HTTP 404 on unauthenticated api.github.com calls — what GitHub returns to anonymous clients past the 60 req/hr limit) suggests the auto-pickup didn't apply in our environment. The empty-restore on cache-nix-action's first run exposed this: every flake input had to fetch from GitHub. Setting the token explicitly makes the auth deterministic. 2. Top-level `permissions: contents: read` block. Defense-in-depth scope-pin on the workflow's token. The workflow only needs to read repo contents (checkout clones; Nix fetches public flake inputs); explicit-over-implicit per CLAUDE.md's whitelist > blanket stance applied to the token surface. No interaction with the `github_access_token` input — different layer. Why cache-nix-action and not Cachix-hosted / FlakeHub / Attic: one-operator project; matched-to-scale tooling; no extra trust delegations beyond GitHub itself. Triggers to revisit (hit rate <60%, second source-built dep, routine aarch64 source builds) are documented in #61's body. Peer-reviewed twice — once for the original cache-nix-action step (12 checkpoints; clean), once for the hardening amend (8 checkpoints; clean with two non-blocking nits surfaced + agreed with operator: comment phrasing left as-is, permissions block folded into this amend). Closes #61.
Two small defense-in-depth additions to .github/workflows/ci.yaml. Both originally landed as part of PR #66 (cache-nix-action adoption per #61); the cache step is removed as a diagnostic revert after that step's presence reproducibly broke api.github.com tarball fetches across two CI runs even with the explicit GITHUB_TOKEN passed. Changes kept in this commit: 1. `github_access_token: ${{ secrets.GITHUB_TOKEN }}` on cachix/install-nix-action@v31. v31's docs say GITHUB_TOKEN is auto-picked-up from the env when this input is empty; setting it explicitly makes the auth deterministic and surfaces the token wiring in the action's logs. 2. Top-level `permissions: contents: read` block. Defense-in-depth scope-pin on the workflow's auto-provisioned token. The workflow only reads repo contents (checkout clones; Nix fetches public flake inputs). Explicit-over-implicit per CLAUDE.md's whitelist > blanket stance. Removed from PR #66's original scope: - `nix-community/cache-nix-action@v7` step. The hypothesis: somehow its presence (or its `purge: true` mechanism) broke nix's GitHub tarball fetches. Two CI runs failed identically with HTTP 404 on api.github.com tarball URLs for different transitive flake inputs (treefmt-nix, hercules-ci/flake-parts, nix-community/nixpkgs.lib — all confirmed existing upstream). The token-passing amend did not fix it. Reverting the cache step isolates whether its presence is the cause: CI on this amend will tell us. If CI on this amend passes: cache-nix-action confirmed as cause; #61 stays open for a different action or later v8 attempt; a breadcrumb comment will land on #61 recording what was tried. If CI still fails: deeper issue beyond cache-nix-action; investigate. Peer-reviewed.
c287976 to
d8a1c22
Compare
This was referenced May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two small defense-in-depth additions to
.github/workflows/ci.yaml:Explicit
github_access_token: ${{ secrets.GITHUB_TOKEN }}oncachix/install-nix-action@v31. v31's docs sayGITHUB_TOKENis auto-picked-up from the env when this input is empty; setting it explicitly makes the auth deterministic and surfaces the token wiring in the action's logs.Top-level
permissions: contents: readblock. Defense-in-depth scope-pin on the workflow's auto-provisioned token. The workflow only reads repo contents (checkout clones; Nix fetches public flake inputs). Explicit-over-implicit per CLAUDE.md's whitelist > blanket stance.Scope shift from #66's original goal
This PR was originally scoped to implement #61 (adding
nix-community/cache-nix-action). After two CI runs failed identically — HTTP 404 onapi.github.com/.../tarball/URLs for different transitive flake inputs (treefmt-nix,hercules-ci/flake-parts,nix-community/nixpkgs.lib— all confirmed existing upstream) — and the token-passing amend did not fix it, the cache step is removed as a diagnostic revert.The two hardening edits above survive the revert because they're independently useful:
permissions: contents: readblock scope-pins the token to the minimum surface (defense-in-depth).#61 stays open. This PR does not close it.
Diagnostic outcome to watch on this PR's CI
nix-community/cache-nix-action@v7is confirmed as the cause of the api.github.com 404s. A breadcrumb comment will land on ci: add nix-community/cache-nix-action for store-path caching across cold runs #61 recording what was tried so future revisits have context.Peer review
Reviewed against 8 checkpoints: cache step fully removed, token+permissions preserved, YAML structure intact, comment updated honestly, actionlint compliance, no accidental edits, comment-language quality, hooks. Clean.
Test plan
actionlint(pre-commit hook) passes.Note for reviewers
PR title and body were edited mid-flight to reflect the scope shift. The original #66 PR was titled "ci: add nix-community/cache-nix-action ...". Git history on this branch reflects the iterations.
🤖 Generated with Claude Code