llm_edge_security/
pii.rs

1//! PII detection and redaction
2
3use regex::Regex;
4
5/// PII redactor that removes sensitive information
6pub struct PIIRedactor {
7    ssn_regex: Regex,
8    email_regex: Regex,
9    credit_card_regex: Regex,
10}
11
12impl Default for PIIRedactor {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl PIIRedactor {
19    pub fn new() -> Self {
20        Self {
21            ssn_regex: Regex::new(r"\b\d{3}-\d{2}-\d{4}\b").unwrap(),
22            email_regex: Regex::new(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")
23                .unwrap(),
24            credit_card_regex: Regex::new(r"\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b").unwrap(),
25        }
26    }
27
28    /// Redacts PII from text
29    pub fn redact(&self, text: &str) -> String {
30        let mut result = text.to_string();
31
32        // Redact SSN
33        result = self
34            .ssn_regex
35            .replace_all(&result, "[SSN_REDACTED]")
36            .to_string();
37
38        // Redact email
39        result = self
40            .email_regex
41            .replace_all(&result, "[EMAIL_REDACTED]")
42            .to_string();
43
44        // Redact credit card
45        result = self
46            .credit_card_regex
47            .replace_all(&result, "[CC_REDACTED]")
48            .to_string();
49
50        result
51    }
52
53    /// Detects if text contains PII
54    pub fn contains_pii(&self, text: &str) -> bool {
55        self.ssn_regex.is_match(text)
56            || self.email_regex.is_match(text)
57            || self.credit_card_regex.is_match(text)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_pii_redaction() {
67        let redactor = PIIRedactor::new();
68
69        let text = "My SSN is 123-45-6789 and email is test@example.com";
70        let redacted = redactor.redact(text);
71
72        assert!(redacted.contains("[SSN_REDACTED]"));
73        assert!(redacted.contains("[EMAIL_REDACTED]"));
74        assert!(!redacted.contains("123-45-6789"));
75        assert!(!redacted.contains("test@example.com"));
76    }
77
78    #[test]
79    fn test_pii_detection() {
80        let redactor = PIIRedactor::new();
81
82        assert!(redactor.contains_pii("My SSN is 123-45-6789"));
83        assert!(redactor.contains_pii("Email: test@example.com"));
84        assert!(!redactor.contains_pii("No PII here"));
85    }
86}