sigil_protocol/scanner.rs
1//! Sensitivity scanning — detect sensitive content before it enters agent context.
2//!
3//! SIGIL defines the trait; implementations choose their detection strategy
4//! (regex, ML-based, dictionary lookup, etc.).
5
6/// Trait for detecting sensitive content in text.
7///
8/// Implementors define their own patterns and detection logic.
9/// The protocol requires only that detected content is categorized
10/// by a human-readable name (e.g., "API Key", "IBAN", "Bank PIN").
11///
12/// # Example
13///
14/// ```rust
15/// use sigil_protocol::SensitivityScanner;
16///
17/// struct RegexScanner { /* ... */ }
18///
19/// impl SensitivityScanner for RegexScanner {
20/// fn scan(&self, text: &str) -> Option<String> {
21/// if text.contains("sk-") {
22/// Some("API Key".to_string())
23/// } else {
24/// None
25/// }
26/// }
27/// }
28/// ```
29pub trait SensitivityScanner: Send + Sync {
30 /// Scan text for sensitive content.
31 ///
32 /// Returns `Some(category_name)` if sensitive content is detected,
33 /// or `None` if the text is safe.
34 ///
35 /// The category name is used in audit logs and vault metadata.
36 fn scan(&self, text: &str) -> Option<String>;
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 struct MockScanner;
44
45 impl SensitivityScanner for MockScanner {
46 fn scan(&self, text: &str) -> Option<String> {
47 if text.contains("SECRET") {
48 Some("Test Secret".to_string())
49 } else {
50 None
51 }
52 }
53 }
54
55 #[test]
56 fn scanner_detects_sensitive_content() {
57 let scanner = MockScanner;
58 assert_eq!(
59 scanner.scan("Contains SECRET data"),
60 Some("Test Secret".to_string())
61 );
62 }
63
64 #[test]
65 fn scanner_passes_safe_content() {
66 let scanner = MockScanner;
67 assert!(scanner.scan("This is totally safe").is_none());
68 }
69}