dd_sds/scanner/
suppression.rs1use ahash::AHashSet;
2use serde::{Deserialize, Serialize};
3use serde_with::serde_as;
4
5#[serde_as]
6#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
7pub struct Suppressions {
8 #[serde(default)]
9 pub starts_with: Vec<String>,
10 #[serde(default)]
11 pub ends_with: Vec<String>,
12 #[serde(default)]
13 pub exact_match: Vec<String>,
14}
15
16pub struct CompiledSuppressions {
17 pub starts_with: Vec<String>,
18 pub ends_with: Vec<String>,
19 pub exact_match: AHashSet<String>,
20}
21
22impl CompiledSuppressions {
23 pub fn should_match_be_suppressed(&self, match_content: &str) -> bool {
24 if self.exact_match.contains(match_content) {
25 return true;
26 }
27 if self
28 .starts_with
29 .iter()
30 .any(|start| match_content.starts_with(start))
31 {
32 return true;
33 }
34 if self
35 .ends_with
36 .iter()
37 .any(|end| match_content.ends_with(end))
38 {
39 return true;
40 }
41 false
42 }
43}
44
45impl From<Suppressions> for CompiledSuppressions {
46 fn from(config: Suppressions) -> Self {
47 Self {
48 starts_with: config.starts_with,
49 ends_with: config.ends_with,
50 exact_match: config.exact_match.into_iter().collect(),
51 }
52 }
53}
54
55#[cfg(test)]
56mod test {
57
58 use super::*;
59
60 #[test]
61 fn test_suppression_correctly_suppresses_correctly() {
62 let config = Suppressions {
63 starts_with: vec!["mary".to_string()],
64 ends_with: vec!["@datadoghq.com".to_string()],
65 exact_match: vec!["nathan@yahoo.com".to_string()],
66 };
67 let compiled_config = CompiledSuppressions::from(config);
68 assert!(compiled_config.should_match_be_suppressed("mary@datadoghq.com"));
69 assert!(compiled_config.should_match_be_suppressed("nathan@yahoo.com"));
70 assert!(compiled_config.should_match_be_suppressed("john@datadoghq.com"));
71 assert!(!compiled_config.should_match_be_suppressed("john@yahoo.com"));
72 assert!(!compiled_config.should_match_be_suppressed("john mary john"));
73 assert!(compiled_config.should_match_be_suppressed("mary john john"));
74 }
75}