fix: split WriteAgentStateFile into WriteAgentForgeToken + WriteAgentMatrixToken

Addresses mara's review: each credential type gets its own PrivRequest
variant, making the exact priv surface visible in the wire protocol.
No runtime filename dispatch — the operation name is the gate.

- WriteAgentForgeToken { agent_name, token } → state/forge-token
- WriteAgentMatrixToken { agent_name, token } → state/matrix-token
- priv_client: two typed fns (write_agent_forge_token, write_agent_matrix_token)
- forge.rs: split mint_and_persist_token into mint_and_persist_agent_token
  (priv) + mint_and_persist_core_token (direct write); drop dead token_path fn
- matrix.rs: call write_agent_matrix_token directly
This commit is contained in:
atlas 2026-06-04 13:53:43 +02:00 committed by mara
commit 7022cd3826
5 changed files with 73 additions and 92 deletions

View file

@ -322,38 +322,28 @@ async fn exec(req: PrivRequest, writer: &mut OwnedWriteHalf) -> Result<(String,
run_forge_admin(args).await
}
PrivRequest::WriteAgentStateFile {
PrivRequest::WriteAgentForgeToken {
ref agent_name,
ref filename,
ref content,
ref token,
} => {
validate_agent_name(agent_name)?;
validate_state_filename(filename)?;
write_agent_state_file(agent_name, filename, content)
write_agent_state_file(agent_name, "forge-token", &format!("{token}\n"))
}
PrivRequest::WriteAgentMatrixToken {
ref agent_name,
ref token,
} => {
validate_agent_name(agent_name)?;
write_agent_state_file(agent_name, "matrix-token", &format!("{token}\n"))
}
}
}
/// Explicit allowlist of filenames `WriteAgentStateFile` may write.
/// New credential files must be added here deliberately — hive-priv
/// rejects any filename not in this list.
const ALLOWED_STATE_FILENAMES: &[&str] = &["forge-token", "matrix-token"];
/// Validate a filename destined for `WriteAgentStateFile` against the
/// explicit allowlist. Only known credential filenames are accepted.
fn validate_state_filename(filename: &str) -> Result<()> {
if !ALLOWED_STATE_FILENAMES.contains(&filename) {
bail!(
"state filename {filename:?} not in allowlist {:?}",
ALLOWED_STATE_FILENAMES
);
}
Ok(())
}
/// Write `content` to `AGENT_STATE_ROOT/<agent_name>/state/<filename>`,
/// chown to the agent user (derived from the state dir's existing owner),
/// and chmod 0600. Running as root (hive-priv), so all of this succeeds
/// Shared helper for `WriteAgentForgeToken` and `WriteAgentMatrixToken`.
/// Writes `content` to `AGENT_STATE_ROOT/<agent_name>/state/<filename>`,
/// chowns to the agent user (derived from the state dir's existing owner),
/// and chmods 0600. Running as root (hive-priv), so this succeeds
/// regardless of the file's prior owner/permissions.
fn write_agent_state_file(
agent_name: &str,