diff --git a/docs/ci.md b/docs/ci.md index cddcf88b..fb64cdef 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -5,7 +5,7 @@ executing CI jobs from `.forgejo/workflows/ci.yml` on every PR. ## For operators -**Enabling it is one line**: `services.hyperhive.swarm.forge.ci.enable = true` +**Enabling it is one line**: `services.hyperhive.deploy.forgejo.ci.enable = true` in the host NixOS config. No manual token provisioning — hive-c0re registers the runner with the forge automatically. @@ -90,9 +90,9 @@ slow); run those manually before pushing Rust changes. The internal forge is always present (mandatory), so the runner always has a hive-forge instance to register against — nothing extra to enable beyond -`services.hyperhive.swarm.forge.ci.enable = true` (see *For operators* above). +`services.hyperhive.deploy.forgejo.ci.enable = true` (see *For operators* above). -Optional tuning: `services.hyperhive.swarm.forge.ci.name` (runner name in forge +Optional tuning: `services.hyperhive.deploy.forgejo.ci.name` (runner name in forge admin panel), `concurrency` (parallel job capacity), `labels` (workflow targeting), `jobTimeout` (per-job wall-clock cap, default `"1h"`, Go duration string e.g. `"3h"` — a job that exceeds it is killed so a hung or runaway @@ -118,7 +118,7 @@ reaches the container. ### hive-c0re side (`forge/ci_runner.rs`, run during the startup sweep) -Gated on `HYPERHIVE_FORGE_CI_ENABLED` (the nix module sets it on `hive-c0re.service` when `forge.ci.enable`). Best-effort — failures are logged and never abort the sweep; a healthy runner is never restarted. +Gated on `HYPERHIVE_FORGE_CI_ENABLED` (the nix module sets it on `hive-c0re.service` when `deploy.forgejo.ci.enable`). Best-effort — failures are logged and never abort the sweep; a healthy runner is never restarted. 1. If `.runner` exists at `/var/lib/nixos-containers/hive-ci/var/lib/gitea-runner/hive/.runner`, validate its id against `GET /api/v1/admin/runners/{id}` with the core admin token: - **200**: still registered — done, no restart. @@ -135,7 +135,7 @@ Gated on `HYPERHIVE_FORGE_CI_ENABLED` (the nix module sets it on `hive-c0re.serv ## Actions checkout mirror -When `forge.ci.enable` is set, hive-c0re auto-seeds an +When `deploy.forgejo.ci.enable` is set, hive-c0re auto-seeds an `actions/checkout` pull-mirror on the local forge and sets Forgejo's `DEFAULT_ACTIONS_URL` to point at the local instance. This means CI `uses: actions/checkout@vN` steps resolve entirely on loopback — no diff --git a/hive-c0re/src/forge/ci_runner.rs b/hive-c0re/src/forge/ci_runner.rs index f4e04ea4..9c7631cb 100644 --- a/hive-c0re/src/forge/ci_runner.rs +++ b/hive-c0re/src/forge/ci_runner.rs @@ -23,7 +23,7 @@ const RUNNER_FILE: &str = "/var/lib/nixos-containers/hive-ci/var/lib/gitea-runne /// Whether the operator enabled the CI runner. The nix module sets /// `HYPERHIVE_FORGE_CI_ENABLED=1` on `hive-c0re.service` when -/// `services.hyperhive.forge.ci.enable` is on; absent means CI is off and +/// `services.hyperhive.deploy.forgejo.ci.enable` is on; absent means CI is off and /// there is no hive-ci container to register a runner for. fn ci_enabled() -> bool { std::env::var("HYPERHIVE_FORGE_CI_ENABLED") diff --git a/nix/host-modules/deploy.nix b/nix/host-modules/deploy.nix index e4020c0b..e0d56d6c 100644 --- a/nix/host-modules/deploy.nix +++ b/nix/host-modules/deploy.nix @@ -69,8 +69,43 @@ in [ "services" "hyperhive" "swarm" "otel" "enable" ] [ "services" "hyperhive" "deploy" "swarm-otel" "enable" ] ) + + # The CI runner, and the only entry here that renames more than an + # `enable`: every knob under it describes the runner THIS host would run, + # so leaving `name`/`concurrency`/`labels`/`package` in the namespace that + # must be identical swarm-wide would keep the original defect for four + # more options. Renamed one by one because `ci` is a plain attrset of + # options rather than a submodule type, so there is no parent path to + # rename in a single entry. + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "forge" "ci" "enable" ] + [ "services" "hyperhive" "deploy" "forgejo" "ci" "enable" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "forge" "ci" "name" ] + [ "services" "hyperhive" "deploy" "forgejo" "ci" "name" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "forge" "ci" "concurrency" ] + [ "services" "hyperhive" "deploy" "forgejo" "ci" "concurrency" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "forge" "ci" "labels" ] + [ "services" "hyperhive" "deploy" "forgejo" "ci" "labels" ] + ) + (lib.mkRenamedOptionModule + [ "services" "hyperhive" "swarm" "forge" "ci" "package" ] + [ "services" "hyperhive" "deploy" "forgejo" "ci" "package" ] + ) ]; + # ⚠️ `deploy.forgejo` is declared in ./hive-ci.nix, not here, and it is the + # one entry with no `enable`: the forge is not optional — it is the canonical + # store for the meta flake and every agent's config repo, so it deploys with + # hyperhive itself. Running the CI runner is the only *deployment* decision + # it has, which is exactly the `{ enable; ci; }` shape the header describes, + # minus the half that does not apply. The knobs live with the module that + # reads them; this file stays the registry of toggles. options.services.hyperhive.deploy = { grafana.enable = lib.mkOption { type = lib.types.bool; diff --git a/nix/host-modules/hive-ci.nix b/nix/host-modules/hive-ci.nix index d9a51204..3725cbfe 100644 --- a/nix/host-modules/hive-ci.nix +++ b/nix/host-modules/hive-ci.nix @@ -5,7 +5,7 @@ ... }: let - cfg = config.services.hyperhive.swarm.forge.ci; + cfg = config.services.hyperhive.deploy.forgejo.ci; forgeCfg = config.services.hyperhive.swarm.forge; gatewayCfg = config.services.hyperhive.gateway; networkCfg = config.services.hyperhive.network; @@ -76,7 +76,7 @@ in # nspawn containers can't create the user-namespaces that nix sandboxing # requires. See docs/gotchas.md. - options.services.hyperhive.swarm.forge.ci = { + options.services.hyperhive.deploy.forgejo.ci = { enable = lib.mkOption { type = lib.types.bool; default = false; @@ -166,7 +166,7 @@ in { assertion = forgeCfg.behindGateway; message = '' - services.hyperhive.swarm.forge.ci.enable requires + services.hyperhive.deploy.forgejo.ci.enable requires services.hyperhive.swarm.forge.behindGateway = true. The CI container runs with a private network namespace and reaches the forge through the gateway vhost on the bridge IP. diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index 8c0dc724..1978346b 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -88,7 +88,7 @@ let # blip otherwise reds every `actions/checkout@vN` fetch from # data.forgejo.org). Auto-append a pull-mirror of it and point # forgejo's DEFAULT_ACTIONS_URL at this instance so `uses:` resolves local. - ciEnabled = config.services.hyperhive.swarm.forge.ci.enable; + ciEnabled = config.services.hyperhive.deploy.forgejo.ci.enable; actionCheckoutMirror = { upstream = "https://github.com/actions/checkout"; dest = "actions/checkout"; @@ -350,7 +350,7 @@ in so a host-resolver blip leaves a *stale* mirror, never a hard failure on whatever reads it. - When `services.hyperhive.swarm.forge.ci.enable` is set, an + When `services.hyperhive.deploy.forgejo.ci.enable` is set, an `actions/checkout` mirror is auto-appended to this list and forgejo's `DEFAULT_ACTIONS_URL` is pointed at this instance, so CI `uses: actions/checkout@vN` steps resolve entirely on loopback with diff --git a/nix/module-eval.nix b/nix/module-eval.nix index 9f2e6435..b07b80da 100644 --- a/nix/module-eval.nix +++ b/nix/module-eval.nix @@ -69,7 +69,7 @@ let allLocal = hive { enableAllLocalDefaults = true; }; bare = hive { }; - withCi = hive { swarm.forge.ci.enable = true; }; + withCi = hive { deploy.forgejo.ci.enable = true; }; # A priority collision is a property of the *option*, not # of the merged value's interior — nix throws the moment the value is