video_editing_poc/.claude/skills/video-editing-diagnostics-a.../scripts/audit_runtime_safety.py

94 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""Lexically audit known runtime safety hazards without executing project code."""
from __future__ import annotations
import argparse
import json
import re
import sys
from pathlib import Path
RULES = (
("BLOCK", "AUTO_DEPENDENCY_INSTALL", re.compile(r"\bpip\s+install\b"), ("tools/*.sh",)),
("BLOCK", "REMOTE_MODEL_RESOLUTION", re.compile(r"\bget_pretrained\s*\("), ("tools/*.py",)),
("BLOCK", "NAMED_YOLO_ACQUISITION", re.compile(r"(?:LOCAL_CV_YOLO_MODEL.*:-|os\.getenv\([^,]+,)\s*[\"']yolo[^\"']*\.pt|YOLO\([^\n]*LOCAL_CV_YOLO_MODEL"), ("tools/*.sh", "tools/*.py")),
("WARN", "YOLO_LOAD_REQUIRES_REVIEW", re.compile(r"\bYOLO\s*\("), ("tools/*.py",)),
("BLOCK", "PLACEHOLDER_TONE", re.compile(r"fallbackTone|fallback-tone|ffmpeg-sine"), ("src/main/java/**/*.java",)),
("BLOCK", "PLACEHOLDER_TONE", re.compile(r"write_fallback_tone\s*\("), ("tools/*.py",)),
("BLOCK", "PLACEHOLDER_SILENCE", re.compile(r"writeSilence|strategy=silence|anullsrc="), ("src/main/java/**/*.java",)),
("BLOCK", "PLACEHOLDER_SILENCE", re.compile(r"write_silence\s*\("), ("tools/*.py",)),
("BLOCK", "AUTO_START_DEFAULT_TRUE", re.compile(r"auto-start:\s*\$\{[^}:]+:true\}"), ("src/main/resources/application*.yml",)),
("BLOCK", "RENDER_DEFAULT_TRUE", re.compile(r"render-enabled:\s*\$\{[^}:]+:true\}"), ("src/main/resources/application*.yml",)),
("BLOCK", "APPROVAL_DEFAULT_FALSE", re.compile(r"require-director-approval:\s*\$\{[^}:]+:false\}"), ("src/main/resources/application*.yml",)),
("BLOCK", "HEURISTIC_FALLBACK_DEFAULT_TRUE", re.compile(r"fallback-to-heuristic:\s*\$\{[^}:]+:true\}"), ("src/main/resources/application*.yml",)),
("WARN", "CONFIGURED_HTTP_NON_LOOPBACK", re.compile(r"https?://(?!127\.0\.0\.1|localhost)", re.IGNORECASE), ("src/main/resources/application*",)),
)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Read-only lexical audit for runtime hazards; findings require human classification and a clean result is not compliance proof."
)
parser.add_argument("--repo", type=Path, default=Path("."), help="Repository root (default: current directory).")
parser.add_argument("--format", choices=("text", "json"), default="text")
parser.add_argument(
"--fail-on", choices=("block", "warn", "never"), default="block",
help="Exit 2 on BLOCK findings, on BLOCK or WARN findings, or never because of findings (default: block).",
)
return parser.parse_args()
def paths_for(repo: Path, globs: tuple[str, ...]) -> list[Path]:
found: set[Path] = set()
for pattern in globs:
found.update(path for path in repo.glob(pattern) if path.is_file())
return sorted(found, key=lambda path: str(path.relative_to(repo)))
def main() -> int:
opts = parse_args()
repo = opts.repo.resolve()
if not (repo / "pom.xml").is_file():
print(f"error: not a recognized repository root (pom.xml missing): {repo}", file=sys.stderr)
return 3
findings: list[dict] = []
try:
for severity, code, pattern, globs in RULES:
for path in paths_for(repo, globs):
for number, line in enumerate(path.read_text(encoding="utf-8", errors="replace").splitlines(), 1):
if pattern.search(line):
findings.append({"severity": severity, "code": code,
"path": str(path.relative_to(repo)), "line": number,
"evidence": line.strip()[:240]})
asset_root = repo / "input" / "highlights" / "assets"
if asset_root.is_dir():
license_markers = list(asset_root.glob("LICENSE*")) + list(asset_root.glob("**/*.license*"))
media = [p for p in asset_root.rglob("*") if p.is_file() and p.suffix.lower() in {".wav", ".mp3", ".flac", ".aif", ".aiff", ".ttf", ".otf", ".cube"}]
if media and not license_markers:
findings.append({"severity": "WARN", "code": "ASSET_LICENSE_MARKER_MISSING",
"path": str(asset_root.relative_to(repo)), "line": 0,
"evidence": f"{len(media)} media/font/LUT files and no LICENSE* or *.license* marker; directory membership and marker files are not license proof"})
except OSError as exc:
print(f"error:goal f {exc}", file=sys.stderr)
return 3
findings.sort(key=lambda item: (item["path"], item["line"], item["code"]))
if opts.format == "json":
print(json.dumps({"repo": str(repo), "findings": findings}, indent=2, sort_keys=True))
else:
for item in findings:
location = f"{item['path']}:{item['line']}" if item["line"] else item["path"]
print(f"{item['severity']} {item['code']} {location} {item['evidence']}")
print(f"SUMMARY block={sum(f['severity'] == 'BLOCK' for f in findings)} warn={sum(f['severity'] == 'WARN' for f in findings)}")
severities = {item["severity"] for item in findings}
if opts.fail_on == "block" and "BLOCK" in severities:
return 2
if opts.fail_on == "warn" and severities & {"BLOCK", "WARN"}:
return 2
return 0
if __name__ == "__main__":
raise SystemExit(main())