//! The secret broker daemon (spec §15). Runs as its own process; only the //! server process can reach its socket — agent sandboxes have no route to //! it by construction. //! //! Configuration (environment): //! - `TEAMCLAW_DATABASE__URL` Postgres connection string (required) //! - `TEAMCLAW_BROKER_SOCKET` unix socket path (default /tmp/teamclaw-broker.sock) //! - `TEAMCLAW_BROKER_KEY_FILE` master key file; generated on first boot use std::path::PathBuf; use std::process::ExitCode; use tc_secrets::{BrokerServer, FileKey}; #[tokio::main] async fn main() -> ExitCode { match run().await { Ok(()) => ExitCode::SUCCESS, Err(message) => { eprintln!("teamclaw-broker: {message}"); ExitCode::FAILURE } } } async fn run() -> Result<(), String> { let database_url = std::env::var("TEAMCLAW_DATABASE__URL") .map_err(|_| "TEAMCLAW_DATABASE__URL is required")?; let socket_path = PathBuf::from( std::env::var("TEAMCLAW_BROKER_SOCKET") .unwrap_or_else(|_| "/tmp/teamclaw-broker.sock".into()), ); let key_path = PathBuf::from( std::env::var("TEAMCLAW_BROKER_KEY_FILE") .unwrap_or_else(|_| "/etc/teamclaw/broker.key".into()), ); if !key_path.exists() { FileKey::generate(&key_path).map_err(|e| format!("key generation failed: {e}"))?; println!( "teamclaw-broker: generated master key at {} — BACK IT UP; \ secrets are unrecoverable without it", key_path.display() ); } let key = FileKey::load(&key_path).map_err(|e| format!("key load failed: {e}"))?; let pool = tc_db::connect(&database_url, 5) .await .map_err(|e| format!("database connection failed: {e}"))?; println!("teamclaw-broker listening on {}", socket_path.display()); BrokerServer::new(pool, key, socket_path) .serve() .await .map_err(|e| format!("broker failed: {e}")) }