use super::is_safe_command;
pub fn is_safe_shell_command(binary: &str, command: &[String]) -> bool {
if !matches!(binary, "bash" | "sh") {
return false;
}
let script_idx = command.iter().position(|arg| arg == "-c" || arg == "-lc");
let Some(idx) = script_idx else {
return false;
};
let Some(script) = command.get(idx + 1) else {
return false;
};
is_safe_shell_script(script)
}
fn is_safe_shell_script(script: &str) -> bool {
if script.contains('>')
|| script.contains('<')
|| script.contains("$(")
|| script.contains('`')
|| script.contains('(')
|| script.contains('{')
{
return false;
}
let commands: Vec<&str> = script
.split("&&")
.flat_map(|s| s.split("||"))
.flat_map(|s| s.split(';'))
.flat_map(|s| s.split('|'))
.map(str::trim)
.filter(|s| !s.is_empty())
.collect();
if commands.is_empty() {
return false;
}
commands.iter().all(|cmd| {
let parts: Vec<String> = shell_words::split(cmd).unwrap_or_default();
if parts.is_empty() {
return false;
}
is_safe_command(&parts)
})
}