- JavaScript 96.4%
- Nix 3.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
Smoke / smoke (push) Failing after 38s
nix substitutes locked inputs from binary caches before refetching upstream (fetchers.cc: ensurePath on the narHash-derived store path), so pushing nix flake archive paths lets runners pull inputs from attic instead of downloading tarballs from github in every ephemeral job. Opt out with push-flake-inputs: false. |
||
| .forgejo/workflows | ||
| docs/superpowers | ||
| fixtures/test-flake | ||
| lib | ||
| test | ||
| .envrc | ||
| .gitignore | ||
| action.yml | ||
| flake.lock | ||
| flake.nix | ||
| main.js | ||
| package.json | ||
| post.js | ||
| README.md | ||
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. |
push-flake-inputs |
no | Push the flake's source and all locked inputs at job end. Default true; set false to disable. Nix substitutes locked inputs from the cache instead of refetching them upstream, so later jobs skip the GitHub downloads. |
fail-on-push-error |
no | true to fail the job on push failure. Default false — cache is an optimization, main work already succeeded. |
push-jobs |
no | Maximum parallel upload processes for attic push. Default 5 (the attic client default). Lower this to reduce load on the attic server. |
At least one of paths, flake-refs, or push-flake-inputs must be active.
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:andpost:hooks, following the same pattern asactions/cache. One step in your workflow; thepostphase fires automatically after subsequent steps finish. - Zero npm dependencies. Pure Node stdlib +
child_process. Nodist/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. - Substituter config is append-only. The cache is added via
extra-substituters/extra-trusted-public-keysin the user-levelnix.conf(plus a netrc for private caches), which merge with the system config.attic useis deliberately not used: it writes a baresubstitutersline that silently overrides any host- or image-level substituter policy (e.g. an internal pull-through cache). - 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
./resultsymlink that doesn't exist) are skipped with a warning rather than failing the job. Mirrorsactions/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.tomldie 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.