Skip to main content

crue_engine/
decision.rs

1//! Decision Types
2
3use serde::{Deserialize, Serialize};
4
5/// Access decision
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7#[serde(rename_all = "UPPERCASE")]
8pub enum Decision {
9    /// Allow access
10    #[default]
11    Allow,
12    /// Block access
13    Block,
14    /// Allow with warning
15    Warn,
16    /// Require approval
17    ApprovalRequired,
18}
19
20impl std::fmt::Display for Decision {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        match self {
23            Decision::Allow => write!(f, "ALLOW"),
24            Decision::Block => write!(f, "BLOCK"),
25            Decision::Warn => write!(f, "WARN"),
26            Decision::ApprovalRequired => write!(f, "APPROVAL_REQUIRED"),
27        }
28    }
29}
30
31/// Action result from rule
32#[derive(Debug, Clone)]
33pub struct ActionResult {
34    pub decision: Decision,
35    pub error_code: Option<String>,
36    pub message: Option<String>,
37    pub alert_soc: bool,
38}
39
40impl ActionResult {
41    /// Create block result
42    pub fn block(code: &str, message: &str) -> Self {
43        ActionResult {
44            decision: Decision::Block,
45            error_code: Some(code.to_string()),
46            message: Some(message.to_string()),
47            alert_soc: false,
48        }
49    }
50
51    /// Create warning result
52    pub fn warn(code: &str, message: &str) -> Self {
53        ActionResult {
54            decision: Decision::Warn,
55            error_code: Some(code.to_string()),
56            message: Some(message.to_string()),
57            alert_soc: false,
58        }
59    }
60
61    /// Create approval required result
62    pub fn approval_required(code: &str, timeout_minutes: u32) -> Self {
63        ActionResult {
64            decision: Decision::ApprovalRequired,
65            error_code: Some(code.to_string()),
66            message: Some(format!(
67                "Approval required within {} minutes",
68                timeout_minutes
69            )),
70            alert_soc: false,
71        }
72    }
73
74    /// Create allow result
75    pub fn allow() -> Self {
76        ActionResult {
77            decision: Decision::Allow,
78            error_code: None,
79            message: None,
80            alert_soc: false,
81        }
82    }
83
84    /// Add SOC alert
85    pub fn with_soc_alert(mut self) -> Self {
86        self.alert_soc = true;
87        self
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_decision_display() {
97        assert_eq!(format!("{}", Decision::Allow), "ALLOW");
98        assert_eq!(format!("{}", Decision::Block), "BLOCK");
99    }
100
101    #[test]
102    fn test_action_result() {
103        let result = ActionResult::block("VOLUME_EXCEEDED", "Quota dépassé");
104        assert_eq!(result.decision, Decision::Block);
105        assert_eq!(result.error_code, Some("VOLUME_EXCEEDED".to_string()));
106    }
107}