diff --git a/docs/process/conventions.md b/docs/process/conventions.md index a9021eb8..756816f7 100644 --- a/docs/process/conventions.md +++ b/docs/process/conventions.md @@ -289,6 +289,8 @@ host access it has. | `execution` | the `bash` MCP server (`mcp__bash__run`/`status`/`kill`), rendered into the agent's MCP config only with it; a subagent gets Claude's own `Bash` instead. See `docs/tools/bash.md`. | | `web_tools` | the Claude built-ins `WebFetch`/`WebSearch` | | `manage_root_agent` | every agent's state (rw) bind-mounted into the holder's container, plus `/meta` (ro) | +| `logs` | the log store: `swarm-logs` queries. Checked by `swarm-logs-auth` at the gateway, not by a tool list. Off by default. | +| `metrics` | the metrics store: `swarm-metrics` queries. Checked by `swarm-metrics-agent-auth`, the same binary, for the metrics gateway. Off by default. | **Always-on tools** — `Permission::ALWAYS_ON_TOOLS` exposes `set_status`, `compact`, and `mark_todos_done` to every agent regardless of its @@ -311,6 +313,23 @@ the default (`Permission::DEFAULT`): `messaging`, `meta`, `inbox`, none. swarm-controller logs every refused `PUT` or `DELETE` on that route at `warn` as `agent permissions: request refused`, with the fields `op`, `agent`, `status` and `detail`. +**`logs` and `metrics`** — off for every agent until granted, and separate +because logs are the more sensitive. Grant one with +`swarmctl agent permissions set ` (listing it with the others) or the +create-agent screen. An agent without it gets a 403 from the store's gateway +when `swarm-logs` or `swarm-metrics` queries; a bad secret is still a 401. The +controller refuses the grant, with a 409 naming the hive, unless the agent's +hive advertises `tolerant-permissions` in its status snapshot +(`swarm_wire::hive_status`): a hive that predates the permission would fail to +decode the record. It also mirrors the two grants to the store leaf +`swarm/agents//observability` (`swarm_secret_client::observability`), +which the gateways read; the gateway denies when it can't read that leaf. A +revoked grant stops working within `authVerdictTtl` (60 seconds by default) of +the agent's last allowed query. Grant it only after the agent runs a harness +that skips names it doesn't know (its next update after the release that adds +these two); an older harness that reads such a record holds no permissions at +its next start. + **Internet flag** — the record also carries `unrestricted_internet`, a boolean that isn't a `Permission`. An absent value means on, so every agent that existed before the field keeps the open access it had. `POST /api/agents` diff --git a/docs/swarm/credentials-reference.md b/docs/swarm/credentials-reference.md index f7c1bc7c..4e841984 100644 --- a/docs/swarm/credentials-reference.md +++ b/docs/swarm/credentials-reference.md @@ -16,47 +16,48 @@ the rest of the cell says how. -| store path | minter | reader | automatic re-mint | automatic re-pull | -| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `swarm/agents//matrix/main` | `swarm-controller`, at agent creation and every 5 minutes | the agent | ✅ when missing or rejected by the homeserver | ✅ the daemon restarts within 5 minutes of a rejection | -| `swarm/agents//matrix/` | `swarm-controller`, from a credential you hand it | the agent | must be stated | ✅ retried within 2 to 16 minutes after a rejection | -| `swarm/agents//matrix-recovery/` | `swarm-controller`, a random passphrase per account | the agent | ❌ never replaced: the account's key backup opens only with this passphrase | ❌ read when the account comes up | -| `swarm/controller/swarm-controller/matrix/appservice-token` | `swarm-matrix-ctl appservice sync` in `hive-matrix`, from the registration's `as_token` | `swarm-controller` | ❌ follows the registration below | ✅ read every 5 minutes | -| `swarm/controller/swarm-controller/matrix/appservice-registration` | `swarm-matrix-ctl appservice render` in `hive-matrix`, when the store answers and holds none; before that, the tokens an earlier version kept in the container, stored unchanged | `swarm-matrix-ctl` in `hive-matrix`; the controller has no grant to it | ❌ minted once; an operator who replaces it makes `sync` render the new pair and restart the homeserver | ✅ `sync` re-reads it every 10 minutes | -| `swarm/controller/swarm-controller/oidc/client` | authelia, first boot | `swarm-controller` | ❌ minted once, straight into the store; minted again only when the store holds none | ✅ re-read when authelia refuses it | -| `swarm/controller/swarm-controller/forge/token` | the forge, once | `swarm-controller` | ❌ minted once; delete `/var/lib/forgejo/swarm-controller-token-name` in the forge container to mint a new one | ✅ re-read on a 401 | -| `swarm/controller/swarm-controller/grafana/token` | `swarm-bao-grafana-controller-token` on Grafana's host | `swarm-controller` | ✅ every 10 minutes, when Grafana refuses it or none is stored | ✅ re-read on a 401 | -| `swarm/controller/swarm-controller/forge/webhook-secret` | `swarm-controller`, at start, from its old `webhook-secret` file; a new one only when there is no file | `swarm-controller` | ❌ minted once; a rotated secret fails every delivery until the forge hooks are re-registered | ❌ read at start | -| `swarm/agents//bao-mtls` | the store's agent PKI mount (`deploy.bao.agentPkiMountPath`), at agent creation, and by the renewal pass when none is stored or its cert-auth role is missing | `hive-c0re`, then the agent | ✅ re-issued every 5 minutes once past half its 7-day validity; minted when none is stored or its cert-auth role is missing, for agents not `Destroyed` | ✅ the agent re-reads every 10 minutes; it renews only while its current leaf is valid | -| `swarm/agents//queue` | `swarm-controller`, at agent creation | the agent; the queue, log and metrics auth services | ✅ re-minted at 45 days; skipped for `Destroyed` agents, whose path is deleted | ✅ read on every reconnect; an open connection keeps the old secret for up to an hour; the log and metrics stores honour a replaced secret for up to `deploy.victorialogs.authVerdictTtl` and `deploy.victoriametrics.agentAuthVerdictTtl` (60 s by default) | -| `swarm/agents//forge-token` | `swarm-controller`, at agent creation and every 5 minutes | the agent | ✅ when missing or no longer matching the forge | ✅ every 10 minutes | -| `swarm/agents//forge/