qubit_redact/policy/field/
redaction_floor.rs1use std::fmt;
11use std::sync::Arc;
12use std::sync::LazyLock;
13
14use super::FieldNameMatching;
15use super::RedactionFloorBuilder;
16use super::SensitiveFieldPreset;
17use super::SensitiveFieldRule;
18use super::UnknownFieldPolicy;
19use crate::policy::internal::RedactionPolicyInner;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct RedactionFloor {
40 pub(crate) inner: Arc<RedactionPolicyInner>,
42}
43
44static STANDARD_FLOOR: LazyLock<RedactionFloor> = LazyLock::new(|| {
46 let mut builder = RedactionFloor::builder();
47 for preset in [
48 SensitiveFieldPreset::Credentials,
49 SensitiveFieldPreset::CredentialContainers,
50 SensitiveFieldPreset::AuthTokens,
51 SensitiveFieldPreset::Http,
52 SensitiveFieldPreset::Session,
53 ] {
54 builder = builder.include_preset(preset);
55 }
56 for &(field, level) in super::super::redaction_policy::STANDARD_EXTRA_FIELDS {
57 builder = builder
58 .raise(field, level)
59 .expect("built-in standard floor fields must be valid");
60 }
61 builder.build().expect("the built-in redaction floor is valid")
62});
63
64impl RedactionFloor {
65 #[must_use]
67 #[inline(always)]
68 pub fn standard() -> Self {
69 STANDARD_FLOOR.clone()
70 }
71
72 #[must_use]
74 #[inline(always)]
75 pub fn builder() -> RedactionFloorBuilder {
76 RedactionFloorBuilder::empty()
77 }
78
79 pub fn sensitive_rules(&self) -> impl Iterator<Item = SensitiveFieldRule<'_>> {
81 self.inner
82 .sensitive
83 .iter()
84 .map(|(field, level)| SensitiveFieldRule::new(field, *level))
85 }
86
87 #[must_use]
89 #[inline(always)]
90 pub fn to_builder(&self) -> RedactionFloorBuilder {
91 RedactionFloorBuilder::from_floor(self)
92 }
93
94 #[must_use]
98 pub(crate) fn combine(&self, other: &Self) -> Self {
99 let mut sensitive = self.inner.sensitive.clone();
100 for (field, level) in &other.inner.sensitive {
101 sensitive
102 .entry(field.clone())
103 .and_modify(|current| *current = (*current).max(*level))
104 .or_insert(*level);
105 }
106 let unknown = match (
107 self.inner.unknown_field_policy.sensitivity(),
108 other.inner.unknown_field_policy.sensitivity(),
109 ) {
110 (Some(left), Some(right)) => Some(left.max(right)),
111 (Some(level), None) | (None, Some(level)) => Some(level),
112 (None, None) => None,
113 };
114 let unknown_field_policy = unknown.map_or(UnknownFieldPolicy::PassThrough, UnknownFieldPolicy::Redact);
115 Self {
116 inner: std::sync::Arc::new(RedactionPolicyInner {
117 sensitive,
118 allow_exact: Default::default(),
119 allow_suffix: Default::default(),
120 matching: if self.inner.matching == FieldNameMatching::ExactOrTokenSuffix
121 || other.inner.matching == FieldNameMatching::ExactOrTokenSuffix
122 {
123 FieldNameMatching::ExactOrTokenSuffix
124 } else {
125 FieldNameMatching::Exact
126 },
127 unknown_field_policy,
128 }),
129 }
130 }
131}
132
133impl Default for RedactionFloor {
134 #[inline(always)]
136 fn default() -> Self {
137 Self::standard()
138 }
139}
140
141impl fmt::Display for RedactionFloor {
142 #[inline(always)]
145 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
146 formatter.write_str("RedactionFloor")
147 }
148}