hyperhive/docs/ci.md
lexis 7f91d52569 docs: add ci.md to CLAUDE.md + clarify runner details
Follow-up to #905: adds CLAUDE.md index entries (file map + reading path)
for the new docs/ci.md. Also clarifies runner details in ci.md:
- curl/jq use absolute nix store paths (no systemPackages needed)
- .runner credential reuse: script writes dummy token on subsequent boots,
  runner ignores it when .runner file exists
2026-06-01 15:52:01 +02:00

56 lines
3 KiB
Markdown

# hive-ci: Forgejo Actions Runner
The `hive-ci` module runs a Forgejo Actions runner in a `hive-ci` nixos-container, executing CI jobs from `.forgejo/workflows/ci.yml` (e.g., `nix flake check` on every PR).
## Operator bootstrap
Set `services.hyperhive.ci.enable = true` in the host NixOS config. That's it — no manual token provisioning.
**Requirements:**
- `services.hyperhive.forge.enable = true` must also be set (the runner registers against hive-forge).
- Optional: tune `services.hyperhive.ci.name` (runner name in forge admin panel), `concurrency` (parallel job capacity), `labels` (workflow targeting).
## Container design
- **Shared host netns**: container reaches hive-forge at `http://127.0.0.1:<httpPort>` (same as hive-gateway).
- **Non-ephemeral**: runner credentials persist across restarts (written to container's stateDir on first registration, reused thereafter).
- **Sandbox fallback**: nspawn containers can't create user-namespaces, so nix's sandboxing would always fail. Module sets `nix.settings.sandbox-fallback = true` in the container — nix builds run unsandboxed (safe because the container is already isolated). See `docs/gotchas.md`.
## Auto-registration flow
1. On first container boot, `systemd` runs the `ExecStartPre` script (from `hive-ci.nix:autoRegisterScript`).
2. Script checks for existing runner credentials (`/var/lib/gitea-runner/hive/.runner`):
- If found: container was previously registered — write dummy token to satisfy module's path check, exit.
- If not found: first boot — proceed to registration.
3. Script reads hive-c0re's admin token from `/run/hive-ci/core-token` (bind-mounted from `/var/lib/hyperhive/forge-core-token`).
4. Calls `POST /api/v1/admin/runners/registration-token` on the forge using `${pkgs.curl}/bin/curl` and `${pkgs.jq}/bin/jq` (absolute nix store paths — the container doesn't need these in systemPackages). Retries for 30s in case forge is still starting.
5. Writes real token to `/run/hive-ci/runner-token`.
6. `gitea-actions-runner` reads the token and registers itself, persisting credentials (`.runner` file) to stateDir.
7. On subsequent boots, runner reuses the `.runner` credentials — the preStart script detects the existing `.runner` file and writes a dummy token instead. The runner ignores the token file when `.runner` already exists.
## CI workflow
The single CI job is defined in `.forgejo/workflows/ci.yml`:
```yaml
name: CI
on:
pull_request:
branches: ["**"]
jobs:
check:
name: nix flake check
runs-on: [hive-ci]
steps:
- uses: actions/checkout@v3
- name: check
run: nix flake check
```
This runs on every PR, executing all flake checks (treefmt, rustfmt, cargo test, cargo clippy, module evaluation). No `--no-build`: the checks' derivations are the canonical source of truth.
## References
- `nix/modules/hive-ci.nix`: runner configuration, auto-registration script, container setup.
- `.forgejo/workflows/ci.yml`: workflow definition.
- `docs/gotchas.md`: nix sandboxing limitations in containers.