use fd_core::{PolicyDecisionId, PolicyRuleId};
use serde::{Deserialize, Serialize};
use crate::trace::DecisionTrace;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyDecision {
pub id: PolicyDecisionId,
pub kind: PolicyDecisionKind,
pub reason: String,
pub rule_id: Option<PolicyRuleId>,
#[serde(default)]
pub metadata: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace: Option<DecisionTrace>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PolicyDecisionKind {
Allow,
Deny,
RequiresApproval,
AllowWithWarning,
}
impl PolicyDecision {
pub fn allow(reason: impl Into<String>) -> Self {
Self {
id: PolicyDecisionId::new(),
kind: PolicyDecisionKind::Allow,
reason: reason.into(),
rule_id: None,
metadata: serde_json::Value::Null,
trace: None,
}
}
pub fn deny(reason: impl Into<String>) -> Self {
Self {
id: PolicyDecisionId::new(),
kind: PolicyDecisionKind::Deny,
reason: reason.into(),
rule_id: None,
metadata: serde_json::Value::Null,
trace: None,
}
}
pub fn requires_approval(reason: impl Into<String>) -> Self {
Self {
id: PolicyDecisionId::new(),
kind: PolicyDecisionKind::RequiresApproval,
reason: reason.into(),
rule_id: None,
metadata: serde_json::Value::Null,
trace: None,
}
}
pub fn with_rule(mut self, rule_id: PolicyRuleId) -> Self {
self.rule_id = Some(rule_id);
self
}
pub fn with_trace(mut self, trace: DecisionTrace) -> Self {
self.trace = Some(trace);
self
}
pub fn is_allowed(&self) -> bool {
matches!(
self.kind,
PolicyDecisionKind::Allow | PolicyDecisionKind::AllowWithWarning
)
}
pub fn is_denied(&self) -> bool {
matches!(self.kind, PolicyDecisionKind::Deny)
}
pub fn needs_approval(&self) -> bool {
matches!(self.kind, PolicyDecisionKind::RequiresApproval)
}
}