use super::config::FilterAction;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ViolationType {
Keyword,
Pattern,
Pii,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Violation {
pub violation_type: ViolationType,
pub pattern: String,
pub action: FilterAction,
pub category: Option<String>,
pub description: Option<String>,
pub matched_text: Option<String>,
}
impl Violation {
pub fn is_blocking(&self) -> bool {
matches!(self.action, FilterAction::Block)
}
pub fn is_warning(&self) -> bool {
matches!(self.action, FilterAction::Warn)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CheckResult {
violations: Vec<Violation>,
blocked: bool,
warned: bool,
}
impl CheckResult {
pub fn passed() -> Self {
Self {
violations: Vec::new(),
blocked: false,
warned: false,
}
}
pub fn from_violations(violations: Vec<Violation>) -> Self {
let blocked = violations.iter().any(|v| v.is_blocking());
let warned = violations.iter().any(|v| v.is_warning());
Self {
violations,
blocked,
warned,
}
}
pub fn is_passed(&self) -> bool {
!self.blocked && self.violations.is_empty()
}
pub fn is_blocked(&self) -> bool {
self.blocked
}
pub fn is_warned(&self) -> bool {
self.warned
}
pub fn has_violations(&self) -> bool {
!self.violations.is_empty()
}
pub fn violations(&self) -> &[Violation] {
&self.violations
}
pub fn blocking_violations(&self) -> Vec<&Violation> {
self.violations.iter().filter(|v| v.is_blocking()).collect()
}
pub fn warning_violations(&self) -> Vec<&Violation> {
self.violations.iter().filter(|v| v.is_warning()).collect()
}
pub fn merge(mut self, other: CheckResult) -> Self {
self.violations.extend(other.violations);
self.blocked = self.blocked || other.blocked;
self.warned = self.warned || other.warned;
self
}
pub fn summary(&self) -> String {
if self.is_passed() {
"PASSED".to_string()
} else if self.is_blocked() {
format!("BLOCKED: {} violation(s)", self.violations.len())
} else if self.is_warned() {
format!("WARNING: {} violation(s)", self.violations.len())
} else {
format!("INFO: {} item(s) logged", self.violations.len())
}
}
}
impl std::fmt::Display for CheckResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.summary())
}
}