feat(#2015): require services.hyperhive.domain (assertion) when hyperhive enabled

This commit is contained in:
damocles 2026-06-26 20:29:26 +02:00 committed by mara
commit 3d39cc00d0

View file

@ -128,9 +128,11 @@ in
options.services.hyperhive.enable = lib.mkEnableOption "hyperhive the agent swarm coordinator"; options.services.hyperhive.enable = lib.mkEnableOption "hyperhive the agent swarm coordinator";
# Canonical hive DNS domain shared by every subsystem that needs a # Canonical hive DNS domain shared by every subsystem that needs a
# stable hostname. Nullable + default null so existing configs # stable hostname. Typed nullOr (default null) so the option always
# evaluate unchanged; subsystems that need it (matrix) assert # exists, but it's REQUIRED whenever hyperhive is enabled — a config
# non-null in their own config block. Full identity-surface # assertion (see the `config` block) fails eval when it's unset, since
# matrix bakes it in on first boot and the gateway/forge/agent URLs all
# derive from it (no safe default; #2015). Full identity-surface
# context (HYPERHIVE_HIVE_DOMAIN / HIVE_NAME / SWARM_NAME env-var # context (HYPERHIVE_HIVE_DOMAIN / HIVE_NAME / SWARM_NAME env-var
# chain → identity.rs → claude prompt): docs/conventions.md:: # chain → identity.rs → claude prompt): docs/conventions.md::
# Hive identity (label + domain + display names). # Hive identity (label + domain + display names).
@ -143,9 +145,10 @@ in
stable name (currently: `services.hyperhive.matrix.serverName` stable name (currently: `services.hyperhive.matrix.serverName`
derives from this, defaulting to derives from this, defaulting to
`matrix.''${services.hyperhive.domain}` when `serverName` is `matrix.''${services.hyperhive.domain}` when `serverName` is
null). No default subsystems that opt to require it assert null). **Required** when `services.hyperhive.enable` eval fails
non-null in their own config and fail eval with a helpful with a helpful message if it's unset (it's baked into matrix on
message if it's missing. Exposed to agents as first boot and drives the gateway/forge/agent URLs, with no safe
default; changing it later is destructive). Exposed to agents as
`HYPERHIVE_HIVE_DOMAIN`; consumed by `HYPERHIVE_HIVE_DOMAIN`; consumed by
`hive-ag3nt::identity::hive_domain()` for `<name>@<domain>` `hive-ag3nt::identity::hive_domain()` for `<name>@<domain>`
qualified labels. qualified labels.
@ -828,31 +831,51 @@ in
config.services.hyperhive.swarm.wireguard.listenPort config.services.hyperhive.swarm.wireguard.listenPort
]; ];
assertions = assertions = [
lib.optionals config.services.hyperhive.swarm.wireguard.enable [ {
{ # `domain` has no safe default: it's baked into the matrix server
assertion = config.services.hyperhive.swarm.wireguard.privateKeyFile != null; # (tuwunnel) on first boot and drives the gateway/forge/agent URLs.
message = '' # Under mandatory network isolation agents can only reach the forge
services.hyperhive.swarm.wireguard.enable requires # via `forge.<domain>` on the bridge — with no domain there's no
services.hyperhive.swarm.wireguard.privateKeyFile to be set. # reachable name (see #2011). Changing it later is destructive
Generate a key: wg genkey > /etc/wireguard/hive.key # (deletes Matrix history), so it must be set before first boot.
''; assertion = config.services.hyperhive.domain != null;
} message = ''
{ services.hyperhive.domain must be set (e.g. "darkest.space").
assertion = config.services.hyperhive.swarm.wireguard.address != ""; It's baked into the matrix server on first boot and into the
message = '' gateway / forge / agent URLs, so hyperhive needs a stable domain
services.hyperhive.swarm.wireguard.enable requires and there is no safe default. Agents reach the forge via
services.hyperhive.swarm.wireguard.address to be set forge.<domain> on the bridge network, so without it the forge is
(e.g. "10.100.0.1/24"). unreachable from containers. Changing the domain after first boot
''; is destructive (deletes Matrix history) pick it before initial
} setup. See docs/gateway.md and docs/matrix.md.
] '';
++ lib.optionals config.services.hyperhive.otel.enable [ }
{ ]
assertion = config.services.hyperhive.otel.endpoint != ""; ++ lib.optionals config.services.hyperhive.swarm.wireguard.enable [
message = "services.hyperhive.otel.enable is true but services.hyperhive.otel.endpoint is empty."; {
} assertion = config.services.hyperhive.swarm.wireguard.privateKeyFile != null;
]; message = ''
services.hyperhive.swarm.wireguard.enable requires
services.hyperhive.swarm.wireguard.privateKeyFile to be set.
Generate a key: wg genkey > /etc/wireguard/hive.key
'';
}
{
assertion = config.services.hyperhive.swarm.wireguard.address != "";
message = ''
services.hyperhive.swarm.wireguard.enable requires
services.hyperhive.swarm.wireguard.address to be set
(e.g. "10.100.0.1/24").
'';
}
]
++ lib.optionals config.services.hyperhive.otel.enable [
{
assertion = config.services.hyperhive.otel.endpoint != "";
message = "services.hyperhive.otel.enable is true but services.hyperhive.otel.endpoint is empty.";
}
];
systemd.services.hive-c0re = { systemd.services.hive-c0re = {
description = "hyperhive coordinator daemon"; description = "hyperhive coordinator daemon";