Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 10s
PR Checklist / pr-checklist (pull_request) Failing after 1m14s
Smoke Test / smoke (pull_request) Failing after 7s
Validate Config / YAML Lint (pull_request) Failing after 8s
Validate Config / JSON Validate (pull_request) Successful in 7s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 8s
Validate Config / Python Test Suite (pull_request) Has been skipped
Validate Config / Shell Script Lint (pull_request) Failing after 17s
Validate Config / Cron Syntax Check (pull_request) Successful in 6s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 5s
Validate Config / Playbook Schema Validation (pull_request) Successful in 8s
Architecture Lint / Lint Repository (pull_request) Failing after 7s
83 lines
2.3 KiB
Python
83 lines
2.3 KiB
Python
#!/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()
|