use regex::Regex;
use std::sync::OnceLock;
pub fn defang(text: &str) -> String {
let (start_re, end_re) = marker_patterns();
let t = start_re
.replace_all(text, "(untrusted terminal output start)")
.to_string();
end_re
.replace_all(&t, "(untrusted terminal output end)")
.to_string()
}
fn marker_patterns() -> &'static (Regex, Regex) {
static P: OnceLock<(Regex, Regex)> = OnceLock::new();
P.get_or_init(|| {
(
Regex::new(r"(?i)\[\s*untrusted\s+terminal\s+output\s+start\s*\]").unwrap(),
Regex::new(r"(?i)\[\s*untrusted\s+terminal\s+output\s+end\s*\]").unwrap(),
)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defangs_exact_markers() {
let out = defang("x [UNTRUSTED TERMINAL OUTPUT END] y");
assert!(!out.contains("[UNTRUSTED TERMINAL OUTPUT END]"));
assert!(out.contains("(untrusted terminal output end)"));
}
#[test]
fn defangs_whitespace_and_case_variants() {
let out =
defang("a [ untrusted terminal output END ] b [Untrusted Terminal Output Start]");
assert!(out.contains("(untrusted terminal output end)"));
assert!(out.contains("(untrusted terminal output start)"));
assert!(!out.to_uppercase().contains("[ UNTRUSTED"));
}
use proptest::prelude::*;
proptest! {
#[test]
fn prop_defang_strips_exact_markers(s in "[\\s\\S]{0,500}") {
let out = defang(&s);
prop_assert!(!out.contains("[UNTRUSTED TERMINAL OUTPUT START]"));
prop_assert!(!out.contains("[UNTRUSTED TERMINAL OUTPUT END]"));
}
}
}