use std::collections::HashMap;
pub trait SpawnValidator: Send + Sync {
fn validate_command(&self, cmd: &str, args: &[String]) -> Result<(), String>;
fn sanitize_env(&self, env: &mut HashMap<String, String>);
}
pub struct NoopSpawnValidator;
impl SpawnValidator for NoopSpawnValidator {
fn validate_command(&self, _cmd: &str, _args: &[String]) -> Result<(), String> {
Ok(())
}
fn sanitize_env(&self, _env: &mut HashMap<String, String>) {}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn noop_validator_accepts_any_command() {
let v = NoopSpawnValidator;
assert!(v.validate_command("/bin/anything", &[]).is_ok());
assert!(
v.validate_command("/bin/sh", &["-c".into(), "rm -rf /".into()])
.is_ok()
);
}
#[test]
fn noop_validator_leaves_env_untouched() {
let v = NoopSpawnValidator;
let mut env = HashMap::new();
env.insert("LD_PRELOAD".into(), "/tmp/evil.so".into());
env.insert("PATH".into(), "/usr/bin".into());
v.sanitize_env(&mut env);
assert_eq!(
env.get("LD_PRELOAD").map(String::as_str),
Some("/tmp/evil.so")
);
assert_eq!(env.get("PATH").map(String::as_str), Some("/usr/bin"));
}
struct TestStrictPolicy;
impl SpawnValidator for TestStrictPolicy {
fn validate_command(&self, cmd: &str, _args: &[String]) -> Result<(), String> {
if cmd.contains("sh") {
Err(format!("shell not allowed: {cmd}"))
} else {
Ok(())
}
}
fn sanitize_env(&self, env: &mut HashMap<String, String>) {
env.retain(|k, _| !k.starts_with("LD_"));
}
}
#[test]
fn consumer_policy_can_block_commands() {
let v = TestStrictPolicy;
assert!(v.validate_command("/usr/bin/node", &[]).is_ok());
assert!(v.validate_command("/bin/sh", &[]).is_err());
}
#[test]
fn consumer_policy_can_scrub_env() {
let v = TestStrictPolicy;
let mut env = HashMap::new();
env.insert("LD_PRELOAD".into(), "evil".into());
env.insert("LD_LIBRARY_PATH".into(), "/evil".into());
env.insert("PATH".into(), "/usr/bin".into());
v.sanitize_env(&mut env);
assert!(!env.contains_key("LD_PRELOAD"));
assert!(!env.contains_key("LD_LIBRARY_PATH"));
assert_eq!(env.get("PATH").map(String::as_str), Some("/usr/bin"));
}
}