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::Bearer
57 | RuleType::Password
58 | RuleType::Multiple(_)
59 | RuleType::Alias(_)
60 | RuleType::Unknown(_) => {}
61 }
62 }
63 Ok(())
64 }
65}
66
67fn get_rule(config: &PiiConfig, id: &str) -> Option<RuleRef> {
68 if let Some(spec) = config.rules.get(id) {
69 Some(RuleRef::new(id.to_owned(), spec))
70 } else {
71 BUILTIN_RULES_MAP
72 .get(id)
73 .map(|spec| RuleRef::new(id.to_owned(), spec))
74 }
75}
76
77#[allow(clippy::mutable_key_type)]
78fn collect_rules(
79 config: &PiiConfig,
80 rules: &mut BTreeSet<RuleRef>,
81 rule_id: &str,
82 parent: Option<RuleRef>,
83) {
84 let rule = match get_rule(config, rule_id) {
85 Some(rule) => rule,
86 None => return,
87 };
88
89 if rules.contains(&rule) {
90 return;
91 }
92
93 let rule = match parent {
94 Some(parent) => rule.for_parent(parent),
95 None => rule,
96 };
97
98 match rule.ty {
99 RuleType::Multiple(ref m) => {
100 let parent = if m.hide_inner {
101 Some(rule.clone())
102 } else {
103 None
104 };
105 for rule_id in &m.rules {
106 collect_rules(config, rules, rule_id, parent.clone());
107 }
108 }
109 RuleType::Alias(ref a) => {
110 let parent = if a.hide_inner {
111 Some(rule.clone())
112 } else {
113 None
114 };
115 collect_rules(config, rules, &a.rule, parent);
116 }
117 RuleType::Unknown(_) => {}
118 _ => {
119 rules.insert(rule);
120 }
121 }
122}
123
124#[derive(Debug, Clone)]
126pub(super) struct RuleRef {
127 pub id: String,
128 pub origin: String,
129 pub ty: RuleType,
130 pub redaction: Redaction,
131}
132
133impl RuleRef {
134 fn new(id: String, spec: &RuleSpec) -> Self {
135 RuleRef {
136 origin: id.clone(),
137 id,
138 ty: spec.ty.clone(),
139 redaction: spec.redaction.clone(),
140 }
141 }
142
143 pub fn for_parent(self, parent: Self) -> Self {
144 RuleRef {
145 id: self.id,
146 origin: parent.origin,
147 ty: self.ty,
148 redaction: match parent.redaction {
149 Redaction::Default => self.redaction,
150 _ => parent.redaction,
151 },
152 }
153 }
154}
155
156impl PartialEq for RuleRef {
157 fn eq(&self, other: &Self) -> bool {
158 self.id == other.id
159 }
160}
161
162impl Eq for RuleRef {}
163
164impl PartialOrd for RuleRef {
165 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
166 Some(self.cmp(other))
167 }
168}
169
170impl Ord for RuleRef {
171 fn cmp(&self, other: &Self) -> Ordering {
172 self.id.cmp(&other.id)
173 }
174}