relay_pii/
compiledconfig.rs1use std::cmp::Ordering;
2use std::collections::BTreeSet;
3
4use crate::builtin::BUILTIN_RULES_MAP;
5use crate::{PiiConfig, PiiConfigError, Redaction, RuleSpec, RuleType, SelectorSpec};
6
7#[derive(Debug, Clone)]
12pub struct CompiledPiiConfig {
13 pub(super) applications: Vec<(SelectorSpec, BTreeSet<RuleRef>)>,
14}
15
16impl CompiledPiiConfig {
17 pub fn new(config: &PiiConfig) -> Self {
19 let mut applications = Vec::new();
20 for (selector, rules) in &config.applications {
21 #[allow(clippy::mutable_key_type)]
22 let mut rule_set = BTreeSet::default();
23 for rule_id in rules {
24 collect_rules(config, &mut rule_set, rule_id, None);
25 }
26 applications.push((selector.clone(), rule_set));
27 }
28
29 CompiledPiiConfig { applications }
30 }
31
32 pub fn force_compile(&self) -> Result<(), PiiConfigError> {
36 for rule in self.applications.iter().flat_map(|(_, rules)| rules.iter()) {
37 match &rule.ty {
38 RuleType::Pattern(rule) => {
39 rule.pattern.compiled().map_err(|e| e.clone())?;
40 }
41 RuleType::RedactPair(rule) => {
42 rule.key_pattern.compiled().map_err(|e| e.clone())?;
43 }
44 RuleType::Anything
45 | RuleType::Imei
46 | RuleType::Mac
47 | RuleType::Uuid
48 | RuleType::Email
49 | RuleType::Ip
50 | RuleType::Creditcard
51 | RuleType::Iban
52 | RuleType::Userpath
53 | RuleType::Pemkey
54 | RuleType::UrlAuth
55 | RuleType::UsSsn
56 | RuleType::Password
57 | RuleType::Multiple(_)
58 | RuleType::Alias(_)
59 | RuleType::Unknown(_) => {}
60 }
61 }
62 Ok(())
63 }
64}
65
66fn get_rule(config: &PiiConfig, id: &str) -> Option<RuleRef> {
67 if let Some(spec) = config.rules.get(id) {
68 Some(RuleRef::new(id.to_owned(), spec))
69 } else {
70 BUILTIN_RULES_MAP
71 .get(id)
72 .map(|spec| RuleRef::new(id.to_owned(), spec))
73 }
74}
75
76#[allow(clippy::mutable_key_type)]
77fn collect_rules(
78 config: &PiiConfig,
79 rules: &mut BTreeSet<RuleRef>,
80 rule_id: &str,
81 parent: Option<RuleRef>,
82) {
83 let rule = match get_rule(config, rule_id) {
84 Some(rule) => rule,
85 None => return,
86 };
87
88 if rules.contains(&rule) {
89 return;
90 }
91
92 let rule = match parent {
93 Some(parent) => rule.for_parent(parent),
94 None => rule,
95 };
96
97 match rule.ty {
98 RuleType::Multiple(ref m) => {
99 let parent = if m.hide_inner {
100 Some(rule.clone())
101 } else {
102 None
103 };
104 for rule_id in &m.rules {
105 collect_rules(config, rules, rule_id, parent.clone());
106 }
107 }
108 RuleType::Alias(ref a) => {
109 let parent = if a.hide_inner {
110 Some(rule.clone())
111 } else {
112 None
113 };
114 collect_rules(config, rules, &a.rule, parent);
115 }
116 RuleType::Unknown(_) => {}
117 _ => {
118 rules.insert(rule);
119 }
120 }
121}
122
123#[derive(Debug, Clone)]
125pub(super) struct RuleRef {
126 pub id: String,
127 pub origin: String,
128 pub ty: RuleType,
129 pub redaction: Redaction,
130}
131
132impl RuleRef {
133 fn new(id: String, spec: &RuleSpec) -> Self {
134 RuleRef {
135 origin: id.clone(),
136 id,
137 ty: spec.ty.clone(),
138 redaction: spec.redaction.clone(),
139 }
140 }
141
142 pub fn for_parent(self, parent: Self) -> Self {
143 RuleRef {
144 id: self.id,
145 origin: parent.origin,
146 ty: self.ty,
147 redaction: match parent.redaction {
148 Redaction::Default => self.redaction,
149 _ => parent.redaction,
150 },
151 }
152 }
153}
154
155impl PartialEq for RuleRef {
156 fn eq(&self, other: &Self) -> bool {
157 self.id == other.id
158 }
159}
160
161impl Eq for RuleRef {}
162
163impl PartialOrd for RuleRef {
164 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
165 Some(self.id.cmp(&other.id))
166 }
167}
168
169impl Ord for RuleRef {
170 fn cmp(&self, other: &Self) -> Ordering {
171 self.id.cmp(&other.id)
172 }
173}