use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::command::{ChangeClassification, CommandRecord, ResourceRef}; use crate::session::OperatorIdentity; /// A complete audit event for a command execution. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AuditEvent { pub event_id: Uuid, pub session_id: Uuid, pub operator_identity: OperatorIdentity, pub timestamp: DateTime, pub command: CommandRecord, pub classification: ChangeClassification, pub policy_decision: PolicyDecision, pub execution_result: ExecutionResult, pub target_resources: Vec, pub target_profile_hash: Option, } /// The result of policy evaluation for a command. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PolicyDecision { pub allowed: bool, pub policy_bundle_hash: String, pub accord_version: String, pub evaluation_duration_ms: u32, pub denied_reason: Option, } impl PolicyDecision { /// Create an allow-all stub decision (used in Phase 1 when OPA is not deployed). pub fn allow_all_stub() -> Self { Self { allowed: true, policy_bundle_hash: "stub".into(), accord_version: "none".into(), evaluation_duration_ms: 0, denied_reason: None, } } } /// The result of executing a command. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExecutionResult { pub status: ExecutionStatus, pub summary: String, pub resources_affected: u32, pub mutations_applied: u32, } /// Execution outcome. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ExecutionStatus { Success, Denied, Error, Timeout, } impl ExecutionResult { pub fn success(summary: String) -> Self { Self { status: ExecutionStatus::Success, summary, resources_affected: 0, mutations_applied: 0, } } pub fn denied(reason: String) -> Self { Self { status: ExecutionStatus::Denied, summary: reason, resources_affected: 0, mutations_applied: 0, } } pub fn error(msg: String) -> Self { Self { status: ExecutionStatus::Error, summary: msg, resources_affected: 0, mutations_applied: 0, } } }