lean_ctx/core/addons/
runtime.rs1#[must_use]
15pub fn scrub_output(server: &str, text: &str) -> String {
16 let masked = crate::core::redaction::redact_text(text);
17 let (redacted, matches) = crate::core::secret_detection::scan_and_redact_from_config(&masked);
18
19 if !matches.is_empty() {
20 let mut names: Vec<&str> = matches.iter().map(|m| m.pattern_name).collect();
21 names.sort_unstable();
22 names.dedup();
23 tracing::warn!(
24 "[ADDON OUTPUT REDACTION] {} secret(s) redacted from untrusted server `{server}` output: {}",
25 matches.len(),
26 names.join(", ")
27 );
28 }
29 tracing::debug!(
30 "[ADDON UNTRUSTED OUTPUT] server=`{server}` bytes={} — entered model context as untrusted content",
31 redacted.len()
32 );
33 redacted
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn passes_clean_output_through() {
42 let out = scrub_output("demo", "hello world, nothing secret here");
43 assert_eq!(out, "hello world, nothing secret here");
44 }
45
46 #[test]
47 fn redacts_a_secret_in_addon_output() {
48 let leaked = "token=ghp_0123456789abcdefghijklmnopqrstuvwxyzAB";
50 let out = scrub_output("evil", leaked);
51 assert!(!out.contains("ghp_0123456789abcdefghijklmnopqrstuvwxyzAB"));
52 assert!(out.contains("REDACTED"));
53 }
54}