pub fn secret_class(line: &str) -> Option<&'static str> {
let lower = line.to_ascii_lowercase();
if lower.contains("kernel command line") || lower.contains("/proc/cmdline") || lower.contains("korp.args") || lower.contains("korp.log_udp=") || lower.contains("korp.env.") || lower.contains("clock_key=") {
return Some("cmdline");
}
if lower.contains("token") || lower.contains("bearer ") || lower.contains("password") || lower.contains("secret") || stripe_secret(&lower) {
return Some("token");
}
if lower.contains("private key") || lower.contains("begin openssh") || lower.contains("ssh-ed25519") || lower.contains("ssh-rsa") || lower.contains("signing.key") || lower.contains("time_ed25519") {
return Some("key");
}
if lower.contains("pubkey") || lower.contains("public key") || lower.contains("sha256:") {
return Some("pubkey");
}
if lower.contains(".env") {
return Some("env");
}
if has_env_record(line) {
return Some("envrecord");
}
if longest_opaque_run(line) >= 40 {
return Some("highentropy");
}
None
}
fn stripe_secret(lower: &str) -> bool {
["sk_live_", "sk_test_", "rk_live_", "rk_test_", "whsec_"].iter().any(|p| lower.contains(p))
}
fn has_env_record(line: &str) -> bool {
line.split_whitespace().any(|tok| {
let Some((name, value)) = tok.split_once('=') else { return false };
!value.is_empty() && name.len() >= 3 && name.starts_with(|c: char| c.is_ascii_uppercase()) && name.chars().all(|c| c.is_ascii_uppercase() || c.is_ascii_digit() || c == '_')
})
}
fn longest_opaque_run(line: &str) -> usize {
let mut best = 0usize;
let mut run = 0usize;
for c in line.chars() {
if c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=' {
run += 1;
best = best.max(run);
} else {
run = 0;
}
}
best
}
fn withhold_runs(line: &str) -> String {
let mut out = String::with_capacity(line.len());
let mut run = String::new();
let flush = |run: &mut String, out: &mut String| {
if run.chars().count() >= 40 {
out.push_str(VALUE_WITHHELD);
} else {
out.push_str(run);
}
run.clear();
};
for c in line.chars() {
if c.is_ascii_alphanumeric() || c == '+' || c == '/' || c == '=' {
run.push(c);
} else {
flush(&mut run, &mut out);
out.push(c);
}
}
flush(&mut run, &mut out);
out
}
pub fn withheld(class: &str, bytes: usize) -> String {
format!("<<WITHHELD: a {class}-class line of {bytes} bytes was not recorded>>")
}
pub fn withheld_run(class: &str, count: u64, bytes: u64) -> String {
if count == 1 {
return withheld(class, bytes as usize);
}
format!("<<WITHHELD: {count} {class}-class lines in a row, {bytes} bytes, were not recorded>>")
}
pub const VALUE_WITHHELD: &str = "<withheld>";
pub fn is_marker(line: &str) -> bool {
line.starts_with("<<WITHHELD: ")
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Cleaned<'a> {
Kept(std::borrow::Cow<'a, str>),
Withheld { class: &'static str, bytes: usize },
}
pub fn cleaned(line: &str) -> Cleaned<'_> {
if is_marker(line) {
return Cleaned::Kept(std::borrow::Cow::Borrowed(line));
}
match secret_class(line) {
None => Cleaned::Kept(std::borrow::Cow::Borrowed(line)),
Some("pubkey") => match redact_values(line) {
Some(kept) => Cleaned::Kept(std::borrow::Cow::Owned(kept)),
None => Cleaned::Kept(std::borrow::Cow::Borrowed(line)),
},
Some("highentropy") => Cleaned::Kept(std::borrow::Cow::Owned(withhold_runs(line))),
Some(class) => Cleaned::Withheld { class, bytes: line.len() },
}
}
pub fn clean(line: &str) -> std::borrow::Cow<'_, str> {
match cleaned(line) {
Cleaned::Kept(kept) => kept,
Cleaned::Withheld { class, bytes } => std::borrow::Cow::Owned(withheld(class, bytes)),
}
}
pub fn clean_lines<'a, I: IntoIterator<Item = &'a str>>(lines: I) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
let mut run: Option<(&'static str, u64, u64)> = None;
for line in lines {
match cleaned(line) {
Cleaned::Kept(kept) => {
out.push(kept.into_owned());
run = None;
}
Cleaned::Withheld { class, bytes } => {
if let Some((c, n, b)) = run.as_mut() {
if *c == class {
*n += 1;
*b += bytes as u64;
let text = withheld_run(class, *n, *b);
if let Some(last) = out.last_mut() {
*last = text;
}
continue;
}
}
out.push(withheld(class, bytes));
run = Some((class, 1, bytes as u64));
}
}
}
out
}
fn names_a_key(word: &str) -> bool {
let w = word.to_ascii_lowercase();
w.contains("pubkey") || w.contains("public_key") || w.contains("public-key") || w.contains("fingerprint")
}
fn looks_like_key(value: &str) -> bool {
value.to_ascii_lowercase().contains("sha256:") || longest_opaque_run(value) >= 16
}
fn short_value(word: &str) -> bool {
!word.is_empty()
&& word.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '+' | '/' | '=' | ':'))
&& word.chars().any(|c| c.is_ascii_digit())
}
fn redact_values(line: &str) -> Option<String> {
let words: Vec<&str> = line.split(' ').collect();
let mut out: Vec<String> = Vec::with_capacity(words.len());
let mut after_name = false;
for (i, w) in words.iter().enumerate() {
let word = if *w == VALUE_WITHHELD {
(*w).to_string()
} else if let Some((k, v)) = w.split_once('=') {
let bare = v.trim_matches('"');
if !bare.is_empty() && bare != VALUE_WITHHELD && (names_a_key(k) || looks_like_key(bare)) {
format!("{k}={VALUE_WITHHELD}")
} else {
(*w).to_string()
}
} else if looks_like_key(w) || (after_name && short_value(w)) {
VALUE_WITHHELD.to_string()
} else {
(*w).to_string()
};
let public_key = i > 0 && words[i - 1].eq_ignore_ascii_case("public") && w.eq_ignore_ascii_case("key");
after_name = !w.contains('=') && (names_a_key(w.trim_end_matches(':')) || public_key);
out.push(word);
}
let kept = out.join(" ");
(kept != line).then_some(kept)
}
#[cfg(test)]
mod tests {
#[test]
fn an_opaque_run_is_withheld_in_place_and_its_line_kept() {
let sha = "0123456789abcdef0123456789abcdef01234567";
let l = format!("2026-09-30T07:00:00.1Z ERROR gunnar::store: push rejected for {sha}: object missing");
match cleaned(&l) {
Cleaned::Kept(k) => {
assert!(!k.contains(sha), "{k}");
assert!(k.contains("ERROR gunnar::store: push rejected for <withheld>: object missing"), "{k}");
}
w => panic!("the line was withheld whole: {w:?}"),
}
let digest = "dba8e30fe8af4a881572f52144afa386df347e80f5029066f695810784e751dd";
let reg = format!("2026-09-30T07:00:00.1Z INFO gunnar_server::self_register: plugin: ADDED — gunnar blake3 {digest} event=\"plugin.self_register\"");
let kept = clean(®);
assert!(kept.contains("plugin: ADDED — gunnar blake3 <withheld>") && !kept.contains(digest), "{kept}");
let key = "AAAAC3NzaC1lZDI1NTE5AAAAIGx8r8b4v8v5r7q2Zk1pQ3aQ";
assert!(!clean(&format!("x {key} y")).contains(key));
assert_eq!(clean(&clean(®)), clean(®), "idempotent");
}
use super::*;
#[test]
fn progress_is_kept_and_every_secret_class_is_withheld_without_its_content() {
assert_eq!(clean("korp-start: stage net up at 6.34 s"), "korp-start: stage net up at 6.34 s");
for (line, class) in [
("[ 0.000000] Kernel command line: korp.args=monetize_pubkey=abc", "cmdline"),
("GUNNAR_UI_ADMIN_TOKEN=xyz", "token"),
("-----BEGIN OPENSSH PRIVATE KEY-----", "key"),
("reading /etc/monetize/monetize.env", "env"),
("monetize-server: stripe: POST /v1/checkout/sessions with sk_live_51Habc", "token"),
("monetize-server: hmac key whsec_5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH", "token"),
("monetize-server: vendor key rk_test_abc", "token"),
] {
assert_eq!(secret_class(line), Some(class), "{line}");
let c = clean(line);
assert!(c.starts_with("<<WITHHELD: a ") && c.contains(class) && !c.contains(line), "{c}");
assert_eq!(clean(&c), c, "a marker cleans to itself");
}
let run = "AAAAC3NzaC1lZDI1NTE5AAAAIGx8r8b4v8v5r7q2Zk1pQ3a";
assert_eq!(secret_class(run), Some("highentropy"));
assert_eq!(clean(run), VALUE_WITHHELD);
}
#[test]
fn an_environment_record_is_withheld_and_names_no_value() {
for (line, class) in [
("kmsg 6,368,90210,-;with environment: HOME=/ TERM=linux KORP_INSTALLER_ROOT=/run/installer", "envrecord"),
("kmsg 6,369,90211,-;with environment: MONETIZE_VERIFY_KEY=MCowBQYDK2VwAyEA", "envrecord"),
("box: STRIPE_ACCOUNT=acct_1Qx9 MONETIZE_SEAL=q7Zp2", "envrecord"),
("app @4s korp.env.GUNNAR_DATA_ROOT applied", "cmdline"),
] {
assert_eq!(secret_class(line), Some(class), "{line}");
let c = clean(line);
assert!(c.starts_with("<<WITHHELD: a ") && c.contains(class) && !c.contains("q7Zp2") && !c.contains("MCowBQ"), "{c}");
}
assert_eq!(secret_class(r#"INFO gunnar::audit: served event="grpc.call" decision="allow" elapsed_ms=3"#), None);
assert_eq!(secret_class("HTTP/1.1 200 OK"), None);
}
#[test]
fn a_pubkey_line_is_kept_with_its_values_withheld_in_place() {
let w = VALUE_WITHHELD;
for (line, kept) in [
("fed monetize pubkey eb16".to_string(), format!("fed monetize pubkey {w}")),
(
"WARN gunnar::audit: event=\"ssh.auth.accepted\" fingerprint=SHA256:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU principal=admin".to_string(),
format!("WARN gunnar::audit: event=\"ssh.auth.accepted\" fingerprint={w} principal=admin"),
),
("feed: monetize_pubkey=abc public key 1f2e3d4c".to_string(), format!("feed: monetize_pubkey={w} public key {w}")),
("public key revoked".to_string(), "public key revoked".to_string()),
] {
assert_eq!(secret_class(&line), Some("pubkey"), "{line}");
let c = clean(&line);
assert_eq!(c, kept);
assert_eq!(clean(&c), c, "idempotent: the VM and the installer both clean");
}
}
#[test]
fn a_run_of_withheld_lines_is_one_counted_marker() {
let lines = ["boot", "a token here", "the token again", "reading x.env", "up", "token", "token"];
let out = clean_lines(lines);
assert_eq!(
out,
vec![
"boot".to_string(),
withheld_run("token", 2, 27),
withheld("env", 13),
"up".to_string(),
withheld_run("token", 2, 10),
]
);
assert!(out.iter().all(|l| clean(l) == l.as_str()), "markers clean to themselves");
assert_eq!(withheld_run("key", 1, 7), withheld("key", 7));
}
}