//! `jclaw-policyd` — the out-of-process JouleClaw policy daemon. //! //! Reads `Request`s from stdin one per line, writes `Response`s to //! stdout one per line. The wire protocol is documented at the crate //! root. //! //! Startup policy: //! //! - If `--policy ` is passed, the daemon loads the policy //! JSON from that path before serving the first request. //! - Otherwise it starts with the empty deny-by-default policy. //! //! Operators upgrade the policy live via the `install_policy` IPC //! request (monotonically increasing version required — see //! `jouleclaw_policy::PolicyError::StalePolicy`). use std::io::{self, BufReader}; use jouleclaw_policy::{InMemoryPolicyEngine, Policy}; use jouleclaw_policy_ipc::PolicyServer; fn main() -> std::io::Result<()> { let policy = parse_args(); let engine = InMemoryPolicyEngine::new(policy); let server = PolicyServer::new(engine); let stdin = io::stdin(); let stdout = io::stdout(); let reader = BufReader::new(stdin.lock()); let mut writer = stdout.lock(); if let Err(e) = server.serve(reader, &mut writer) { eprintln!("jclaw-policyd: {e}"); std::process::exit(1); } Ok(()) } fn parse_args() -> Policy { let mut args = std::env::args().skip(1); // Every arm below returns or exits, so only the first argument is ever // examined; `if let` says that, where a loop implied iteration that // cannot happen. if let Some(arg) = args.next() { match arg.as_str() { "--policy" => { let path = args.next().unwrap_or_else(|| { eprintln!("jclaw-policyd: --policy requires a path"); std::process::exit(2); }); let bytes = match std::fs::read(&path) { Ok(b) => b, Err(e) => { eprintln!("jclaw-policyd: read {path}: {e}"); std::process::exit(1); } }; return match serde_json::from_slice::(&bytes) { Ok(p) => p, Err(e) => { eprintln!("jclaw-policyd: parse {path}: {e}"); std::process::exit(1); } }; } "--help" | "-h" => { println!( "jclaw-policyd — JouleClaw out-of-process policy daemon\n\ usage: jclaw-policyd [--policy ]\n" ); std::process::exit(0); } other => { eprintln!("jclaw-policyd: unknown argument `{other}`"); std::process::exit(2); } } } Policy::empty() }