From 55145ff8e888996703394b8935d3940caa243422 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 2 Sep 2026 05:31:40 +0200 Subject: [PATCH] hive-ci: keep the two load-bearing properties, drop the retelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module header restated `docs/scheduler/ci.md`'s credential-isolation paragraph nearly word for word, and re-told the nix-sandbox gotcha that `docs/process/gotchas.md` owns — both immediately above lines that already pointed at those docs. Measured, not eyeballed: 6-gram intersection between this file's comments and `docs/scheduler/ci.md`, 74 -> 24. Kept, because neither is visible from the config that implements it and a reader changing this file needs both: * the container has its own network namespace, not the host's, so a PR's nix build cannot reach host-loopback services — a prompt-injection boundary rather than a preference; * the forge ADMIN token never enters this container; only a registration token is handed in. Each is now one sentence naming the property and its consequence, with the mechanism behind a `docs/x.md::Section` pointer whose heading was checked to exist (`Container isolation`, `Container design`). Also restated in the present: the container is non-ephemeral because the runner writes its registered credentials on first registration and reuses them, which is why an ephemeral one would re-register every restart. That was previously a description of what gitea-actions-runner does, with the reason left implicit. Comments only; no behaviour change. Refs #3901. --- nix/host-modules/hive-ci.nix | 40 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/nix/host-modules/hive-ci.nix b/nix/host-modules/hive-ci.nix index 9907cbdc..adede597 100644 --- a/nix/host-modules/hive-ci.nix +++ b/nix/host-modules/hive-ci.nix @@ -51,30 +51,26 @@ let in { # Forgejo Actions runner in a `hive-ci` nixos-container. - # Uses a private network namespace (bridge-connected, not host netns) - # so CI build scripts cannot reach host-loopback services (dashboard, - # forge internal port, etc.) — a key defence against prompt-injection - # via PR nix builds. The runner reaches the forge via the - # gateway at `http://${forgeCfg.domain}` (resolved to the bridge IP - # via `networking.extraHosts`; gateway port 80 is always open on the - # bridge; `addSSL = true` means HTTP is served alongside HTTPS without - # a redirect). See docs/networking/network.md. - # Container is non-ephemeral: the runner's registered credentials - # survive restarts (gitea-actions-runner writes them to its stateDir - # on first registration and reuses them on every subsequent start). # - # Credential isolation: the forge admin token (`forge-core-token`) - # never enters the hive-ci container. hive-c0re holds it and performs - # all forge API calls (runner validation + registration-token mint, - # in `forge/ci_runner.rs`); via hive-priv it writes only the runner - # registration token to the host env-file `/run/hive-ci/runner-token`, - # which the container bind-mounts read-only. The container never has - # access to the wider admin token. + # ⚠️ Two properties here are load-bearing and neither is visible from the + # config that implements it: # - # Nix builds inside the container use the shared /nix/store (standard - # nixos-container behaviour) with sandbox-fallback = true, because - # nspawn containers can't create the user-namespaces that nix sandboxing - # requires. See docs/process/gotchas.md. + # - The container gets its OWN network namespace, not the host's, so a + # PR's nix build cannot reach host-loopback services. That is a + # prompt-injection boundary; moving this to host netns for convenience + # removes it. Reachability of the forge from inside: + # `docs/networking/network.md::Container isolation`. + # - The forge ADMIN token never enters this container — hive-c0re holds + # it and hands in only a registration token. Full flow: + # `docs/scheduler/ci.md::Container design`. + # + # Non-ephemeral on purpose: gitea-actions-runner writes its registered + # credentials to its stateDir on first registration and reuses them, so an + # ephemeral container would re-register on every restart. + # + # Nix builds here use the shared /nix/store with `sandbox-fallback = true` + # — nspawn containers cannot create the user namespaces nix sandboxing + # wants: `docs/process/gotchas.md`. options.services.hyperhive.deploy.forgejo.ci = { enable = lib.mkOption {