Watch
0
0
Fork
You've already forked hyperhive
0

swarm-controller: mint each agent's matrix account with the swarm's token

A `MintAgentMatrixAccount` node creates the agent's account on the swarm's
homeserver with the swarm appservice token, stores its token at
`swarm/agents/<agent>/matrix/main`, and reads it back with whoami before
reporting success. It is a root of agent creation, `after_any` into the
deploy, and a five-minute backfill over every agent with a store identity
queues the same node — the shape of the forge-token mint.

The decision reads the stored token back rather than only checking that one
is stored: the swarm and a hive both pin the device `hyperhive-<agent>`, so
each login replaces the other's token. A failed read plans nothing, so an
outage never rotates every agent's token.

`matrixHomeserverUrl` now defaults to the swarm's `chat.` vhost, since the
mint is what consults it.
This commit is contained in:
atlas 2026-09-25 00:25:06 +02:00 • committed by mara
commit 2776e121e5
7 changed files with 626 additions and 36 deletions

View file

@ -1,5 +1,13 @@
//! Give one agent an external matrix account: put the credential in the
//! swarm's secret store, then tell that agent's hive it is there.
//! An agent's matrix accounts, from this daemon's two sides of them.
//!
//! **The internal one** — [`agent_token`] — is the agent's own `main` account on
//! the swarm's homeserver, minted with the swarm's appservice token and stored
//! where the agent's daemon reads it. See docs/swarm/credentials.md for why
//! `main` is the one name [`put_matrix_account`] refuses to write.
//!
//! **The external one** — [`put_matrix_account`] and everything under it — is
//! an account somewhere else that an operator hands us a credential for: put it
//! in the swarm's secret store, then tell that agent's hive it is there.
//!
//! The hive end is `hive-c0re/src/workers/credential.rs`, which reads the
//! value under its own identity and writes it into the agent's state dir. The
@ -31,6 +39,8 @@ use utoipa::ToSchema;
use super::{AppState, error_problem, swarm_hive};
pub mod agent_token;
fn default_mode() -> String {
"token".to_owned()
}
@ -41,9 +51,9 @@ fn default_mode() -> String {
/// when a caller omits one. Read via [`configured_default_homeserver`], not
/// directly — see that fn's doc.
///
/// Not yet consulted by [`put_matrix_account`]: `homeserver_or_configured_default`
/// below exists for a later slice of this homeserver-default rollout to
/// call; this one only wires the config through.
/// Also the homeserver [`agent_token`] mints agents' own accounts on. Not yet
/// consulted by [`put_matrix_account`]: `homeserver_or_configured_default`
/// below exists for a later slice of this homeserver-default rollout to call.
pub(crate) const DEFAULT_HOMESERVER_ENV: &str = "SWARM_CONTROLLER_MATRIX_HOMESERVER_URL";
/// `caller`'s own homeserver, or `default` when the caller left it unset.
@ -250,11 +260,11 @@ pub async fn put_matrix_account(
Ok(Json(PutMatrixAccountResponse { user_id }))
}
/// Whether `account` is the hive-internal name every hive declares per
/// agent (`nix/agent-modules/matrix.nix`) — see the call site's own comment
/// for why this route must never write one.
/// Whether `account` is the agent's own account, which [`agent_token`] mints
/// and `nix/agent-modules/matrix.nix` declares per agent — see the call site's
/// own comment for why this route must never write one.
fn is_reserved_account(account: &str) -> bool {
account == "main"
account == agent_token::ACCOUNT
}
/// Token-mode's only requirement: a token was actually given. Split out of