use super::{Verdict, VerdictResponse};
impl VerdictResponse {
pub fn allow(event_id: String, latency_ms: f64) -> Self {
Self::with_verdict(Verdict::Allow, event_id, latency_ms)
}
pub fn approve(event_id: String, latency_ms: f64) -> Self {
Self::with_verdict(Verdict::Approve, event_id, latency_ms)
}
pub fn deny(
event_id: String,
latency_ms: f64,
reason: Option<String>,
severity: Option<String>,
rule_id: Option<String>,
) -> Self {
Self {
reason,
severity,
rule_id,
..Self::with_verdict(Verdict::Deny, event_id, latency_ms)
}
}
fn with_verdict(verdict: Verdict, event_id: String, latency_ms: f64) -> Self {
Self {
schema_version: "1.0".to_string(),
verdict,
event_id,
latency_ms,
reason: None,
severity: None,
threat_category: None,
rule_id: None,
details_url: None,
offline: false,
context: None,
}
}
}
pub fn new_event_id() -> String {
format!("evt_{}", uuid::Uuid::now_v7())
}
pub fn current_timestamp() -> String {
chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
}
pub fn current_time_utc() -> chrono::DateTime<chrono::Utc> {
chrono::Utc::now()
}
pub fn os_string() -> &'static str {
std::env::consts::OS
}
pub fn arch_string() -> &'static str {
std::env::consts::ARCH
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deny_carries_the_deciding_rules_fields() {
let r = VerdictResponse::deny(
"evt_1".to_string(),
1.5,
Some("Canary enforce".to_string()),
Some("high".to_string()),
Some("OL-CMD-ENF".to_string()),
);
assert_eq!(r.verdict, Verdict::Deny);
assert_eq!(r.reason.as_deref(), Some("Canary enforce"));
assert_eq!(r.severity.as_deref(), Some("high"));
assert_eq!(r.rule_id.as_deref(), Some("OL-CMD-ENF"));
assert_eq!(r.schema_version, "1.0");
assert!(r.context.is_none());
assert!(!r.offline);
}
#[test]
fn allow_and_approve_leave_the_policy_fields_empty() {
for r in [
VerdictResponse::allow("evt_1".to_string(), 0.0),
VerdictResponse::approve("evt_1".to_string(), 0.0),
] {
assert!(r.reason.is_none());
assert!(r.severity.is_none());
assert!(r.rule_id.is_none());
}
}
}