Files
khadhroony-bot3/scripts/audit_pre_0_4_6_static_contracts.py
2026-08-01 11:28:43 +02:00

114 lines
4.3 KiB
Python

#!/usr/bin/env python3
# file: scripts/audit_pre_0_4_6_static_contracts.py
# version: 1
"""Audit static contracts that must remain true before the 0.4.6 alignment."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
import tomllib
def fail(code: str, message: str) -> None:
"""Print one violation."""
print(f"{code}: {message}")
def frontend_invokes(root: pathlib.Path) -> set[str]:
"""Return literal Tauri commands invoked by the frontend."""
commands: set[str] = set()
pattern = re.compile(r"invoke(?:<[^>]+>)?\(\s*[\"']([A-Za-z0-9_]+)[\"']")
for suffix in ("*.ts", "*.html"):
for path in (root / "kb-app-demo-desktop" / "frontend").rglob(suffix):
commands.update(pattern.findall(path.read_text(encoding="utf-8")))
return commands
def registered_commands(root: pathlib.Path) -> set[str]:
"""Return commands registered in generate_handler."""
path = root / "kb-app-demo-desktop" / "src" / "tauri.rs"
text = path.read_text(encoding="utf-8")
match = re.search(r"generate_handler!\[(.*?)\]\);", text, re.DOTALL)
if match is None:
return set()
return set(re.findall(r"^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*,", match.group(1), re.MULTILINE))
def main() -> int:
"""Run the pre-0.4.6 static audit."""
parser = argparse.ArgumentParser()
parser.add_argument("--root", default=".")
parser.add_argument("--report-only", action="store_true")
arguments = parser.parse_args()
root = pathlib.Path(arguments.root).resolve()
violations = 0
dotenv_crates: list[str] = []
for cargo in sorted(root.glob("*/Cargo.toml")):
data = tomllib.loads(cargo.read_text(encoding="utf-8"))
dependencies = data.get("dependencies", {})
if "dotenvy" in dependencies:
dotenv_crates.append(cargo.parent.name)
if dotenv_crates != ["kb-config"]:
fail("ALIGN001", f"dotenvy must be owned only by kb-config, found {dotenv_crates}")
violations += 1
missing = sorted(frontend_invokes(root) - registered_commands(root))
if missing:
fail("ALIGN002", f"frontend commands missing from Tauri registration: {missing}")
violations += 1
tauri_text = (root / "kb-app-demo-desktop" / "src" / "tauri.rs").read_text(encoding="utf-8")
if 'window.label() != "main"' not in tauri_text or "disconnect_demo_ws_app_state" not in tauri_text:
fail("ALIGN003", "global WebSocket shutdown must be tied to main-window destruction")
violations += 1
if re.search(r'window\.label\(\)\s*==\s*"demo_ws".*disconnect_demo_ws', tauri_text, re.DOTALL):
fail("ALIGN004", "demo_ws window destruction must not disconnect the application session")
violations += 1
app_state = (root / "kb-app-demo-desktop" / "src" / "app_state.rs").read_text(encoding="utf-8")
if "demo_ws_session" not in app_state:
fail("ALIGN005", "AppState must own the persistent demo WebSocket session")
violations += 1
forbidden_crates = (
"kb_decoder_",
"kb_executor_",
"kb_materializer_",
"kb_store_core",
"kb_store_pg",
)
for path in sorted(root.rglob("*.rs")):
if any(part in {"olddocs", "target"} for part in path.parts):
continue
text = path.read_text(encoding="utf-8")
for name in forbidden_crates:
if name in text:
fail("ALIGN006", f"legacy crate identity {name!r} found in {path.relative_to(root)}")
violations += 1
required_docs = ("README.md", "TODO.md", "USAGE.md", "CHANGELOG.md")
for cargo in sorted(root.glob("*/Cargo.toml")):
for document in required_docs:
if not (cargo.parent / document).is_file():
fail("ALIGN007", f"missing {document} in {cargo.parent.name}")
violations += 1
matrix = root / "test-fixtures" / "contract-matrices" / "OPERATION_NAMING_MATRIX.json"
if not matrix.is_file():
fail("ALIGN008", "operation naming matrix is missing")
violations += 1
if violations == 0:
print("Pre-0.4.6 static contract audit: clean")
return 0
print(f"Pre-0.4.6 static contract audit: {violations} violation(s)")
return 0 if arguments.report_only else 1
if __name__ == "__main__":
raise SystemExit(main())