mirror of https://github.com/aliasrobotics/cai.git
153 lines
5.5 KiB
Python
153 lines
5.5 KiB
Python
"""Tests for false-positive suppression in the sensitive command guard.
|
|
|
|
Verifies that tool names appearing in file paths or arguments do NOT
|
|
trigger the guard, while actual tool invocations still do.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from cai.util.user_prompts import (
|
|
_extract_all_binaries,
|
|
detect_sensitive_command,
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _guard_enabled():
|
|
"""Ensure the guard is always enabled during tests."""
|
|
with patch.dict("os.environ", {"CAI_SENSITIVE_GUARD": "true", "CAI_TUI_MODE": "false"}):
|
|
yield
|
|
|
|
|
|
# ── _extract_all_binaries unit tests ──────────────────────────────────
|
|
|
|
class TestExtractAllBinaries:
|
|
def test_simple_command(self):
|
|
assert _extract_all_binaries("ls -la /tmp") == {"ls"}
|
|
|
|
def test_sudo_prefix(self):
|
|
assert _extract_all_binaries("sudo nmap -sS 10.0.0.1") == {"nmap"}
|
|
|
|
def test_pipeline(self):
|
|
assert _extract_all_binaries("nmap -sS 10.0.0.1 | grep open") == {"nmap", "grep"}
|
|
|
|
def test_chain_and(self):
|
|
assert _extract_all_binaries("whoami && nmap -sS 10.0.0.1") == {"whoami", "nmap"}
|
|
|
|
def test_chain_or(self):
|
|
assert _extract_all_binaries("false || nmap 10.0.0.1") == {"false", "nmap"}
|
|
|
|
def test_semicolon(self):
|
|
assert _extract_all_binaries("cd /tmp; nmap 10.0.0.1") == {"cd", "nmap"}
|
|
|
|
def test_env_assignment_prefix(self):
|
|
assert _extract_all_binaries("FOO=bar nmap -sS 10.0.0.1") == {"nmap"}
|
|
|
|
def test_full_path_binary(self):
|
|
assert _extract_all_binaries("/usr/bin/nmap -sS 10.0.0.1") == {"nmap"}
|
|
|
|
def test_tool_in_path_only(self):
|
|
assert _extract_all_binaries("ls -la /home/kali/nmap/") == {"ls"}
|
|
|
|
def test_multiple_prefixes(self):
|
|
assert _extract_all_binaries("sudo env nmap -sS 10.0.0.1") == {"nmap"}
|
|
|
|
|
|
# ── False positives (should NOT trigger the guard) ────────────────────
|
|
|
|
class TestFalsePositives:
|
|
def test_ls_nmap_directory(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("ls -la /home/kali/nmap/")
|
|
assert not is_sensitive
|
|
|
|
def test_cat_masscan_config(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("cat /opt/masscan/config.txt")
|
|
assert not is_sensitive
|
|
|
|
def test_find_shred_backup(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("find / -name shred_backup")
|
|
assert not is_sensitive
|
|
|
|
def test_echo_nmap_string(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("echo 'installed nmap yesterday'")
|
|
assert not is_sensitive
|
|
|
|
def test_grep_in_hydra_log(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("grep error /var/log/hydra.log")
|
|
assert not is_sensitive
|
|
|
|
def test_grep_alternation_with_sudo_literal_not_sudo_privilege(self):
|
|
cmd = (
|
|
r"tail -100 /var/log/auth.log 2>/dev/null | "
|
|
r"grep -E \"(Failed|Accepted|Invalid|session opened|session closed|sudo|su:)\" | tail -50"
|
|
)
|
|
is_sensitive, _, category = detect_sensitive_command(cmd)
|
|
assert not is_sensitive
|
|
assert category == ""
|
|
|
|
def test_mkdir_nikto_output(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("mkdir -p /tmp/nikto_results")
|
|
assert not is_sensitive
|
|
|
|
def test_cp_fdisk_backup(self):
|
|
is_sensitive, _, _ = detect_sensitive_command("cp /tmp/fdisk_output.txt /backup/")
|
|
assert not is_sensitive
|
|
|
|
|
|
# ── True positives (MUST trigger the guard) ───────────────────────────
|
|
|
|
class TestTruePositives:
|
|
def test_nmap_direct(self):
|
|
is_sensitive, reason, category = detect_sensitive_command("nmap -sS 10.0.0.1")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|
|
|
|
def test_sudo_nmap(self):
|
|
is_sensitive, _, category = detect_sensitive_command("sudo nmap -sV 10.0.0.1")
|
|
assert is_sensitive
|
|
assert category == "sudo"
|
|
|
|
def test_nmap_in_pipeline(self):
|
|
is_sensitive, _, category = detect_sensitive_command("cat hosts.txt | nmap -iL -")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|
|
|
|
def test_env_prefix_nmap(self):
|
|
is_sensitive, _, category = detect_sensitive_command("FOO=bar nmap -sS 10.0.0.1")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|
|
|
|
def test_hydra_direct(self):
|
|
is_sensitive, _, category = detect_sensitive_command("hydra -l admin ssh://10.0.0.1")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|
|
|
|
def test_shred_direct(self):
|
|
is_sensitive, _, category = detect_sensitive_command("shred -u /tmp/secret.txt")
|
|
assert is_sensitive
|
|
assert category == "destructive"
|
|
|
|
def test_fdisk_direct(self):
|
|
is_sensitive, _, category = detect_sensitive_command("fdisk /dev/sda")
|
|
assert is_sensitive
|
|
assert category == "destructive"
|
|
|
|
def test_sudo_rm_rf(self):
|
|
"""sudo category is NOT subject to binary post-check."""
|
|
is_sensitive, _, category = detect_sensitive_command("sudo rm -rf /")
|
|
assert is_sensitive
|
|
assert category == "sudo"
|
|
|
|
def test_full_path_nmap(self):
|
|
is_sensitive, _, category = detect_sensitive_command("/usr/bin/nmap -sS 10.0.0.1")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|
|
|
|
def test_msfconsole(self):
|
|
is_sensitive, _, category = detect_sensitive_command("msfconsole -q")
|
|
assert is_sensitive
|
|
assert category == "recon_tool"
|