mod config;
#[cfg(feature = "git")]
mod client;
#[cfg(feature = "git")]
mod cmd;
pub use config::GitConfig;
#[cfg(feature = "git")]
pub use client::GitClient;
#[cfg(feature = "git")]
pub use cmd::Git;
#[cfg(any(feature = "git", test))]
pub(crate) fn sanitize_git_output(s: &str) -> String {
use regex::Regex;
use std::sync::LazyLock;
static ANSI_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\x1b\[[0-9;]*[a-zA-Z]|\x1b\][^\x07]*\x07|\x1b[^\[\]].?")
.expect("ANSI regex is valid")
});
let stripped = ANSI_RE.replace_all(s, "");
stripped
.chars()
.filter(|&ch| {
if ch == '\t' || ch == '\n' || ch == '\r' {
return true;
}
if (ch as u32) <= 0x1f {
return false;
}
if ch as u32 == 0x7f {
return false;
}
if (0x80..=0x9f).contains(&(ch as u32)) {
return false;
}
true
})
.collect()
}
#[cfg(test)]
mod tests {
use super::sanitize_git_output;
#[test]
fn test_strips_ansi_escape_sequences() {
let input = "main\x1b[31mPWNED\x1b[0m";
assert_eq!(sanitize_git_output(input), "mainPWNED");
}
#[test]
fn test_strips_null_bytes() {
let input = "hello\x00world";
assert_eq!(sanitize_git_output(input), "helloworld");
}
#[test]
fn test_strips_c0_control_chars() {
let input = "a\x01b\x02c\x07d\x08e";
assert_eq!(sanitize_git_output(input), "abcde");
}
#[test]
fn test_preserves_tab_newline_cr() {
let input = "line1\n\tindented\r\nline2";
assert_eq!(sanitize_git_output(input), "line1\n\tindented\r\nline2");
}
#[test]
fn test_strips_c1_control_chars() {
let input = format!("a{}b{}c{}d", '\u{0080}', '\u{009b}', '\u{009f}');
assert_eq!(sanitize_git_output(&input), "abcd");
}
#[test]
fn test_strips_del() {
let input = "hello\x7fworld";
assert_eq!(sanitize_git_output(input), "helloworld");
}
#[test]
fn test_complex_ansi_injection() {
let input = "\x1b[2J\x1b[Hfake-prompt$ rm -rf /\x1b[0m";
assert_eq!(sanitize_git_output(input), "fake-prompt$ rm -rf /");
}
#[test]
fn test_passthrough_normal_text() {
let input = "feature/my-branch-123";
assert_eq!(sanitize_git_output(input), "feature/my-branch-123");
}
#[test]
fn test_unicode_preserved() {
let input = "日本語ブランチ";
assert_eq!(sanitize_git_output(input), "日本語ブランチ");
}
}