#!/usr/bin/env python3 """Check Phase 3A source boundaries, generated provenance, and secret canaries.""" from __future__ import annotations import hashlib import json import pathlib import re import sys ROOT = pathlib.Path(__file__).resolve().parents[1] FORBIDDEN_WIRE_FIELDS = { "provider_url", "vm_address", "machine_id", "machine_address", "direct_host", "private_key", "pairing_key", "rtsp_url", "gamestream", "apollo_url", "windows_password", } SECRET_PATTERNS = ( re.compile(rb"-----BEGIN [A-Z ]+PRIVATE KEY-----"), re.compile(rb"\bAKIA[0-9A-Z]{16}\b"), re.compile(rb"\bgh[pousr]_[A-Za-z0-9]{20,}\b"), re.compile(rb"\bsk-[A-Za-z0-9]{20,}\b"), ) def fail(message: str) -> None: raise ValueError(message) def check_generated_provenance() -> None: schema_path = ROOT / "schemas/control-v1.schema.json" generator_path = ROOT / "tools/generate.py" manifest = json.loads((ROOT / "gen/manifest.json").read_text(encoding="utf-8")) schema_hash = hashlib.sha256(schema_path.read_bytes()).hexdigest() generator_hash = hashlib.sha256(generator_path.read_bytes()).hexdigest() if manifest.get("schema_sha256") != schema_hash: fail("generated manifest schema hash is stale") if manifest.get("generator_sha256") != generator_hash: fail("generated manifest generator hash is stale") if manifest.get("protocol_version") != (ROOT / "VERSION").read_text(encoding="utf-8").strip(): fail("generated manifest protocol version is stale") def check_manifest_schema() -> None: schema = json.loads((ROOT / "schemas/control-v1.schema.json").read_text(encoding="utf-8")) definitions = schema.get("$defs", {}) for name in ("ConnectionManifest", "ManifestGateway", "ManifestTunnel", "ManifestProfile", "ManifestBounds", "GrantReference"): properties = definitions.get(name, {}).get("properties", {}) forbidden = sorted(FORBIDDEN_WIRE_FIELDS.intersection(properties)) if forbidden: fail(f"{name} exposes forbidden wire fields: {forbidden}") def check_text_boundaries() -> None: paths = [ ROOT / "openapi/control-v1.yaml", ROOT / "schemas/control-v1.schema.json", ROOT / "proto/versevdi/control/v1/control.proto", ROOT / "proto/versevdi/tunnel/v1/tunnel.proto", ROOT / "frames/datagram-v1.md", ROOT / "frames/registry.json", ROOT / "registries/features.json", ROOT / "registries/datagrams.json", ] for path in paths: text = path.read_text(encoding="utf-8").lower() for field in FORBIDDEN_WIRE_FIELDS: if field in text: fail(f"{path.relative_to(ROOT)} contains forbidden wire field {field}") generated_paths = list((ROOT / "gen").rglob("*")) for path in generated_paths: if not path.is_file() or path.name == "manifest.json" or path.suffix in {".pb", ".binpb"}: continue text = path.read_text(encoding="utf-8").lower() for field in FORBIDDEN_WIRE_FIELDS: if field in text: fail(f"generated output {path.relative_to(ROOT)} contains forbidden wire field {field}") def check_secret_canaries() -> None: for path in ROOT.rglob("*"): if not path.is_file() or ".git" in path.parts or path.name in {"LICENSE"}: continue data = path.read_bytes() for pattern in SECRET_PATTERNS: if pattern.search(data): fail(f"secret canary matched in {path.relative_to(ROOT)}") def main() -> int: check_generated_provenance() check_manifest_schema() check_text_boundaries() check_secret_canaries() print("Protocol scope and provenance validation passed") return 0 if __name__ == "__main__": try: raise SystemExit(main()) except (OSError, ValueError, json.JSONDecodeError) as exc: print(f"scope: {exc}", file=sys.stderr) raise SystemExit(1)