Skip to content

ci: harden flake-check workflow (explicit GH token + permissions pin)#66

Merged
dannyfaris merged 1 commit into
mainfrom
ci/cache-nix-action
May 28, 2026
Merged

ci: harden flake-check workflow (explicit GH token + permissions pin)#66
dannyfaris merged 1 commit into
mainfrom
ci/cache-nix-action

Conversation

@dannyfaris

@dannyfaris dannyfaris commented May 28, 2026

Copy link
Copy Markdown
Owner

Summary

Two small defense-in-depth additions to .github/workflows/ci.yaml:

  1. Explicit 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.

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 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) — 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:

  • The token explicit-set documents and surfaces what install-nix-action would otherwise do implicitly.
  • The permissions: contents: read block 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

  • If CI passes: nix-community/cache-nix-action@v7 is 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.
  • If CI still fails: the issue is independent of cache-nix-action; deeper investigation needed (GitHub API regression on Actions runners? Some interaction with our flake inputs? Etc.)

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.
  • YAML structure verified.
  • CI matrix green on both arches.

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

@dannyfaris dannyfaris enabled auto-merge (squash) May 28, 2026 13:10
@dannyfaris dannyfaris force-pushed the ci/cache-nix-action branch from 7cee318 to c287976 Compare May 28, 2026 13:18
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.
@dannyfaris dannyfaris force-pushed the ci/cache-nix-action branch from c287976 to d8a1c22 Compare May 28, 2026 13:24
@dannyfaris dannyfaris changed the title ci: add nix-community/cache-nix-action to amortise store paths across cold runs (#61) ci: harden flake-check workflow (explicit GH token + permissions pin) May 28, 2026
@dannyfaris dannyfaris merged commit f380bf9 into main May 28, 2026
4 checks passed
@dannyfaris dannyfaris deleted the ci/cache-nix-action branch May 28, 2026 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant