use regex::Regex;
use std::sync::LazyLock;
#[allow(clippy::panic)]
fn compile(tag: &'static str, source: &'static str) -> Regex {
Regex::new(source).unwrap_or_else(|e| {
panic!(
"santh-error::redact: secret pattern `{tag}` failed to compile: {e}. \
Fix: correct the regex source in `redact.rs` for `{tag}`."
)
})
}
static SECRET_PATTERNS: LazyLock<Vec<Regex>> = LazyLock::new(|| {
vec![
compile("aws_access_key", r"AKIA[0-9A-Z]{16}"),
compile("github_pat_classic", r"gh[pousr]_[A-Za-z0-9_]{36,}"),
compile("github_pat_fine", r"github_pat_[A-Za-z0-9_]{22,}"),
compile(
"jwt",
r"eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*",
),
compile("bearer", r"Bearer\s+[A-Za-z0-9_-]+"),
compile("password_kv", r"(?i)password\s*[=:]\s*\S+"),
compile("passwd_kv", r"(?i)passwd\s*[=:]\s*\S+"),
compile("api_key_kv", r"(?i)api[_-]?key\s*[=:]\s*\S+"),
compile("token_kv", r"(?i)token\s*[=:]\s*\S+"),
compile("secret_kv", r"(?i)secret\s*[=:]\s*\S+"),
compile("openai_api_key", r"sk-[a-zA-Z0-9]{20,}"),
compile(
"pem_private_key",
r"-----BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----",
),
]
});
static URL_USERINFO: LazyLock<Regex> =
LazyLock::new(|| compile("url_userinfo", r"://[^/@\s]*:[^/@\s]*@"));
pub fn redact_secrets(input: &str) -> String {
let mut output = input.to_string();
for pattern in SECRET_PATTERNS.iter() {
output = pattern.replace_all(&output, "[REDACTED]").into_owned();
}
output = URL_USERINFO.replace_all(&output, "://***@").into_owned();
output
}