Watch
0
0
Fork
You've already forked hyperhive
0

refuse an agentNatsUrl that hive-priv would reject at container start

on deploy, deploy.hive-controller.queue.agentNatsUrl must be one
scheme://host:port; an IPv6 literal or a comma list now fails at evaluation
instead of failing every container start.
This commit is contained in:
atlas 2026-10-24 19:20:37 +02:00
commit 6dd9d0086e
3 changed files with 27 additions and 2 deletions

View file

@ -179,7 +179,9 @@ holds it in memory only. The one thing to configure is where the queue is:
It reaches each container at start, as `HIVE_AGENT_NATS_URL` in It reaches each container at start, as `HIVE_AGENT_NATS_URL` in
`/etc/hyperhive-hive-facts`, so no agent build carries it. On every hive, `/etc/hyperhive-hive-facts`, so no agent build carries it. On every hive,
`agentNatsUrl` defaults to the same `agentNatsUrl` defaults to the same
`tls://<swarm.nats.domain>:<swarm.nats.port>` as the hive's own. On the queue's `tls://<swarm.nats.domain>:<swarm.nats.port>` as the hive's own. The option takes one
`<scheme>://<host>:<port>` (a hostname or IPv4 address), not an IPv6 literal or a
list: evaluation refuses anything else. On the queue's
host the name resolves inside a container to the bridge address, where the host the name resolves inside a container to the bridge address, where the
firewall opens the port; on any other hive it resolves through the host's DNS, firewall opens the port; on any other hive it resolves through the host's DNS,
like the store's name. ⚠️ **Never a loopback address here**: an agent has its like the store's name. ⚠️ **Never a loopback address here**: an agent has its

View file

@ -477,7 +477,7 @@ in
# Only the address lives here. Each agent reads its own credential from the # Only the address lives here. Each agent reads its own credential from the
# store (`nix/agent-modules/queue-identity.nix`). # store (`nix/agent-modules/queue-identity.nix`).
options.services.hyperhive.deploy.hive-controller.queue.agentNatsUrl = lib.mkOption { options.services.hyperhive.deploy.hive-controller.queue.agentNatsUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str; type = lib.types.nullOr (lib.types.strMatching "[a-z]{1,10}://[A-Za-z0-9._-]{1,200}:[0-9]{1,5}");
default = "tls://${swarmCfg.nats.domain}:${toString swarmCfg.nats.port}"; default = "tls://${swarmCfg.nats.domain}:${toString swarmCfg.nats.port}";
defaultText = lib.literalExpression ''"tls://''${swarm.nats.domain}:''${swarm.nats.port}"''; defaultText = lib.literalExpression ''"tls://''${swarm.nats.domain}:''${swarm.nats.port}"'';
example = "tls://nats.example.com:4222"; example = "tls://nats.example.com:4222";
@ -492,6 +492,10 @@ in
agent's network namespace `127.0.0.1` is the agent, not this host, agent's network namespace `127.0.0.1` is the agent, not this host,
and the queue's certificate names no address anyway. and the queue's certificate names no address anyway.
One `<scheme>://<host>:<port>`: a hostname or IPv4 address, no IPv6 literal and no
list. The value reaches the container as `HIVE_AGENT_NATS_URL`, whose
character set hive-priv enforces at container start.
Null means this hive's agents have not been given the queue's address, Null means this hive's agents have not been given the queue's address,
and the harness is handed none. and the harness is handed none.
''; '';

View file

@ -308,6 +308,25 @@ let
name = "a hive with no agent queue address forwards none"; name = "a hive with no agent queue address forwards none";
ok = !(noAgentQueue.systemd.services.hive-c0re.environment ? HIVE_AGENT_NATS_URL); ok = !(noAgentQueue.systemd.services.hive-c0re.environment ? HIVE_AGENT_NATS_URL);
} }
{
# hive-priv refuses a value outside the facts' character set at container
# start, so the option refuses an IPv6 literal or a list at evaluation.
# Only the option's own value is forced, not the rest of either host. The
# default (`allLocal`) is the control that the lookup accepts an address.
name = "the agents' queue address option takes one scheme://host:port and nothing else";
ok =
let
accepts =
host: (builtins.tryEval host.services.hyperhive.deploy.hive-controller.queue.agentNatsUrl).success;
in
accepts allLocal
&& !(accepts (hiveWithController {
deploy.hive-controller.queue.agentNatsUrl = "tls://[fd00::1]:4222";
}))
&& !(accepts (hiveWithController {
deploy.hive-controller.queue.agentNatsUrl = "tls://a.t.local:4222,tls://b.t.local:4222";
}));
}
{ {
# Control: `bare` sets none of them, and its serve.json carries the # Control: `bare` sets none of them, and its serve.json carries the
# dashboard port, so the key lookup reads a real document. # dashboard port, so the key lookup reads a real document.