#![cfg(test)]
use std::fs;
use std::process::Command;
use tempfile::TempDir;
fn setup_git_repo_with_history() -> TempDir {
let temp_dir = TempDir::new().unwrap();
let repo_path = temp_dir.path();
Command::new("git")
.arg("init")
.current_dir(repo_path)
.status()
.expect("Failed to init git repo");
Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(repo_path)
.status()
.expect("Failed to configure git user name");
Command::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(repo_path)
.status()
.expect("Failed to configure git user email");
fs::write(repo_path.join("file1.txt"), "initial content\n").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.status()
.expect("Failed to git add");
Command::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(repo_path)
.status()
.expect("Failed to create first commit");
fs::write(
repo_path.join("file1.txt"),
"initial content\nmodified line\n",
)
.unwrap();
fs::write(repo_path.join("file2.txt"), "new file content\n").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(repo_path)
.status()
.expect("Failed to git add second commit");
Command::new("git")
.args(["commit", "-m", "Second commit"])
.current_dir(repo_path)
.status()
.expect("Failed to create second commit");
temp_dir
}
#[test]
fn test_get_changed_files_command_injection_vulnerability() {
let repo = setup_git_repo_with_history();
let injection_proof = repo.path().join("injection_test_result.txt");
let malicious_from =
"HEAD~1; echo 'INJECTION_SUCCESSFUL' > injection_test_result.txt; echo HEAD~1";
let result =
context_creator::utils::git::get_changed_files(repo.path(), malicious_from, "HEAD");
if injection_proof.exists() {
let content = fs::read_to_string(&injection_proof).unwrap();
panic!(
"CRITICAL SECURITY VULNERABILITY CONFIRMED: Command injection in get_changed_files succeeded! \
Malicious command created file with content: '{}'",
content.trim()
);
}
match result {
Ok(_) => {
println!("WARNING: get_changed_files accepted malicious input without validation");
println!("Malicious input: {malicious_from}");
}
Err(e) => {
println!("Function failed with error: {e}");
}
}
let malicious_to = "HEAD; echo 'INJECTION_TO_SUCCESSFUL' > injection_to_result.txt; echo HEAD";
let injection_to_proof = repo.path().join("injection_to_result.txt");
let _result =
context_creator::utils::git::get_changed_files(repo.path(), "HEAD~1", malicious_to);
if injection_to_proof.exists() {
let content = fs::read_to_string(&injection_to_proof).unwrap();
panic!(
"CRITICAL SECURITY VULNERABILITY CONFIRMED: Command injection in 'to' parameter succeeded! \
Content: '{}'",
content.trim()
);
}
println!("get_changed_files is vulnerable to command injection - parameters should be validated/escaped");
}
#[test]
fn test_get_diff_stats_command_injection_vulnerability() {
let repo = setup_git_repo_with_history();
let injection_proof = repo.path().join("diff_stats_injection.txt");
let malicious_ref =
"HEAD~1; echo 'DIFF_STATS_INJECTION' > diff_stats_injection.txt; echo HEAD~1";
let result = context_creator::utils::git::get_diff_stats(repo.path(), malicious_ref, "HEAD");
if injection_proof.exists() {
let content = fs::read_to_string(&injection_proof).unwrap();
panic!(
"CRITICAL SECURITY VULNERABILITY: Command injection in get_diff_stats! Content: '{}'",
content.trim()
);
}
println!("Testing get_diff_stats with malicious input: {malicious_ref}");
match result {
Ok(stats) => {
println!("Function returned stats: {stats:?}");
println!("WARNING: get_diff_stats accepted malicious input");
}
Err(e) => {
println!("Function failed: {e}");
}
}
println!(
"get_diff_stats is vulnerable to command injection - git references should be validated"
);
}
#[test]
fn test_get_repository_root_command_injection_through_path() {
let repo = setup_git_repo_with_history();
let result = context_creator::utils::git::get_repository_root(repo.path());
match result {
Ok(root) => {
println!("Repository root: {root:?}");
}
Err(e) => {
println!("get_repository_root failed: {e}");
}
}
println!("get_repository_root should validate path inputs to prevent directory traversal");
}
#[test]
fn test_path_traversal_in_git_output_processing() {
let repo = setup_git_repo_with_history();
let result = context_creator::utils::git::get_changed_files(repo.path(), "HEAD~1", "HEAD");
match result {
Ok(files) => {
println!("Changed files: {files:?}");
for file in &files {
if file.to_string_lossy().contains("..") {
println!("WARNING: Path traversal detected in: {file:?}");
}
}
println!("VULNERABILITY: git.rs:42 joins git output with repo_path without validation");
println!("If git returns '../../../etc/passwd', it would create a dangerous path");
}
Err(e) => {
println!("Function failed: {e}");
}
}
println!("Path joining in get_changed_files should validate git output to prevent traversal");
}
#[test]
fn test_error_message_information_disclosure_in_git_utils() {
let repo = setup_git_repo_with_history();
let result = context_creator::utils::git::get_changed_files(
repo.path(),
"invalid-ref-that-does-not-exist-12345",
"HEAD",
);
match result {
Ok(_) => {
println!("Unexpected success with invalid git ref");
}
Err(e) => {
let error_msg = format!("{e}");
println!("Error message: {error_msg}");
if error_msg.contains("fatal:")
|| error_msg.contains("error:")
|| error_msg.contains(&repo.path().to_string_lossy().to_string())
{
println!("WARNING: Error message may contain sensitive information");
println!("Raw git errors should be sanitized before showing to users");
}
}
}
println!("Error messages should be sanitized to avoid information disclosure");
}