diff --git a/docs/trust-boundary/boundary.md b/docs/trust-boundary/boundary.md index be8c00d9..c1e6e5e7 100644 --- a/docs/trust-boundary/boundary.md +++ b/docs/trust-boundary/boundary.md @@ -14,9 +14,9 @@ always on), the gateway proxies all operator-facing traffic, and - **Operator** — reaches every UI (the dashboard + every per-agent page) through the gateway, on one origin. - Operator-authority actions (approve / deny, answer-as-operator, - lifecycle POSTs) are served by the core daemon and only - reachable via the gateway. + The core daemon serves operator-authority actions (approve / deny, + answer-as-operator, lifecycle POSTs), reachable only via the + gateway. - **Agent** — speaks only for itself, only over its per-agent unix socket. The socket's identity _is_ the agent (see `docs/process/conventions.md`, "identity = socket"). An agent must not @@ -112,8 +112,8 @@ both sockets are `0666`, which is all a dialer needs. **Ownership is declared, not repaired.** The tmpfiles.d entry written by `SyncAgentTmpfiles` names the uid/gid directly. Don't add a chown alongside it: `d` re-applies on every boot _and_ every agent -spawn/destroy, so ownership set afterwards is reverted the next time any -agent changes — which is exactly how this dir spent a long time at +spawn/destroy, and reverts any ownership set afterwards the next time +any agent changes — which is exactly how this dir spent a long time at `0777 root root` while a privileged chown appeared to be fixing it. The mode is load-bearing, not cosmetic. Write permission on a diff --git a/docs/trust-boundary/security.md b/docs/trust-boundary/security.md index 48c77cbb..c6fa8982 100644 --- a/docs/trust-boundary/security.md +++ b/docs/trust-boundary/security.md @@ -34,8 +34,8 @@ Each agent gets its own scoped credentials, never shared: collaborator grants; can't act as another agent or as `core`). - **matrix token** → that agent's matrix account only. -A compromised/confused agent's reach on the forge or matrix is bounded by -_its own_ account's scope, not the swarm's. This is the main thing standing +_Its own_ account's scope bounds a compromised/confused agent's reach on the +forge or matrix, not the swarm's. This is the main thing standing between "one agent does something dumb" and "the whole hive is affected." **Identity vs. secret (matrix).** The scoping is on the _secret_, not the @@ -100,7 +100,7 @@ provider) before handing them over. `GET /api/state-file?path=

` serves files from agent state dirs and the shared space to authenticated dashboard users (browser, operator). -Two allow-listed root prefixes are accepted; all other paths are rejected +It accepts two allow-listed root prefixes and rejects all other paths before touching the filesystem: - `/var/lib/hyperhive/agents//state/` — per-agent durable notes @@ -224,13 +224,13 @@ known operations; there is no arbitrary command pass-through: | `WriteAgentForgeToken` / `WriteAgentMatrixToken` | write `0600` credential file into agent state dir | | `RestartMatrixDaemon` | `systemctl --machine=h- restart hive-matrix-daemon.service` | -**Container allowlist** — every request is validated against an -allowlist before any operation: only names matching the agent-name -convention (char-validated) or the known sibling service containers -(`hive-forge`, `hive-matrix`, `hive-ci`) are accepted. `hive-gateway` is -a host unit, not a container, so it's not in this list — see -`ReloadGatewayNginx` above for how its access is scoped instead. -Arbitrary container names are rejected. +**Container allowlist** — `hive-priv` validates every request against +an allowlist before any operation: the allowlist accepts only names +matching the agent-name convention (char-validated) or the known +sibling service containers (`hive-forge`, `hive-matrix`, `hive-ci`), +and rejects arbitrary container names. `hive-gateway` is a host unit, +not a container, so it's not in this list — see `ReloadGatewayNginx` +above for how its access is scoped instead. **Socket-activated** — systemd starts `hive-priv` on the first incoming connection (`LISTEN_FDS=1`); it's not running between calls.