hive-priv: replace json! with typed structs for account sidecar files

This commit is contained in:
damocles 2026-08-13 19:53:34 +02:00 committed by mara
commit fa658567db
3 changed files with 37 additions and 2 deletions

View file

@ -27,6 +27,7 @@ use hive_priv_sock::{
NetworkIsolation, PAUSED_MARKER_FILE, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse,
PrivStream, PrivStreamLine, SIBLING_CONTAINERS,
};
use serde::Serialize;
use tokio::io::{AsyncWriteExt, BufReader};
use tokio::net::unix::OwnedWriteHalf;
use tokio::net::{UnixListener, UnixStream};
@ -468,7 +469,10 @@ async fn exec(
// when both `account` and `homeserver` are present; the account
// suffix is already validated above.
if let (Some(a), Some(hs)) = (account, homeserver) {
let meta = serde_json::json!({ "homeserver": hs }).to_string();
let meta = serde_json::to_string(&MatrixAccountSidecar {
homeserver: hs.as_str(),
})
.context("serialize matrix account sidecar")?;
write_agent_state_file(agent_name, &format!("matrix-account-{a}.json"), &meta)?;
}
Ok(res)
@ -497,7 +501,10 @@ async fn exec(
)?;
// Sidecar carries the base URL — there's no host-side nix config
// for extra forges, so this is the only place it's persisted.
let meta = serde_json::json!({ "base_url": base_url }).to_string();
let meta = serde_json::to_string(&ForgeSidecar {
base_url: base_url.as_str(),
})
.context("serialize forge account sidecar")?;
write_agent_state_file(agent_name, &format!("forge-{label}.json"), &meta)?;
Ok(res)
}
@ -957,6 +964,32 @@ fn write_state_file_nofollow(dir: &Path, filename: &str, content: &str) -> Resul
Ok(file)
}
/// Sidecar written alongside an extra matrix account's token
/// (`matrix-account-<name>.json`) so `hive-matrix-mcp` can auto-discover
/// the account's homeserver without a static `matrixAccounts` config
/// entry. Read side: `hive-matrix-mcp/src/accounts.rs`'s
/// `read_account_homeserver` (deliberately reads via a bare
/// `serde_json::Value` rather than this shape — that side treats a
/// malformed/missing sidecar as "skip this account" rather than an
/// error, so it stays loosely typed; this side is the one place the
/// file is written, so it gets the precise shape).
#[derive(Serialize)]
struct MatrixAccountSidecar<'a> {
homeserver: &'a str,
}
/// Sidecar written alongside a dashboard-provisioned extra forge
/// account's token (`forge-<label>.json`) so `hive-forge` can resolve
/// the account's base URL. Read side: `hive-forge/src/client.rs`'s own
/// (separately defined, deserialize-only) `ForgeSidecar` — same field
/// name (`base_url`), no shared crate between `hive-priv` and
/// `hive-forge` to hang a common type off, so the two structs are
/// pinned to the same JSON key by convention, not by the compiler.
#[derive(Serialize)]
struct ForgeSidecar<'a> {
base_url: &'a str,
}
/// 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),