#!/usr/bin/env python3 """Anthropic Ban Enforcement Scanner. Scans all config files, scripts, and playbooks for any references to banned Anthropic providers, models, or API keys. Policy: Anthropic is permanently banned (2026-04-09). Refs: ansible/BANNED_PROVIDERS.yml """ import sys import os import re from pathlib import Path BANNED_PATTERNS = [ r"anthropic", r"claude-sonnet", r"claude-opus", r"claude-haiku", r"claude-\d", r"api\.anthropic\.com", r"ANTHROPIC_API_KEY", r"CLAUDE_API_KEY", r"sk-ant-", ] ALLOWLIST_FILES = { "ansible/BANNED_PROVIDERS.yml", # The ban list itself "bin/banned_provider_scan.py", # This scanner "DEPRECATED.md", # Historical references } SCAN_EXTENSIONS = {".py", ".yml", ".yaml", ".json", ".sh", ".toml", ".cfg", ".md"} def scan_file(filepath: str) -> list[tuple[int, str, str]]: """Return list of (line_num, pattern_matched, line_text) violations.""" violations = [] try: with open(filepath, "r", errors="replace") as f: for i, line in enumerate(f, 1): for pattern in BANNED_PATTERNS: if re.search(pattern, line, re.IGNORECASE): violations.append((i, pattern, line.strip())) break except (OSError, UnicodeDecodeError): pass return violations def main(): root = Path(os.environ.get("SCAN_ROOT", ".")) total_violations = 0 scanned = 0 for ext in SCAN_EXTENSIONS: for filepath in root.rglob(f"*{ext}"): rel = str(filepath.relative_to(root)) if rel in ALLOWLIST_FILES: continue if ".git" in filepath.parts: continue violations = scan_file(str(filepath)) scanned += 1 if violations: total_violations += len(violations) for line_num, pattern, text in violations: print(f"VIOLATION: {rel}:{line_num} [{pattern}] {text[:120]}") print(f"\nScanned {scanned} files. Found {total_violations} violations.") if total_violations > 0: print("\n❌ BANNED PROVIDER REFERENCES DETECTED. Fix before merging.") sys.exit(1) else: print("\n✓ No banned provider references found.") sys.exit(0) if __name__ == "__main__": main()