Skip to content

Commit 9c84ce9

Browse files
nipunn1313Convex, Inc.
authored and
Convex, Inc.
committed
Redact emails as PII (#25294)
GitOrigin-RevId: 08306106ece8aaf0dd7c4cd35db8ef5d3834d152
1 parent 8db019c commit 9c84ce9

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

crates/common/src/errors.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
borrow::Cow,
23
collections::{
34
btree_map::Entry,
45
BTreeMap,
@@ -37,10 +38,20 @@ use value::{
3738

3839
use crate::metrics::log_errors_reported_total;
3940

40-
/// Regex to match PII where we show the object that doesn't match the
41-
/// validator.
42-
static SCHEMA_VALIDATION_OBJECT_PII: LazyLock<Regex> =
43-
LazyLock::new(|| Regex::new(r"(?s)Object:.*Validator").unwrap());
41+
/// Replacers for PII in errors before reporting to thirdparty services
42+
/// (sentry/datadog)
43+
static PII_REPLACEMENTS: LazyLock<Vec<(Regex, &'static str)>> = LazyLock::new(|| {
44+
vec![
45+
// Regex to match PII where we show the object that doesn't match the
46+
// validator.
47+
(Regex::new(r"(?s)Object:.*Validator").unwrap(), "Validator"),
48+
// Regex to match emails
49+
(
50+
Regex::new(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b").unwrap(),
51+
"*****@*****.***",
52+
),
53+
]
54+
});
4455

4556
/// Return Result<(), MainError> from main functions to report returned errors
4657
/// to Sentry.
@@ -63,9 +74,12 @@ impl std::fmt::Debug for MainError {
6374

6475
fn strip_pii(err: &mut anyhow::Error) {
6576
if let Some(error_metadata) = err.downcast_mut::<ErrorMetadata>() {
66-
let stripped_msg =
67-
SCHEMA_VALIDATION_OBJECT_PII.replace_all(&error_metadata.msg, "Validator");
68-
error_metadata.msg = stripped_msg.to_string().into();
77+
for (regex, replacement) in PII_REPLACEMENTS.iter() {
78+
match regex.replace_all(&error_metadata.msg, *replacement) {
79+
Cow::Borrowed(b) if b == error_metadata.msg => (),
80+
cow => error_metadata.msg = Cow::Owned(cow.into_owned()),
81+
}
82+
}
6983
}
7084
}
7185

@@ -654,7 +668,7 @@ mod tests {
654668
}
655669

656670
#[test]
657-
fn test_strip_pii() -> anyhow::Result<()> {
671+
fn test_strip_pii_obj() -> anyhow::Result<()> {
658672
let object = obj!("foo" => "bar")?;
659673
let validation_error = ValidationError::ExtraField {
660674
object: object.clone(),
@@ -678,6 +692,17 @@ mod tests {
678692
Ok(())
679693
}
680694

695+
#[test]
696+
fn test_strip_pii_email() -> anyhow::Result<()> {
697+
let mut e = anyhow::anyhow!(ErrorMetadata::bad_request(
698+
"DIY",
699+
"Need DIY advice? Email [email protected]"
700+
));
701+
strip_pii(&mut e);
702+
assert_eq!(e.to_string(), "Need DIY advice? Email *****@*****.***");
703+
Ok(())
704+
}
705+
681706
#[test]
682707
fn test_js_error_conversion_anyhow_macro() -> anyhow::Result<()> {
683708
let js_error = JsError::from_message("Big Error".into());

0 commit comments

Comments
 (0)