#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Twenty-five host-only guardrails for Phase 1.0A.""" from __future__ import annotations import argparse import importlib.util from pathlib import Path import sys from types import ModuleType from typing import Callable def load_module(name: str, path: Path) -> ModuleType: spec = importlib.util.spec_from_file_location(name, path) if spec is None or spec.loader is None: raise RuntimeError(f"could not load {path}") module = importlib.util.module_from_spec(spec) sys.modules[name] = module spec.loader.exec_module(module) return module def require(condition: bool, message: str) -> None: if not condition: raise RuntimeError(message) def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--root", type=Path, required=True) args = parser.parse_args() root = args.root.resolve() validator = load_module( "phase10a_validator", root / "tools/validate_retroarch_phase10a.py" ) cases: list[tuple[str, Callable[[], None]]] = [] def case(name: str) -> Callable[[Callable[[], None]], Callable[[], None]]: def register(function: Callable[[], None]) -> Callable[[], None]: cases.append((name, function)) return function return register def artifact(**changes: object) -> dict[str, object]: value: dict[str, object] = { "name": "retroarch_ps5_headless.elf", "execution_eligible": False, "target_execution_performed": False, "reproducibility": "BYTE_IDENTICAL_TWO_CLEAN_BUILDS", "required_symbols": sorted(validator.REQUIRED_REAL_SYMBOLS), "sha256": "a" * 64, "size": 1, "linker_map_sha256": "b" * 64, "undefined_symbols": [], "embedded_personal_paths": False, "embedded_ip_addresses": ["127.0.0.1"], "embedded_device_ip_addresses": False, "forbidden_markers_found": [], } value.update(changes) return value def profile(**changes: object) -> dict[str, object]: value: dict[str, object] = { "disabled_features": sorted(validator.DISABLED_FEATURES), "automatic_retry": False, "filesystem_writes_on_default_path": False, } value.update(changes) return value @case("01 smokecore API compliance is recorded") def _() -> None: text = (root / "docs/retroarch/phase-1.0a-driver-status.md").read_text() require("libretro" in text.lower(), "libretro contract absent") @case("02 600 deterministic frames are pinned") def _() -> None: require("frames\") != 600" in (root / "tools/validate_retroarch_phase10a.py").read_text(), "frame guard absent") @case("03 video hash is pinned") def _() -> None: require("43f920496eb5f435" in (root / "tools/validate_retroarch_phase10a.py").read_text(), "video hash absent") @case("04 audio hash is pinned") def _() -> None: require("a48f47dc08c56625" in (root / "tools/validate_retroarch_phase10a.py").read_text(), "audio hash absent") @case("05 input mapping is required") def _() -> None: require("input_mapping" in (root / "tools/validate_retroarch_phase10a.py").read_text(), "input guard absent") @case("06 clean core shutdown is required") def _() -> None: require("clean_shutdown" in (root / "tools/validate_retroarch_phase10a.py").read_text(), "shutdown guard absent") @case("07 real RetroArch registration is required") def _() -> None: require(validator.is_real_retroarch_artifact(artifact()), "real symbols rejected") @case("08 platform feature matrix is explicit") def _() -> None: require(validator.profile_is_closed(profile()), "closed profile rejected") @case("09 disabled features remain disabled") def _() -> None: require(not validator.profile_is_closed(profile(disabled_features=[])), "open profile accepted") @case("10 default config write is forbidden") def _() -> None: require(not validator.profile_is_closed(profile(filesystem_writes_on_default_path=True)), "write path accepted") @case("11 networking is disabled") def _() -> None: disabled = validator.DISABLED_FEATURES - {"networking"} require(not validator.profile_is_closed(profile(disabled_features=sorted(disabled))), "networking accepted") @case("12 updater is disabled") def _() -> None: disabled = validator.DISABLED_FEATURES - {"online_updater"} require(not validator.profile_is_closed(profile(disabled_features=sorted(disabled))), "updater accepted") @case("13 autoload is disabled") def _() -> None: disabled = validator.DISABLED_FEATURES - {"autoload"} require(not validator.profile_is_closed(profile(disabled_features=sorted(disabled))), "autoload accepted") @case("14 installation is disabled") def _() -> None: disabled = validator.DISABLED_FEATURES - {"installation"} require(not validator.profile_is_closed(profile(disabled_features=sorted(disabled))), "installation accepted") @case("15 lifecycle probe marker is forbidden") def _() -> None: require( validator.route_is_forbidden("chimera_lifecycle_probe"), "lifecycle probe marker accepted", ) @case("16 GNM is disabled") def _() -> None: disabled = validator.DISABLED_FEATURES - {"gnm"} require(not validator.profile_is_closed(profile(disabled_features=sorted(disabled))), "GNM accepted") @case("17 headless artifact must be real RetroArch") def _() -> None: require(not validator.is_real_retroarch_artifact(artifact(required_symbols=["main"])), "sample accepted") @case("18 static core symbols are mandatory") def _() -> None: symbols = validator.REQUIRED_REAL_SYMBOLS - {"retro_run"} require(not validator.is_real_retroarch_artifact(artifact(required_symbols=sorted(symbols))), "coreless ELF accepted") @case("19 software backend is explicit") def _() -> None: manifest = validator.load_json(root / "manifests/retroarch/phase-1.0a-build.json") features = manifest["profiles"]["ps5-software-rgui-smokecore"]["enabled_features"] require({"sdl2_software_video", "sdl2_ps5_pad", "sdl2_ps5_audio"}.issubset(features), "software backend matrix incomplete") @case("20 unsupported features are not silent successes") def _() -> None: text = (root / "docs/retroarch/phase-1.0a-driver-status.md").read_text() require("Explicitly unsupported" in text, "unsupported matrix absent") @case("21 exact upstream commits are bound") def _() -> None: upstreams = validator.load_json(root / "manifests/retroarch/upstreams.json") require(upstreams["sources"]["retroarch"]["commit"] == validator.RETROARCH_COMMIT, "RetroArch commit mismatch") @case("22 target output is never execution eligible") def _() -> None: require(not validator.artifact_execution_allowed(artifact()), "artifact became eligible") @case("23 no sender is part of build") def _() -> None: require(validator.route_is_forbidden("payload_sender"), "sender marker accepted") @case("24 IP addresses are detected") def _() -> None: require(validator.has_ip_address(["connect 192.0.2.1"]), "IP not detected") @case("25 personal host paths are detected") def _() -> None: require(validator.has_personal_path([r"C:\Users\Example\port"]), "host path not detected") failures: list[str] = [] for name, function in cases: try: function() except Exception as error: # noqa: BLE001 - isolated test reporting failures.append(f"{name}: {error}") if len(cases) != 25: failures.append(f"expected 25 cases, found {len(cases)}") if failures: print("\n".join(failures), file=sys.stderr) return 1 print("25 Phase 1.0A guardrails passed") return 0 if __name__ == "__main__": raise SystemExit(main())