fix: route forge/matrix token writes through hive-priv

hive-c0re runs as the unprivileged hive-core user (privsep from #702)
and cannot write to agent-owned state directories. forge-token and
matrix-token writes were failing with EACCES on every startup sweep.

Add WriteAgentStateFile to PrivRequest: hive-priv (root) writes the
file 0600 and chowns it to the agent user so the agent can read it.

- hive-sh4re: add AGENT_STATE_ROOT constant + WriteAgentStateFile variant
- hive-priv: validate agent name + filename (no traversal), write via root
- priv_client: add write_agent_state_file helper
- forge: mint_and_persist_token routes agent paths through priv
- matrix: ensure_user_for routes matrix-token through priv

Closes #1257
This commit is contained in:
atlas 2026-06-04 12:11:59 +02:00 committed by mara
commit eb51362d50
5 changed files with 172 additions and 46 deletions

View file

@ -22,6 +22,12 @@ pub const SIBLING_CONTAINERS: &[&str] = &["hive-forge", "hive-matrix", "hive-gat
/// `{META_DIR}#{name}`, derived by `hive-priv` — never passed over the wire.
pub const META_DIR: &str = "/var/lib/hyperhive/meta";
/// Root of per-agent state directories on the host.
/// Subdirectory layout: `<AGENT_STATE_ROOT>/<name>/state/<file>`.
/// Used by `WriteAgentStateFile` to derive the write path so the
/// exact path is never passed over the wire.
pub const AGENT_STATE_ROOT: &str = "/var/lib/hyperhive/agents";
/// Output format for `ReadContainerJournal`. Maps to journalctl
/// `--output=<...>`. Restricted to the two formats hive callers use so
/// the wire type can't smuggle an arbitrary `--output` value.
@ -222,6 +228,30 @@ pub enum PrivRequest {
/// Each element is a separate argv word — no shell expansion occurs.
args: Vec<String>,
},
// --- Agent state file writes ---
/// Write a credential file into an agent's bind-mounted state directory.
///
/// Path resolved by hive-priv: `AGENT_STATE_ROOT/<agent_name>/state/<filename>`.
/// hive-priv validates both the agent name and filename before writing.
///
/// After writing, the file is chowned to the agent user's uid/gid
/// (read from the state directory's owner) and chmoded 0600 so
/// only the agent process can read it.
///
/// Required because hive-c0re runs as the unprivileged `hive-core`
/// user and cannot write to agent-owned (0755) state directories
/// after the privsep introduced in #702.
WriteAgentStateFile {
/// Logical agent name (validated by `validate_agent_name`).
agent_name: String,
/// Plain filename within the state dir — no path separators allowed.
/// Example: `"forge-token"`, `"matrix-token"`.
filename: String,
/// File content to write. Written as-is; caller is responsible for
/// including any trailing newline.
content: String,
},
}
/// Response from the privileged helper.