docs: Enhance MONOREPO_CONVERSION_PLAN.md with improved details
- Specify production-ready implementation details for sal-git package. - Add a detailed code review and quality assurance process section. - Include comprehensive success metrics and validation checklists for production readiness. - Improve security considerations and risk mitigation strategies. - Add stricter code review criteria based on sal-git's conversion. - Update README with security configurations and environment variables.
This commit is contained in:
197
git/tests/git_executor_security_tests.rs
Normal file
197
git/tests/git_executor_security_tests.rs
Normal file
@@ -0,0 +1,197 @@
|
||||
use sal_git::*;
|
||||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn test_git_executor_initialization() {
|
||||
let mut executor = GitExecutor::new();
|
||||
|
||||
// Test that executor can be initialized without panicking
|
||||
// Even if Redis is not available, init should handle it gracefully
|
||||
let result = executor.init();
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"GitExecutor init should handle Redis unavailability gracefully"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_redis_connection_fallback() {
|
||||
// Test that GitExecutor handles Redis connection failures gracefully
|
||||
// Set an invalid Redis URL to force connection failure
|
||||
env::set_var("REDIS_URL", "redis://invalid-host:9999/0");
|
||||
|
||||
let mut executor = GitExecutor::new();
|
||||
let result = executor.init();
|
||||
|
||||
// Should succeed even with invalid Redis URL (graceful fallback)
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"GitExecutor should handle Redis connection failures gracefully"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
env::remove_var("REDIS_URL");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_environment_variable_precedence() {
|
||||
// Test REDIS_URL takes precedence over SAL_REDIS_URL
|
||||
env::set_var("REDIS_URL", "redis://primary:6379/0");
|
||||
env::set_var("SAL_REDIS_URL", "redis://fallback:6379/1");
|
||||
|
||||
// Create executor - should use REDIS_URL (primary)
|
||||
let mut executor = GitExecutor::new();
|
||||
let result = executor.init();
|
||||
|
||||
// Should succeed (even if connection fails, init handles it gracefully)
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"GitExecutor should handle environment variables correctly"
|
||||
);
|
||||
|
||||
// Test with only SAL_REDIS_URL
|
||||
env::remove_var("REDIS_URL");
|
||||
let mut executor2 = GitExecutor::new();
|
||||
let result2 = executor2.init();
|
||||
assert!(
|
||||
result2.is_ok(),
|
||||
"GitExecutor should use SAL_REDIS_URL as fallback"
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
env::remove_var("SAL_REDIS_URL");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_git_command_argument_validation() {
|
||||
let executor = GitExecutor::new();
|
||||
|
||||
// Test with empty arguments
|
||||
let result = executor.execute(&[]);
|
||||
assert!(result.is_err(), "Empty git command should fail");
|
||||
|
||||
// Test with invalid git command
|
||||
let result = executor.execute(&["invalid-command"]);
|
||||
assert!(result.is_err(), "Invalid git command should fail");
|
||||
|
||||
// Test with malformed URL (should fail due to URL validation, not injection)
|
||||
let result = executor.execute(&["clone", "not-a-url"]);
|
||||
assert!(result.is_err(), "Invalid URL should be rejected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_git_executor_with_valid_commands() {
|
||||
let executor = GitExecutor::new();
|
||||
|
||||
// Test git version command (should work if git is available)
|
||||
let result = executor.execute(&["--version"]);
|
||||
|
||||
match result {
|
||||
Ok(output) => {
|
||||
// If git is available, version should be in output
|
||||
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
output_str.contains("git version"),
|
||||
"Git version output should contain 'git version'"
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
// If git is not available, that's acceptable in test environment
|
||||
println!("Note: Git not available in test environment");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_credential_helper_environment_setup() {
|
||||
use std::process::Command;
|
||||
|
||||
// Test that we can create and execute a simple credential helper script
|
||||
let temp_dir = std::env::temp_dir();
|
||||
let helper_script = temp_dir.join("test_git_helper");
|
||||
|
||||
// Create a test credential helper script
|
||||
let script_content = "#!/bin/bash\necho username=testuser\necho password=testpass\n";
|
||||
|
||||
// Write the helper script
|
||||
let write_result = std::fs::write(&helper_script, script_content);
|
||||
assert!(
|
||||
write_result.is_ok(),
|
||||
"Should be able to write credential helper script"
|
||||
);
|
||||
|
||||
// Make it executable (Unix only)
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mut perms = std::fs::metadata(&helper_script).unwrap().permissions();
|
||||
perms.set_mode(0o755);
|
||||
let perm_result = std::fs::set_permissions(&helper_script, perms);
|
||||
assert!(
|
||||
perm_result.is_ok(),
|
||||
"Should be able to set script permissions"
|
||||
);
|
||||
}
|
||||
|
||||
// Test that the script can be executed
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let output = Command::new(&helper_script).output();
|
||||
match output {
|
||||
Ok(output) => {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(
|
||||
stdout.contains("username=testuser"),
|
||||
"Script should output username"
|
||||
);
|
||||
assert!(
|
||||
stdout.contains("password=testpass"),
|
||||
"Script should output password"
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Note: Could not execute credential helper script (shell not available)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
let _ = std::fs::remove_file(&helper_script);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_redis_url_masking() {
|
||||
// Test that sensitive Redis URLs are properly masked for logging
|
||||
// This tests the internal URL masking functionality
|
||||
|
||||
// Test URLs with passwords
|
||||
let test_cases = vec![
|
||||
("redis://user:password@localhost:6379/0", true),
|
||||
("redis://localhost:6379/0", false),
|
||||
("redis://user@localhost:6379/0", false),
|
||||
("invalid-url", false),
|
||||
];
|
||||
|
||||
for (url, has_password) in test_cases {
|
||||
// Set the Redis URL and create executor
|
||||
std::env::set_var("REDIS_URL", url);
|
||||
|
||||
let mut executor = GitExecutor::new();
|
||||
let result = executor.init();
|
||||
|
||||
// Should always succeed (graceful handling of connection failures)
|
||||
assert!(result.is_ok(), "GitExecutor should handle URL: {}", url);
|
||||
|
||||
// The actual masking happens internally during logging
|
||||
// We can't easily test the log output, but we verify the executor handles it
|
||||
if has_password {
|
||||
println!(
|
||||
"Note: Tested URL with password (should be masked in logs): {}",
|
||||
url
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
std::env::remove_var("REDIS_URL");
|
||||
}
|
Reference in New Issue
Block a user