diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 0000000..dba71e9 --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1 @@ +@../AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..cbb1d7d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. + +## Overview + +Smallstep's Nix User Repository (NUR): Nix packaging for `step-agent` plus the `services.step-agent` NixOS module. It is consumed as a flake (`github:smallstep/nur`), as a classic NUR package set (`import ./default.nix { inherit pkgs; }`), or as a nixpkgs overlay (`overlay.nix`). There is no source code to compile here: every package fetches a prebuilt Linux tarball (`x86_64-linux` and `aarch64-linux` only) and runs it through `autoPatchelfHook`. The only flake input is `nixpkgs` (`nixpkgs-unstable`). This is a public, MIT-licensed repository. + +## Commands + +Nix with `nix-command` and `flakes` enabled is required. Packages only build on Linux; on macOS you can evaluate but not build. + +```bash +nix flake show # list outputs: packages, legacyPackages, nixosModules +nix flake check # evaluate every output against flake.lock +nix build .#step-agent # newest stable release +nix build .#step-agent_0_70_0-rc2 # a specific release; prereleases only by explicit attribute +nix-build -A step-agent # classic path, uses from NIX_PATH, not flake.lock +nix flake update # bump flake.lock (manual, see "CI" below) +``` + +What CI actually runs (`.github/workflows/build.yml`), reproducible locally with `` on `NIX_PATH`: + +```bash +# evaluation check +nix-env -f . -qa \* --meta --xml --drv-path --show-trace \ + --option restrict-eval true --option allow-import-from-derivation true \ + -I "nixpkgs=$(nix-instantiate --find-file nixpkgs)" -I "$PWD" +# build every cacheable derivation +nix shell -f '' nix-build-uncached -c nix-build-uncached ci.nix -A cacheOutputs +``` + +There is no Makefile, test suite, linter, or formatter. Build products land in gitignored `result` / `result-*` symlinks. + +## Generated code — do not edit + +| Pattern | Generator | +|---------|-----------| +| `pkgs/step-agent/step-agent_.nix` | GoReleaser, in the agent's release pipeline (each file is headed `This file was generated by GoReleaser. DO NOT EDIT.`) | +| `nixos-modules/step-agent.nix` | Mirrored on merge from the upstream agent repository (`extra/step-agent.nix`, linked from README.md); send changes there | + +The `step-ci` bot commits both directly to `main`, not through pull requests. Hand edits are overwritten by the next release or mirror. + +## Architecture + +``` +nur/ +├── flake.nix # packages + legacyPackages per system; nixosModules (not per system) +├── flake.lock # pins nixpkgs for flake users; NOT exercised by CI +├── default.nix # NUR entry point: derives the package set from pkgs/ at eval time +├── ci.nix # filters default.nix into buildPkgs / cachePkgs / cacheOutputs +├── overlay.nix # nixpkgs overlay exposing the same attributes +├── lib/, overlays/ # NUR-template placeholders, empty +├── nixos-modules/ +│ ├── default.nix # { step-agent = ./step-agent.nix; } +│ └── step-agent.nix # services.step-agent: user, systemd units, PKCS#11 socket, polkit +└── pkgs/step-agent/ # one derivation per release, ~70 files, oldest 0.65.0-rc11 +``` + +### How the package list is generated + +There is no checked-in package list. `default.nix` calls `builtins.readDir` on `pkgs//` at evaluation time and registers every `_.nix` as attribute `_` with `.` replaced by `_` (`step-agent_0.69.2.nix` becomes `step-agent_0_69_2`; a `-rc1` suffix is kept verbatim). The bare `` attribute is the newest version matching `[0-9]+\.[0-9]+\.[0-9]+`, compared with `builtins.compareVersions`, so a prerelease is never the default. `flake.nix` exposes the whole set as `legacyPackages` and the derivations alone as `packages`. Adding a second package family is one more `packageSet ""` line at the bottom of `default.nix`. + +### How a new version lands + +1. The agent's release pipeline runs GoReleaser, which renders `pkgs/step-agent/step-agent_.nix` (download URL and sha256 per platform) and pushes it straight to `main` as `step-ci`, message `step-agent: vOLD -> vNEW`. +2. That push triggers `build.yml`, which evaluates and builds every cacheable derivation on three nixpkgs channels (`nixpkgs-unstable`, `nixos-unstable`, `nixos-25.11`) with `nix-build-uncached`. +3. Nothing else changes: no list to update, no lock to bump. Old versions are never removed automatically. + +Because `ci.nix` builds everything under `pkgs/`, one release whose tarball has gone missing breaks CI for the whole repo; deleting that file is the fix. Derivations are not uniform across time (older files use `pname = "step-agent-plugin"` and GitHub release URLs; newer ones use `pname = "step-agent"` and `packages.smallstep.com`), because each reflects the GoReleaser config of its day. + +### NixOS module + +`nixosModules.step-agent` exposes `services.step-agent.{enable,package,settings}`. `package` defaults to `pkgs.step-agent` from the host's nixpkgs channel, not this repository's build; README.md shows how to point it here. `settings` is rendered to `/etc/step-agent/agent.yaml` when set, otherwise `step-agent register` writes that file. The module is deliberately a single self-contained file: it is also published standalone at `https://files.smallstep.com/step-agent.nix`, and its option surface tracks the module proposed for nixpkgs in NixOS/nixpkgs#555971. It requires a hardware TPM 2.0. + +## CI and workflows + +| Workflow | Trigger | What it does | +|----------|---------|--------------| +| `build.yml` | PR, push to `main`, manual | eval check + `nix-build-uncached ci.nix -A cacheOutputs` on 3 nixpkgs channels | +| `actionci.yml` | PR (its push trigger names `master`, which does not exist) | actionlint + zizmor via `smallstep/workflows`; policy in `.github/zizmor.yml` | +| `dependabot-auto-merge.yml` | PR | auto-merges Dependabot; only the `github-actions` ecosystem is configured, weekly, 7-day cooldown | +| `test-commit-push.yml`, `test-pat-push.yml` | manual only | smoke tests for the bot's SSH signing key and push token; not part of CI | + +`build.yml` selects nixpkgs through `NIX_PATH` and `nix-env -f .`, so `flake.lock` is never evaluated in CI. `nix flake check` and `nix build` locally do use it, which means a stale lock can break flake consumers while CI stays green. Update it by hand with `nix flake update` in its own PR. + +## Conventions + +- Version bumps and module mirrors are bot commits to `main`. Human PRs are for `default.nix`, `flake.nix`, `ci.nix`, CI workflows, and README.md. +- Third-party actions are SHA-pinned; `smallstep/*` reusable workflows may use `@main` (zizmor `unpinned-uses` policy). +- Every package is `stdenvNoCC.mkDerivation` + `autoPatchelfHook`, with `meta.sourceProvenance = binaryNativeCode` and `meta.platforms` limited to the two Linux targets; the binary is wrapped with `tpm2-tss`, `tpm2-openssl`, `desktop-file-utils`, `polkit`, and `p11-kit` on `PATH`. +- `flake.nix` sets no `nixConfig` and no binary cache; consumers build from source or hit their own cache.