git_lore/lore/
sanitize.rs1use super::LoreAtom;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
4pub struct SanitizationIssue {
5 pub atom_id: String,
6 pub field: String,
7 pub reason: String,
8}
9
10pub fn scan_atoms(atoms: &[LoreAtom]) -> Vec<SanitizationIssue> {
11 let mut issues = Vec::new();
12
13 for atom in atoms {
14 if let Some(reason) = scan_text(&atom.title) {
15 issues.push(SanitizationIssue {
16 atom_id: atom.id.clone(),
17 field: "title".to_string(),
18 reason,
19 });
20 }
21
22 if let Some(body) = atom.body.as_deref() {
23 if let Some(reason) = scan_text(body) {
24 issues.push(SanitizationIssue {
25 atom_id: atom.id.clone(),
26 field: "body".to_string(),
27 reason,
28 });
29 }
30 }
31 }
32
33 issues
34}
35
36pub fn scan_text(text: &str) -> Option<String> {
37 let lowered = text.to_ascii_lowercase();
38
39 let markers = [
40 ("api key", "possible API key disclosure"),
41 ("secret", "possible secret disclosure"),
42 ("token", "possible token disclosure"),
43 ("password", "possible password disclosure"),
44 ("private key", "possible private key disclosure"),
45 ("-----begin", "possible private key block"),
46 ("akia", "possible AWS key disclosure"),
47 ("xoxb-", "possible Slack token disclosure"),
48 ("ghp_", "possible GitHub token disclosure"),
49 ("AIza", "possible Google API key disclosure"),
50 ];
51
52 markers
53 .iter()
54 .find(|(needle, _)| lowered.contains(*needle))
55 .map(|(_, reason)| reason.to_string())
56}