#!/usr/bin/env python3 """Phase 5 audit for cross-request/static state risks in site code files.""" from __future__ import annotations import argparse import json from dataclasses import asdict, dataclass from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SITE = ROOT / "site" PATTERNS = [ ("static local/global", "static "), ("once hook", "ONCE("), ("init hook", "INIT("), ("background task", "task_"), ] SKIP_PARTS = {".git", "tmp", "work", "bin", "pkg", "__pycache__"} CODE_SUFFIXES = {".uce", ".h"} DOC_SUFFIXES = {".txt"} @dataclass class Finding: path: str line: int kind: str severity: str text: str note: str def iter_files(include_doc_text: bool) -> list[Path]: suffixes = CODE_SUFFIXES | (DOC_SUFFIXES if include_doc_text else set()) result: list[Path] = [] for path in SITE.rglob("*"): if not path.is_file(): continue if any(part in SKIP_PARTS for part in path.parts): continue if path.suffix not in suffixes: continue result.append(path) return sorted(result) def note_for(kind: str, severity: str) -> str: if severity == "documentation": return "Documentation prose mention; useful for terminology review, not a direct static-state migration finding." if kind in {"once hook", "init hook"}: return "Audit behavior under per-request wasm workspaces; ONCE/INIT may need host-side cache semantics if used for cross-request state." if kind == "background task": return "Task APIs cross request lifetimes; verify they are host handles, not guest statics." return "Check whether state is request-local, immutable, or intentionally persistent; unit statics reset per wasm workspace." def severity_for(path: Path) -> str: return "documentation" if path.suffix in DOC_SUFFIXES else "code" def scan(include_doc_text: bool) -> list[Finding]: findings: list[Finding] = [] for path in iter_files(include_doc_text): try: lines = path.read_text(encoding="utf-8").splitlines() except UnicodeDecodeError: continue severity = severity_for(path) for lineno, line in enumerate(lines, 1): stripped = line.strip() if severity == "code" and (stripped.startswith("//") or stripped.startswith("# ")): continue for kind, needle in PATTERNS: if needle in line: findings.append(Finding( path=str(path.relative_to(ROOT)), line=lineno, kind=kind, severity=severity, text=stripped[:180], note=note_for(kind, severity), )) return findings def write_reports(findings: list[Finding], out_dir: Path) -> None: out_dir.mkdir(parents=True, exist_ok=True) (out_dir / "site-static-audit.json").write_text(json.dumps([asdict(f) for f in findings], indent=2) + "\n") lines = ["# Phase 5 site static-state audit", ""] if not findings: lines.append("No candidate cross-request/static-state patterns found.") else: code_count = sum(1 for f in findings if f.severity == "code") doc_count = sum(1 for f in findings if f.severity == "documentation") lines.append(f"Findings: {code_count} code, {doc_count} documentation prose.") lines.append("") lines.extend(["| file | line | severity | kind | code | note |", "|---|---:|---|---|---|---|"]) for f in findings: code = f.text.replace("|", "\\|") note = f.note.replace("|", "\\|") lines.append(f"| {f.path} | {f.line} | {f.severity} | {f.kind} | `{code}` | {note} |") (out_dir / "site-static-audit.md").write_text("\n".join(lines) + "\n") def main() -> int: parser = argparse.ArgumentParser(description="Phase 5 site static/cross-request-state audit") parser.add_argument("--include-doc-text", action="store_true", help="include site/doc .txt prose as documentation-severity findings") parser.add_argument("--out-dir", default="/tmp/uce/wasm-phase5") args = parser.parse_args() out_dir = Path(args.out_dir) findings = scan(args.include_doc_text) write_reports(findings, out_dir) print(f"Found {len(findings)} candidate static/cross-request patterns") print(f"wrote {out_dir / 'site-static-audit.json'} and {out_dir / 'site-static-audit.md'}") return 0 if __name__ == "__main__": raise SystemExit(main())