Watch
0
0
Fork
You've already forked hyperhive
0

docs: drop harness systemd settings; swarm-nats-auth: refuse the hive's shared agent client

Docs (review on #4948): the harness's restart settings are not useful to
a reader, so the `Restart`/`RestartSec` bullet in docs/turn-loop and the
"30 seconds later, no start limit" wording in docs/swarm are removed.
What stays is the behaviour: the harness exits and comes back until the
queue accepts it.

Grant: with the harness's shared-client fallback gone, nothing presents
the hive's shared agent client (`hive-<hive>-agent`) to the queue;
swarm-logs uses that OIDC client over HTTP only. swarm-nats-auth now
refuses it outright instead of granting the configured
`$SWARM.term.{hive}.>` / `$SWARM.agent-state.{hive}.>` publish and its
`_INBOX.client.<id>.>` subscribe, so an agent holding it can no longer
publish as a sibling. The agent arm still runs before the hive arm, so
that id never falls through to its hive's grant.

Removed with it: the `--agent-publish-subject` flag and its two uses in
swarm-nats.nix, `Policy`'s agent subject list, and
swarm-queue-client's `client_inbox_prefix`. The module-eval now asserts
the flag is absent; the policy tests assert the refusal and that the
hive itself is still admitted.
This commit is contained in:
atlas 2026-10-04 20:46:49 +02:00 • committed by mara
commit 91fdf96a67
10 changed files with 85 additions and 333 deletions

View file

@ -812,26 +812,15 @@ in
"--hive-client-prefix ${lib.escapeShellArg autheliaCfg.hiveClientPrefix}"
"--agent-client-suffix ${lib.escapeShellArg autheliaCfg.agentClientSuffix}"
"--reader-client ${lib.escapeShellArg controllerCfg.queueClientId}"
# What an agent may publish to, `{hive}` standing for the
# hive its client id names. Without it the responder has no
# agent grant to hand out and refuses every agent at CONNECT,
# so the terminal stream below depends on this line existing.
# What an agent may publish to, keyed on its own name: its
# terminal rows and its turn-state header
# (`hive-agent::swarm_agent_state`), two subject families so a
# subscriber following one agent's terminal is not also handed
# every header. The hive's shared agent client gets nothing.
#
# `$$`, not `$`: systemd substitutes `$NAME` in `ExecStart`
# whether or not it is quoted, so a single dollar reaches the
# responder as the empty expansion of an unset `SWARM` and the
# grant silently becomes `.term.{hive}.>`.
"--agent-publish-subject ${lib.escapeShellArg "\$\$SWARM.term.{hive}.>"}"
# The turn-state header the swarm's agent view renders from
# (`hive-agent::swarm_agent_state`). Its own subject family
# rather than a leaf under `.term.`: a subscriber following
# one agent's terminal should not also be handed every
# header, and the two have opposite shapes — a terminal is
# an append-only row stream, a header is one current value
# republished on change.
"--agent-publish-subject ${lib.escapeShellArg "\$\$SWARM.agent-state.{hive}.>"}"
# What an agent that proved its own credential may publish to:
# the same two streams, keyed on the agent alone.
# responder as the empty expansion of an unset `SWARM`.
"--agent-token-publish-subject ${lib.escapeShellArg "\$\$SWARM.term.{agent}"}"
"--agent-token-publish-subject ${lib.escapeShellArg "\$\$SWARM.agent-state.{agent}"}"
# Its own key in the `agent-icons` KV bucket, and nothing else
@ -840,9 +829,6 @@ in
# one subject is the whole write. The harness publishes to the
# subject directly instead of opening the bucket, so it needs
# no `$JS.API.*` subject; swarm-controller creates the bucket.
# Not granted to the hive's shared agent client: every agent
# on a hive presents that one, so it cannot be scoped to one
# agent's key.
"--agent-token-publish-subject ${lib.escapeShellArg "\$\$KV.agent-icons.{agent}"}"
# Its subagents' terminal rows
# (`swarm_queue_client::subagent_term`), publish only and no

View file

@ -103,45 +103,21 @@ let
ok = natsOldPath.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608;
}
{
# Reads the RENDERED unit text, not the module's source, because the
# failure this defends against renders perfectly: systemd substitutes
# `$NAME` in `ExecStart` regardless of quoting, so a single dollar
# here hands the responder `.term.{hive}.>` — a grant that parses, is
# accepted, and matches nothing an agent ever publishes to. Asserting
# the doubled dollar is the only way to tell the two apart before
# deploy. The flag's presence is asserted separately so that dropping
# the grant entirely fails as its own arm rather than as an escaping
# complaint.
name = "the responder grants agents their hive's terminal subject, and the dollar survives systemd";
# The responder refuses the hive's shared agent client and takes no flag
# granting it subjects: an `--agent-publish-subject` fails the unit at
# start.
name = "the responder grants the hive's shared agent client nothing";
ok =
let
exec =
natsOldPath.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
in
lib.hasInfix "--agent-publish-subject " exec && lib.hasInfix "$$SWARM.term.{hive}.>" exec;
!(lib.hasInfix "--agent-publish-subject " exec);
}
{
# Second grant, same escaping trap, asserted separately: the two
# subject families are independent features (terminal rows and the
# turn-state header) and dropping either should fail as its own arm
# rather than being masked by the other still being present.
#
# Flag and argument are matched as one infix rather than as two
# independent `hasInfix` calls: the responder takes the flag
# repeatedly, so the thing worth pinning is that THIS subject is the
# argument of one of them, which two separate presence checks would
# both pass on while the subject sat under some other flag entirely.
name = "the responder grants agents their hive's agent-state subject too";
ok =
let
exec =
natsOldPath.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
in
lib.hasInfix "--agent-publish-subject '$$SWARM.agent-state.{hive}.>'" exec;
}
{
# The per-agent grant: the same two streams keyed on the agent alone,
# with the same doubled dollar, and the role the store writes for it.
# The per-agent grant: the terminal and agent-state streams keyed on the
# agent alone, with the doubled dollar, and the role the store writes for
# it.
name = "the responder grants a verified agent its own hive-free subjects";
ok =
let