Files
dd0c/products/06-runbook-automation/agent/src/audit.rs

59 lines
1.7 KiB
Rust
Raw Normal View History

use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;
/// Immutable, append-only audit log entry.
/// Every command execution gets logged — no exceptions (BMad must-have).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
pub id: String,
pub tenant_id: String,
pub runbook_id: String,
pub step_index: usize,
pub command: String,
pub safety_level: String,
pub approved_by: Option<String>,
pub approval_method: Option<String>, // "slack_button", "api", "auto" (read-only only)
pub exit_code: Option<i32>,
pub stdout_hash: Option<String>, // SHA-256 of stdout (don't store raw output)
pub stderr_hash: Option<String>,
pub started_at: DateTime<Utc>,
pub completed_at: Option<DateTime<Utc>>,
pub duration_ms: Option<u64>,
pub status: AuditStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditStatus {
Pending,
AwaitingApproval,
Approved,
Rejected,
Executing,
Completed,
Failed,
TimedOut,
}
impl AuditEntry {
pub fn new(tenant_id: &str, runbook_id: &str, step_index: usize, command: &str, safety_level: &str) -> Self {
Self {
id: Uuid::new_v4().to_string(),
tenant_id: tenant_id.to_string(),
runbook_id: runbook_id.to_string(),
step_index,
command: command.to_string(),
safety_level: safety_level.to_string(),
approved_by: None,
approval_method: None,
exit_code: None,
stdout_hash: None,
stderr_hash: None,
started_at: Utc::now(),
completed_at: None,
duration_ms: None,
status: AuditStatus::Pending,
}
}
}