#!/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")