use gamecode_mcp2::tools::ToolManager;
use serde_json::json;
use std::collections::HashMap;
use std::path::PathBuf;
use tempfile::TempDir;
#[tokio::test]
async fn test_path_traversal_prevention() {
let _temp_dir = TempDir::new().unwrap();
let mut tool_manager = ToolManager::new();
let path = PathBuf::from("tests/fixtures/test_tools.yaml");
tool_manager.load_from_file(&path).await.unwrap();
let traversal_attempts = vec![
"../../../etc/passwd",
"../../../../../../etc/shadow",
"/etc/passwd",
"~/.ssh/id_rsa",
];
for attempt in traversal_attempts {
let args = json!({
"path": attempt,
"content": "malicious content"
});
let result = tool_manager.execute_tool("file_writer", args, &HashMap::new()).await;
if result.is_ok() {
println!("WARNING: Path traversal successful with: {}", attempt);
}
}
}
#[tokio::test]
async fn test_command_argument_injection() {
let mut tool_manager = ToolManager::new();
let path = PathBuf::from("tests/fixtures/test_tools.yaml");
tool_manager.load_from_file(&path).await.unwrap();
let injection_attempts = vec![
("test$(whoami)", "test$(whoami)"),
("test`id`", "test`id`"),
("test;ls -la", "test;ls -la"),
("test|cat /etc/passwd", "test|cat /etc/passwd"),
("test&&rm -rf /tmp/test", "test&&rm -rf /tmp/test"),
];
for (attempt, expected) in injection_attempts {
let args = json!({
"message": attempt
});
let result = tool_manager.execute_tool("echo_test", args, &HashMap::new()).await;
assert!(result.is_ok(), "Command should execute");
let output = result.unwrap();
let text = output["output"].as_str().unwrap().trim();
assert_eq!(
text, expected,
"Injection attempt '{}' should produce literal output",
attempt
);
assert!(
!text.contains("root"),
"Should not contain system user info"
);
assert!(!text.contains("uid="), "Should not contain uid info");
}
}
#[tokio::test]
async fn test_yaml_include_path_restrictions() {
let temp_dir = TempDir::new().unwrap();
let malicious_yaml = temp_dir.path().join("malicious.yaml");
tokio::fs::write(
&malicious_yaml,
r#"
include:
- /etc/passwd
- ~/.ssh/config
- ../../../../../../../etc/shadow
tools: []
"#,
)
.await
.unwrap();
let mut tool_manager = ToolManager::new();
let result = tool_manager.load_from_file(&malicious_yaml).await;
assert!(result.is_err(), "Should fail to include system files");
}
#[tokio::test]
async fn test_recursive_include_dos() {
let temp_dir = TempDir::new().unwrap();
let yaml_a = temp_dir.path().join("a.yaml");
let yaml_b = temp_dir.path().join("b.yaml");
tokio::fs::write(&yaml_a, "include:\n - ./b.yaml\ntools: []")
.await
.unwrap();
tokio::fs::write(&yaml_b, "include:\n - ./a.yaml\ntools: []")
.await
.unwrap();
let _tool_manager = ToolManager::new();
}
#[tokio::test]
async fn test_large_file_dos() {
let temp_dir = TempDir::new().unwrap();
let large_file = temp_dir.path().join("large.txt");
let _large_content = "A".repeat(100_000_000);
let mut _tool_manager = ToolManager::new();
let path = PathBuf::from("tests/fixtures/test_tools.yaml");
_tool_manager.load_from_file(&path).await.unwrap();
let _args = json!({
"path": large_file.to_str().unwrap(),
"content": _large_content
});
}
#[tokio::test]
async fn test_symlink_traversal() {
let temp_dir = TempDir::new().unwrap();
let target = temp_dir.path().join("target.txt");
let symlink = temp_dir.path().join("link.txt");
tokio::fs::write(&target, "target content").await.unwrap();
#[cfg(unix)]
{
std::os::unix::fs::symlink(&target, &symlink).unwrap();
let mut tool_manager = ToolManager::new();
let path = PathBuf::from("tests/fixtures/test_tools.yaml");
tool_manager.load_from_file(&path).await.unwrap();
let args = json!({
"path": symlink.to_str().unwrap(),
"content": "new content"
});
let result = tool_manager.execute_tool("file_writer", args, &HashMap::new()).await;
if result.is_ok() {
let content = tokio::fs::read_to_string(&target).await.unwrap();
assert_eq!(content, "new content", "Symlink was followed");
}
}
}