ai_lib_rust/guardrails/
result.rs1use super::config::FilterAction;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum ViolationType {
10 Keyword,
12 Pattern,
14 Pii,
16 Custom,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct Violation {
23 pub violation_type: ViolationType,
25 pub pattern: String,
27 pub action: FilterAction,
29 pub category: Option<String>,
31 pub description: Option<String>,
33 pub matched_text: Option<String>,
35}
36
37impl Violation {
38 pub fn is_blocking(&self) -> bool {
40 matches!(self.action, FilterAction::Block)
41 }
42
43 pub fn is_warning(&self) -> bool {
45 matches!(self.action, FilterAction::Warn)
46 }
47}
48
49#[derive(Debug, Clone, Default, Serialize, Deserialize)]
51pub struct CheckResult {
52 violations: Vec<Violation>,
54 blocked: bool,
56 warned: bool,
58}
59
60impl CheckResult {
61 pub fn passed() -> Self {
63 Self {
64 violations: Vec::new(),
65 blocked: false,
66 warned: false,
67 }
68 }
69
70 pub fn from_violations(violations: Vec<Violation>) -> Self {
72 let blocked = violations.iter().any(|v| v.is_blocking());
73 let warned = violations.iter().any(|v| v.is_warning());
74
75 Self {
76 violations,
77 blocked,
78 warned,
79 }
80 }
81
82 pub fn is_passed(&self) -> bool {
84 !self.blocked && self.violations.is_empty()
85 }
86
87 pub fn is_blocked(&self) -> bool {
89 self.blocked
90 }
91
92 pub fn is_warned(&self) -> bool {
94 self.warned
95 }
96
97 pub fn has_violations(&self) -> bool {
99 !self.violations.is_empty()
100 }
101
102 pub fn violations(&self) -> &[Violation] {
104 &self.violations
105 }
106
107 pub fn blocking_violations(&self) -> Vec<&Violation> {
109 self.violations.iter().filter(|v| v.is_blocking()).collect()
110 }
111
112 pub fn warning_violations(&self) -> Vec<&Violation> {
114 self.violations.iter().filter(|v| v.is_warning()).collect()
115 }
116
117 pub fn merge(mut self, other: CheckResult) -> Self {
119 self.violations.extend(other.violations);
120 self.blocked = self.blocked || other.blocked;
121 self.warned = self.warned || other.warned;
122 self
123 }
124
125 pub fn summary(&self) -> String {
127 if self.is_passed() {
128 "PASSED".to_string()
129 } else if self.is_blocked() {
130 format!("BLOCKED: {} violation(s)", self.violations.len())
131 } else if self.is_warned() {
132 format!("WARNING: {} violation(s)", self.violations.len())
133 } else {
134 format!("INFO: {} item(s) logged", self.violations.len())
135 }
136 }
137}
138
139impl std::fmt::Display for CheckResult {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 write!(f, "{}", self.summary())
142 }
143}