use std::process::Command;
fn dcg_binary() -> std::path::PathBuf {
let mut path = std::env::current_exe().unwrap();
path.pop(); path.pop(); path.push("dcg");
path
}
fn run_hook(command: &str) -> String {
let input = serde_json::json!({
"tool_name": "Bash",
"tool_input": {
"command": command,
}
});
let mut child = Command::new(dcg_binary())
.env("DCG_PACKS", "system.permissions")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.expect("failed to spawn dcg");
{
let stdin = child.stdin.as_mut().expect("failed to open stdin");
serde_json::to_writer(stdin, &input).expect("failed to write json");
}
let output = child.wait_with_output().expect("failed to wait for dcg");
String::from_utf8_lossy(&output.stdout).to_string()
}
#[test]
fn chmod_false_positive_filename() {
let cmd = "chmod 644 file_777";
let output = run_hook(cmd);
assert!(
!output.contains("deny"),
"False positive: '{cmd}' was blocked! Output: {output}"
);
}
#[test]
fn chmod_recursive_false_positive_filename() {
let cmd = "chmod -R 644 file_777";
let output = run_hook(cmd);
assert!(
!output.contains("deny"),
"False positive: '{cmd}' was blocked! Output: {output}"
);
}
#[test]
fn chmod_recursive_bypass_long_flag() {
let cmd = "chmod --recursive 755 /etc";
let output = run_hook(cmd);
assert!(output.contains("deny"), "Bypass: '{cmd}' was allowed!");
}
#[test]
fn chmod_recursive_root_false_positive_home() {
let cmd = "chmod -R 755 /home/user/project";
let output = run_hook(cmd);
assert!(
!output.contains("deny"),
"False positive: '{cmd}' was blocked! Output: {output}"
);
}
#[test]
fn chmod_777_symbolic_bypass() {
let cmd = "chmod 0777 /etc";
let output = run_hook(cmd);
assert!(output.contains("deny"), "Bypass: '{cmd}' was allowed!");
}