agentic-ai-engineering/skills/kits/security-foundation/examples/example-security-hooks.py

133 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""
Example: Applying L3-L5 Security Hooks to a Claude Code Agent.
This script shows how to configure and test each security level
from the Security Foundation skill kit.
Usage:
python example-security-hooks.py --level 3 # Test L3 blacklist
python example-security-hooks.py --level 4 # Test L4 whitelist
python example-security-hooks.py --level 5 # Test L5 no-bash
"""
import argparse
import sys
# ── L3: Blacklist Hook ────────────────────────────────────────────
BLOCKED_PATTERNS = [
r"rm\s+-rf",
r"git\s+clean\s+-fdx",
r"DROP\s+(TABLE|DATABASE)",
r"truncate\s+",
r"curl\s+-X\s+POST",
]
def l3_check(command: str) -> tuple[bool, str]:
"""Check command against blacklist. Returns (blocked, reason)."""
import re
for pattern in BLOCKED_PATTERNS:
if re.search(pattern, command, re.IGNORECASE):
return True, pattern
return False, ""
# ── L4: Whitelist Hook ────────────────────────────────────────────
ALLOWED_COMMANDS = [
r"^npm test$",
r"^git status$",
r"^uv run pytest",
r"^cat [\w/\.-]+$",
r"^pwd$",
r"^ls\b",
]
def l4_check(command: str) -> bool:
"""Check command against whitelist. Returns True if allowed."""
import re
return any(re.match(p, command) for p in ALLOWED_COMMANDS)
# ── L5: No Bash (Tool-based only) ─────────────────────────────────
def l5_execute(tool_name: str, params: dict) -> str:
"""Execute only through approved tools. No bash at all."""
allowed_tools = {
"read_file": lambda p: f"Reading file: {p['path']}",
"write_file": lambda p: f"Writing {len(p['content'])} chars to {p['path']}",
"grep_search": lambda p: f"Searching for '{p['pattern']}' in {p.get('path', '.')}",
}
if tool_name not in allowed_tools:
return f"BLOCKED: {tool_name} is not allowed at L5"
return allowed_tools[tool_name](params)
# ── Test Harness ──────────────────────────────────────────────────
def test_blacklist():
print(" L3 Blacklist Tests:")
tests = [
("rm -rf /", True),
("git status", False),
("DROP TABLE users", True),
("npm install express", False),
("git clean -fdx", True),
("pwd", False),
]
for cmd, expected in tests:
blocked, reason = l3_check(cmd)
status = "⛔ blocked" if blocked else "✓ allowed"
assert blocked == expected, f"FAIL: {cmd}"
print(f" {status}{cmd}")
def test_whitelist():
print(" L4 Whitelist Tests:")
tests = [
("npm test", True),
("python cleanup.py", False),
("git status", True),
("rm -rf node_modules", False),
("cat config.json", True),
]
for cmd, expected in tests:
allowed = l4_check(cmd)
status = "✓ allowed" if allowed else "⛔ blocked"
assert allowed == expected, f"FAIL: {cmd}"
print(f" {status}{cmd}")
def test_nobash():
print(" L5 No-Bash Tests:")
tests = [
("read_file", {"path": "test.txt"}, True),
("delete_file", {"path": "test.txt"}, False),
("write_file", {"path": "out.txt", "content": "hi"}, True),
]
for tool, params, expected in tests:
result = l5_execute(tool, params)
is_allowed = not result.startswith("BLOCKED")
status = "✓ allowed" if is_allowed else "⛔ blocked"
assert is_allowed == expected, f"FAIL: {tool}"
print(f" {status}{tool}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--level", type=int, choices=[3, 4, 5], default=3)
args = parser.parse_args()
print(f"\nSecurity Foundation — Testing L{args.level}\n")
if args.level == 3:
test_blacklist()
elif args.level == 4:
test_whitelist()
elif args.level == 5:
test_nobash()
print("\n All tests passed.\n")