From fa658567db84424dcda3d0ebd4fed2787f04d84b Mon Sep 17 00:00:00 2001 From: damocles Date: Thu, 13 Aug 2026 19:53:34 +0200 Subject: [PATCH] hive-priv: replace json! with typed structs for account sidecar files --- Cargo.lock | 1 + hive-priv/Cargo.toml | 1 + hive-priv/src/main.rs | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bcab7b39..693b1121 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1795,6 +1795,7 @@ dependencies = [ "anyhow", "hive-priv-sock", "libc", + "serde", "serde_json", "tokio", "tracing", diff --git a/hive-priv/Cargo.toml b/hive-priv/Cargo.toml index a322d0f9..c63d98b2 100644 --- a/hive-priv/Cargo.toml +++ b/hive-priv/Cargo.toml @@ -11,6 +11,7 @@ workspace = true anyhow.workspace = true hive-priv-sock.workspace = true libc.workspace = true +serde.workspace = true serde_json.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/hive-priv/src/main.rs b/hive-priv/src/main.rs index a5ca3d75..7abaf198 100644 --- a/hive-priv/src/main.rs +++ b/hive-priv/src/main.rs @@ -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-.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-