codetether-agent 4.7.0-a-002.4

A2A-native AI coding agent for the CodeTether ecosystem
Documentation
use crate::tool::sandbox::SandboxPolicy;
use anyhow::{Result, anyhow};
use std::path::Path;

const NETWORK_TOOLS: &[&str] = &[
    "curl", "wget", "nc", "netcat", "ssh", "scp", "sftp", "rsync", "telnet", "ftp",
];

pub fn validate(policy: &SandboxPolicy, command: &str, args: &[String]) -> Result<Vec<String>> {
    if policy.allow_network {
        return Ok(Vec::new());
    }
    if mentions_network_tool(command, args) {
        return Err(anyhow!(
            "Sandbox policy denies network access for this command"
        ));
    }
    Ok(vec!["network_marker_only".to_string()])
}

fn mentions_network_tool(command: &str, args: &[String]) -> bool {
    is_network_command(command) || args.iter().any(|arg| mentions_shell_word(arg))
}

fn is_network_command(command: &str) -> bool {
    let command = command.to_ascii_lowercase();
    let name = Path::new(&command)
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or(command.as_str());
    NETWORK_TOOLS.contains(&name)
}

fn mentions_shell_word(arg: &str) -> bool {
    let arg = arg.to_ascii_lowercase();
    let dequoted = arg.replace(['"', '\'', '\\'], "");
    NETWORK_TOOLS
        .iter()
        .any(|tool| contains_shell_word(&arg, tool) || contains_shell_word(&dequoted, tool))
}

fn contains_shell_word(haystack: &str, needle: &str) -> bool {
    haystack
        .split(|ch: char| !(ch.is_ascii_alphanumeric() || ch == '-' || ch == '_'))
        .any(|word| word == needle)
}