From 78482cb6240851c494202340511555b0971006d3 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 17 Jun 2026 15:29:52 +0200 Subject: [PATCH] nix: remove the non-isolated (shared-netns) mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Network isolation is validated working end to end (forge + matrix reach the gateway under private netns), so the shared-host-netns mode is removed — there is now one mode. - hive-network.nix: the bridge/DNS block and the isolation overlay are now unconditional whenever hyperhive is enabled (gated on services.hyperhive.enable, not the per-feature toggles). The redundant isolateContainers-implies-enable guard is dropped. - network.enable and isolateContainers are kept as DEPRECATED no-op options so existing configs that set them to true still evaluate cleanly; setting either to false now warns (gated on hyperhive being enabled, so a non-hyperhive host gets no spurious warning) and has no effect. Both are slated for removal in a future release. - hive-c0re.nix: the HIVE_FORGE_URL / HIVE_MATRIX_URL conditionals drop the "&& isolateContainers" clause — agents always reach forge/matrix through the gateway vhost now. - hive-matrix.nix: refresh one stale comment. The Rust lifecycle is env-driven (HIVE_NETWORK_ISOLATION), so no Rust change is needed: the env is now always set, so the existing private-netns path always runs. Supersedes the default-on flip (the option it would have defaulted is gone). --- nix/modules/hive-c0re.nix | 29 +++++------ nix/modules/hive-matrix.nix | 2 +- nix/modules/hive-network.nix | 97 +++++++++++++++++++++--------------- 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index ef3f9e98..2aa1b879 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -756,10 +756,13 @@ in # needed — nginx proxies to forgejo as it does for the operator. # - Shared netns: host loopback is reachable, use direct port. # See `docs/gateway.md::HIVE_FORGE_URL`. + # Network isolation is now unconditional (the shared-netns mode was + # removed), so agents always reach the forge through the gateway + # vhost rather than host loopback. The `network.enable` guard remains + # only so a deliberately network-less deployment still falls back to + # loopback; in the normal case it is always on. HIVE_FORGE_URL = - if - config.services.hyperhive.network.enable && config.services.hyperhive.network.isolateContainers - then + if config.services.hyperhive.network.enable then "http://${config.services.hyperhive.forge.domain}" else "http://127.0.0.1:${toString config.services.hyperhive.forge.httpPort}"; @@ -767,19 +770,17 @@ in // lib.optionalAttrs config.services.hyperhive.matrix.enable { # In-cluster matrix homeserver URL for each agent's # hive-matrix-daemon. Same shape + rationale as HIVE_FORGE_URL: - # - Isolated (private netns): reach tuwunel via the gateway vhost - # (`matrix.`) on plain http:80 — host loopback is dead. - # - Shared netns: direct host loopback on the tuwunel port. - # gatewayHost null-guard falls back to loopback so a domain-less - # config doesn't break eval (it just won't work under isolation, - # which needs a gateway anyway). Forwarded to agents by meta.rs - # alongside HIVE_FORGE_URL; shares the same env-forwarding ordering - # caveat (value baked at config-generation time). + # network isolation is now unconditional, so agents reach tuwunel + # via the gateway vhost (`matrix.`) on plain http:80 rather + # than host loopback. The gatewayHost null-guard falls back to + # loopback so a domain-less config still evals; the `network.enable` + # guard covers a deliberately network-less deployment. Forwarded to + # agents by meta.rs alongside HIVE_FORGE_URL; shares the same + # env-forwarding ordering caveat (value baked at config-generation + # time). HIVE_MATRIX_URL = if - config.services.hyperhive.network.enable - && config.services.hyperhive.network.isolateContainers - && config.services.hyperhive.matrix.gatewayHost != null + config.services.hyperhive.network.enable && config.services.hyperhive.matrix.gatewayHost != null then "http://${config.services.hyperhive.matrix.gatewayHost}" else diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix index ca287a7b..555b8d4f 100644 --- a/nix/modules/hive-matrix.nix +++ b/nix/modules/hive-matrix.nix @@ -377,7 +377,7 @@ in # `environment.etc."resolv.conf".text` is `nameserver `. # This container always shares the host netns # (`privateNetwork = false`), so it reaches `bridgeIp` regardless - # of `isolateContainers`. Network module off → inherit the host's + # of agent-container isolation. Network module off → inherit the host's # resolv.conf. See `docs/network.md`. networking = lib.mkMerge [ (lib.mkIf networkCfg.enable { diff --git a/nix/modules/hive-network.nix b/nix/modules/hive-network.nix index b20e7553..f4a6f9e9 100644 --- a/nix/modules/hive-network.nix +++ b/nix/modules/hive-network.nix @@ -19,18 +19,18 @@ in defaultText = lib.literalExpression "config.services.hyperhive.enable"; example = false; description = '' - Stand up the hive-internal bridge + dnsmasq resolver. - Defaults to `config.services.hyperhive.enable` so it comes - on automatically with the rest of hyperhive. Requires - `services.hyperhive.domain` to be set — the dnsmasq resolver - is authoritative for `` and its sub-domains. - When enabled: a bridge interface (`bridgeName`) appears on the - host with `bridgeIp` assigned, and the hive-gateway container - runs a dnsmasq listening on that IP for `` + - sub-domains. Agent containers still default to shared host - netns — the endpoint is up but only used once - `isolateContainers = true` flips containers to private netns - + veth peers on this bridge. + **DEPRECATED — ignored.** The hive network (bridge + dnsmasq + resolver + private-netns isolation) is now always on whenever + hyperhive is enabled; setting this to `false` warns and has no + effect. Retained as a no-op so existing configs eval; will be + removed in a future release. + + The network requires `services.hyperhive.domain` to be set — the + dnsmasq resolver is authoritative for `` and its + sub-domains. A bridge interface (`bridgeName`) appears on the host + with `bridgeIp` assigned, the hive-gateway container runs a dnsmasq + on that IP, and each agent container runs in a private netns with a + veth pair on the bridge. ''; }; @@ -94,11 +94,16 @@ in isolateContainers = lib.mkOption { type = lib.types.bool; - default = false; + default = true; example = true; description = '' - Flip agent containers from shared host netns to private netns. - When true, each agent container gets a dedicated veth + **DEPRECATED — ignored.** Network isolation is now the only mode and + is always on whenever hyperhive is enabled; the shared-netns path was + removed. This option is retained as a no-op so existing configs eval; + setting it to `false` warns and has no effect. It will be removed in + a future release. + + Each agent container gets a dedicated veth pair attached to `bridgeName` and a deterministic IP from the bridge subnet. The bridge (already up when `enable = true`) becomes the sole routed path between the host and agent @@ -142,21 +147,27 @@ in }; config = lib.mkMerge [ - (lib.mkIf cfg.enable { + # The hive network + container isolation are unconditional whenever + # hyperhive is enabled: the shared-netns mode was removed, so there is + # one mode (private netns behind the bridge). `network.enable` and + # `isolateContainers` are kept as deprecated no-op options (see the + # warnings block below) so existing configs that set them still eval. + (lib.mkIf config.services.hyperhive.enable { assertions = [ { assertion = config.services.hyperhive.domain != null; message = '' - services.hyperhive.network.enable = true requires - services.hyperhive.domain to be set — the resolver needs a - domain to be authoritative for. Either pin a hostname - (`services.hyperhive.domain = "example.com";`) or set - `services.hyperhive.network.enable = false` explicitly. + hyperhive requires services.hyperhive.domain to be set — the + hive resolver is authoritative for `` and its + sub-domains, and agents reach the forge/matrix through the + gateway by that domain. Pin a hostname + (`services.hyperhive.domain = "example.com";`). ''; } ]; - # Virtual bridge — veth pairs attach when isolateContainers flips on. + # Virtual bridge — each agent container attaches a veth pair (isolation + # is unconditional now). networking.bridges.${cfg.bridgeName}.interfaces = [ ]; # Bridge IP — dnsmasq (in the gateway container) binds here. @@ -174,23 +185,9 @@ in }; }) - # Guard: fires unconditionally on isolateContainers so the assertion - # is not silently swallowed when enable=false. - (lib.mkIf cfg.isolateContainers { - assertions = [ - { - assertion = cfg.enable; - message = '' - services.hyperhive.network.isolateContainers = true requires - services.hyperhive.network.enable = true (the bridge and - resolver must be running before isolation is flipped on). - ''; - } - ]; - }) - - # Container isolation overlay — see docs/network.md#container-isolation. - (lib.mkIf (cfg.enable && cfg.isolateContainers) { + # Container isolation overlay — now unconditional (the shared-netns + # mode was removed). See docs/network.md#container-isolation. + (lib.mkIf config.services.hyperhive.enable { # Agents route internet traffic via the bridge; NAT masquerades their RFC-1918 IPs. boot.kernel.sysctl."net.ipv4.ip_forward" = 1; @@ -222,5 +219,27 @@ in HIVE_NETWORK_SUBNET = "${cfg.bridgeIp}/${toString cfg.bridgePrefixLength}"; }; }) + + # Deprecation surface for the removed toggles. Both options are kept so + # existing configs that set them to `true` still eval cleanly; setting + # either to `false` no longer does anything (network + isolation are + # unconditional now), so warn rather than silently ignore. + { + # Only warn when hyperhive itself is enabled — otherwise `cfg.enable` + # defaults to `false` (tracking `hyperhive.enable`) and we'd fire a + # spurious deprecation warning on a host that doesn't run hyperhive. + warnings = lib.optionals config.services.hyperhive.enable ( + lib.optional (!cfg.enable) '' + services.hyperhive.network.enable = false is deprecated and ignored + — the hive network is now always on (private-netns isolation is the + only mode). Remove the setting. + '' + ++ lib.optional (!cfg.isolateContainers) '' + services.hyperhive.network.isolateContainers = false is deprecated + and ignored — network isolation is now the only mode and is always + on. Remove the setting. + '' + ); + } ]; }