fix(#981): validate runner credentials on every boot, purge stale .runner

hive-ci-register.service now runs unconditionally on every boot (not
just when .runner is absent). Before fetching a registration token it
validates existing .runner credentials via the forge admin API:
- 200: runner still registered, write dummy token and exit
- 404: runner deleted from forge, purge .runner and re-register
- 000: forge unreachable, keep credentials (runner surfaces the error)
- other non-200 or malformed .runner: purge and re-register

Removes ConditionPathExists so stale credentials from a wiped forge
no longer block the runner indefinitely. Updates docs/ci.md to match.
This commit is contained in:
atlas 2026-06-02 00:10:15 +02:00 committed by mara
commit 9d816431dc
2 changed files with 72 additions and 32 deletions

View file

@ -18,15 +18,19 @@ Set `services.hyperhive.ci.enable = true` in the host NixOS config. That's it
## 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.
`hive-ci-register.service` is a oneshot that runs on **every boot** before `gitea-runner-hive.service`. It handles both first-run registration and stale-credential detection.
### Every boot
1. Read the core admin token from `/run/hive-ci/core-token` (bind-mounted from `/var/lib/hyperhive/forge-core-token`).
2. If `.runner` exists: validate the runner ID against `GET /api/v1/admin/runners/{id}` using the core token:
- **200**: runner still registered — write dummy `TOKEN=placeholder` and exit; runner reuses `.runner` credentials.
- **404**: runner was deleted from forge (e.g. after a wipe) — delete `.runner`, proceed to re-registration below.
- **000** (forge unreachable): keep existing `.runner`; the runner itself will surface the connectivity error.
- **other non-200**: treat as stale, delete `.runner` and re-register.
- **malformed `.runner`** (no `id` field): delete and re-register.
3. If `.runner` is absent (first boot or purged above): fetch a fresh registration token from `GET /api/v1/admin/runners/registration-token`. Retries for 30s in case forge is still starting. Writes `TOKEN=<real>` to `/run/hive-ci/runner-token`.
4. `gitea-actions-runner` reads the token, registers itself, and persists credentials to `.runner`. On subsequent boots step 2 validates these credentials and fast-paths past registration.
## CI workflow