1use serde::Serialize;
2use serde_json::Value;
3use std::fs::OpenOptions;
4use std::io::Write;
5use std::path::Path;
6
7#[derive(Serialize)]
8pub struct AuditEvent {
9 pub timestamp: String, pub decision: String, pub tool: Option<String>,
12 pub reason: Option<String>,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub request_id: Option<Value>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub agentic: Option<Value>, }
18
19pub struct AuditLog {
20 file: Option<std::fs::File>,
21}
22
23impl AuditLog {
24 pub fn new(path: Option<&Path>) -> Self {
25 let file = path.and_then(|p| OpenOptions::new().create(true).append(true).open(p).ok());
26 Self { file }
27 }
28
29 pub fn log(&mut self, event: &AuditEvent) {
30 if let Some(f) = &mut self.file {
31 if let Ok(json) = serde_json::to_string(event) {
32 writeln!(f, "{}", json).ok();
33 }
34 }
35 }
36}