No description
  • JavaScript 93.8%
  • Nix 6.2%
Find a file
Matt 38b4063759
All checks were successful
Smoke / smoke (push) Successful in 28s
fix: use attic use for authenticated substituter config
attic use writes both substituter + netrc with token, giving Nix
authenticated pull access. Replaces our manual nix.conf writing
which lacked auth and caused HTTP 401 on private cache pulls.

Drops the public-key input — attic fetches it from the server.
Drops lib/nixconf.js and NIX_USER_CONF_FILES plumbing.
2026-04-17 20:01:07 -04:00
.forgejo/workflows fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00
docs/superpowers docs: add implementation plan for setup-attic Forgejo Action 2026-04-17 19:05:56 -04:00
fixtures/test-flake test: add smoke fixture flake with time-stamped derivation 2026-04-17 19:25:20 -04:00
lib fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00
test fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00
.envrc chore: bootstrap repo with flake scaffold and action design spec 2026-04-17 19:02:25 -04:00
.gitignore chore: scaffold Node action repo (package.json, node in devShell) 2026-04-17 19:14:25 -04:00
action.yml fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00
flake.lock chore: bootstrap repo with flake scaffold and action design spec 2026-04-17 19:02:25 -04:00
flake.nix chore: scaffold Node action repo (package.json, node in devShell) 2026-04-17 19:14:25 -04:00
main.js fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00
package.json chore: scaffold Node action repo (package.json, node in devShell) 2026-04-17 19:14:25 -04:00
post.js fix(entry): honor fail-on-push-error for resolve errors, fail fast on missing GITHUB_ENV 2026-04-17 19:32:16 -04:00
README.md fix: use attic use for authenticated substituter config 2026-04-17 20:01:07 -04:00

setup-attic

A Forgejo Action that configures a CI job to pull from and push to a self-hosted attic Nix binary cache. One step in your workflow; both phases handled automatically via Forgejo's main/post action hooks.

Usage

- uses: actions/checkout@v6

- uses: matt/setup-attic@v1
  with:
    endpoint: https://cache.example.com
    cache: my-cache
    token: ${{ secrets.ATTIC_TOKEN }}
    flake-refs: .#my-package

- run: nix build .#my-package --no-link

The main phase installs the attic client, wires the cache up as a Nix substituter (so your builds pull from it), and authenticates. The post phase resolves paths:/flake-refs: to realised store paths and pushes them — skipping anything that wasn't actually built, with no error.

Inputs

Name Required Description
endpoint yes Attic server base URL, e.g. https://cache.example.com.
cache yes Cache name on the server, e.g. my-cache.
token yes Attic JWT, scoped to at least push on the target cache. Always source from a secret.
paths no Newline-separated list of store paths or symlinks (like ./result) to push.
flake-refs no Newline-separated list of flake references (like .#my-package) to resolve and push at job end.
fail-on-push-error no true to fail the job on push failure. Default false — cache is an optimization, main work already succeeded.

At least one of paths or flake-refs must be non-empty.

Multiple entries, newline-separated:

with:
  flake-refs: |
    .#foo
    .#bar
    .#baz

Obtaining a token

On the attic server:

attic make-token --sub ci --validity 90d --push my-cache

Copy the output into your repo's secrets as ATTIC_TOKEN (or whatever name you reference in the workflow). Refer to attic's docs for finer-grained token options.

How it works

  • Node action with main: and post: hooks, following the same pattern as actions/cache. One step in your workflow; the post phase fires automatically after subsequent steps finish.
  • Zero npm dependencies. Pure Node stdlib + child_process. No dist/ bundle.
  • Attic client is realised on-demand via nix run nixpkgs#attic-client. First invocation pays the build cost; subsequent runs on the same host are a cache lookup.
  • Server name in the attic config is deterministically derived from <endpoint-hostname-slug>-<cache>, so you can use this action multiple times in one job pointing at different caches (or different servers) without collisions.
  • Missing paths (a declared flake-ref that wasn't built, a ./result symlink that doesn't exist) are skipped with a warning rather than failing the job. Mirrors actions/cache's behavior.

Security

  • Token is a secret. Always source token: from ${{ secrets.* }}. Never hardcode.
  • No cross-job leakage. Forgejo's runner creates a fresh container per job (ReuseContainers: false). Credentials written to ~/.config/attic/config.toml die with the container.
  • Within-job exposure. Other actions running in the same job can read the attic credentials file while the job is in progress. If you compose this action with untrusted third-party actions in the same workflow, be aware.

License

MIT.