From 727743507c8c07347e9f5124d9745500477f78fb Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 5 Aug 2026 22:45:09 +0200 Subject: [PATCH] feat(nix): the forge's default hostname moves under the swarm domain A swarm runs one forge and every hive in it reaches the same host, so the name belongs to the swarm rather than to whichever hive happens to run it: `forge.` instead of `forge.`. A deployment that was running before this keeps its current name with one line -- `swarm.forge.domain = "forge."` -- which is exactly what the old default rendered, so pinning it is a no-op today and freezes it against the new default. Certificates follow either way: the swarm-services sub-CA is name-constrained to the CONFIGURED names rather than to a fixed tree, so a pinned legacy name is as issuable as the new default. DNS follows too -- dnsmasq already lists `forge.domain` explicitly, precisely so a cross-domain override stays routed. The default stays total on a null swarm domain (`forge.invalid`) so the required-domain assertion in hive-network.nix is what an operator sees, rather than a coercion error naming this option. --- nix/host-modules/hive-forge/default.nix | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index c50532ef..7a59a3ce 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -8,6 +8,7 @@ let cfg = config.services.hyperhive.swarm.forge; gatewayCfg = config.services.hyperhive.gateway; hyperhiveDomain = config.services.hyperhive.domain; + swarmDomain = config.services.hyperhive.swarm.domain; tlsCfg = config.services.hyperhive.tls; # Self-signed gateway TLS: forgejo (Go) validates outbound webhook @@ -120,10 +121,14 @@ in domain = lib.mkOption { type = lib.types.str; - # Total on a null hive domain so the required-domain assertion in + # Under the SWARM domain, not this hive's: a swarm runs one forge + # and every hive in it reaches the same host, so the name belongs + # to the swarm rather than to whichever hive happens to run it. + # + # Total on a null swarm domain so the required-domain assertion in # hive-network.nix is the thing that fires; see the comment there. - default = if hyperhiveDomain == null then "forge.invalid" else "forge.${hyperhiveDomain}"; - defaultText = lib.literalExpression ''"forge.''${services.hyperhive.domain}"''; + default = if swarmDomain == null then "forge.invalid" else "forge.${swarmDomain}"; + defaultText = lib.literalExpression ''"forge.''${services.hyperhive.swarm.domain}"''; example = "git.example.com"; description = '' Public hostname for the forge. Doubles as both the forgejo @@ -131,10 +136,16 @@ in gateway vhost server-name when `behindGateway = true` (sub-domain routing — see `docs/gateway.md`). - Defaults to `forge.''${services.hyperhive.domain}` (idiomatic - sub-domain shape — `forge` labelled under the hive's bare - domain). `services.hyperhive.domain` is required, so there's - always a domain to derive from. + Defaults to `forge.''${services.hyperhive.swarm.domain}` — the + swarm's domain, not this hive's, because a swarm runs **one** + forge that every hive in it talks to. + + ⚠️ A deployment that was running before this moved keeps its + current name by pinning it here: + `forge.''${services.hyperhive.domain}`, which is exactly what + the old default rendered. Certificates follow either way: the + swarm-services sub-CA is name-constrained to the configured + names (see `./swarm-ca.nix`), not to a fixed tree. Set to a full hostname (`git.example.com`, `forge.internal.lan`, etc.) for a bespoke vhost shape — the