use crate::error::SafetyCategory;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SanitizeResult {
Clean(String),
Redacted {
text: String,
redactions: Vec<Redaction>,
},
Blocked {
reason: String,
category: SafetyCategory,
},
}
impl SanitizeResult {
pub fn text(&self) -> Option<&str> {
match self {
SanitizeResult::Clean(text) => Some(text),
SanitizeResult::Redacted { text, .. } => Some(text),
SanitizeResult::Blocked { .. } => None,
}
}
pub fn is_blocked(&self) -> bool {
matches!(self, SanitizeResult::Blocked { .. })
}
pub fn is_modified(&self) -> bool {
matches!(self, SanitizeResult::Redacted { .. })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Redaction {
pub redaction_type: RedactionType,
pub original_hash: String,
pub replacement: String,
pub start: usize,
pub end: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RedactionType {
Ssn,
CreditCard,
Email,
Phone,
IpAddress,
ApiKey,
Password,
OtherPii,
}
impl std::fmt::Display for RedactionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RedactionType::Ssn => write!(f, "SSN"),
RedactionType::CreditCard => write!(f, "Credit Card"),
RedactionType::Email => write!(f, "Email"),
RedactionType::Phone => write!(f, "Phone"),
RedactionType::IpAddress => write!(f, "IP Address"),
RedactionType::ApiKey => write!(f, "API Key"),
RedactionType::Password => write!(f, "Password"),
RedactionType::OtherPii => write!(f, "Other PII"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SafetyLevel {
Safe,
Controversial,
Unsafe,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuardContext {
pub request_id: Uuid,
pub user_id: Option<String>,
pub session_id: Option<String>,
pub timestamp: DateTime<Utc>,
pub source_ip: Option<String>,
pub metadata: serde_json::Value,
}
impl Default for GuardContext {
fn default() -> Self {
Self {
request_id: Uuid::new_v4(),
user_id: None,
session_id: None,
timestamp: Utc::now(),
source_ip: None,
metadata: serde_json::Value::Null,
}
}
}
impl GuardContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_user_id(mut self, user_id: impl Into<String>) -> Self {
self.user_id = Some(user_id.into());
self
}
pub fn with_session_id(mut self, session_id: impl Into<String>) -> Self {
self.session_id = Some(session_id.into());
self
}
pub fn with_source_ip(mut self, ip: impl Into<String>) -> Self {
self.source_ip = Some(ip.into());
self
}
pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
self.metadata = metadata;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
pub context: GuardContext,
pub direction: Direction,
pub content_hash: String,
pub result: AuditResult,
pub processing_time_ms: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Direction {
Input,
Output,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditResult {
Passed,
Redacted { count: usize },
Blocked { category: SafetyCategory },
}