#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Thirty host-only guardrails for the Phase-0.9D readback design.""" from __future__ import annotations import argparse import copy 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( "phase09d_validator", root / "tools/validate_phase09d_readback.py" ) manifest = validator.load_json( root / "manifests/runtime/phase-0.9d-existing-stack-readback.json" ) schema = validator.load_json( root / "manifests/runtime/phase-0.9d-existing-stack-readback.schema.json" ) defaults = manifest["endpoint_defaults"] 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 candidate(**changes: object) -> dict[str, object]: route: dict[str, object] = { "readback_candidate": True, "open_flags": ["O_RDONLY", "O_NOFOLLOW"], "writes_bytes": False, "creates_file": False, "removes_file": False, "renames_file": False, "modifies_configuration": False, "launches_payload": False, "process_or_service_action": False, "writes_autoload_triggered": False, "binary_safe_file_response": True, "exact_returned_byte_count": True, "partial_result_rejected": True, "short_read_behavior": "DETECTED_AND_INVALID", "automatic_retry": False, "automatic_resume": False, } route.update(changes) return route def invalid_manifest(changed: dict[str, object], message: str) -> None: require(bool(validator.validate_manifest(changed)), message) @case("01 device write can never be a readback candidate") def _() -> None: errors = validator.route_readback_errors( candidate(writes_bytes=True), defaults ) require(bool(errors), "device-write candidate passed") @case("02 rename unlink create and truncate are rejected") def _() -> None: mutations = ( {"renames_file": True}, {"removes_file": True}, {"creates_file": True}, {"open_flags": ["fopen(wb)"]}, ) for mutation in mutations: require( bool( validator.route_readback_errors( candidate(**mutation), defaults ) ), f"mutating route passed: {mutation}", ) @case("03 payload launch is rejected") def _() -> None: require( bool( validator.route_readback_errors( candidate(launches_payload=True), defaults ) ), "launch route passed", ) @case("04 autoload_triggered routes are excluded") def _() -> None: require( bool( validator.route_readback_errors( candidate(writes_autoload_triggered=True), defaults ) ), "autoload mutation passed", ) require( manifest["flag_semantics"]["autoload_triggered"]["excluded_windows"] == [1, 2], "autoload route is not excluded from Windows 1 and 2", ) @case("05 server_active alone is not anti-brick critical") def _() -> None: semantics = manifest["flag_semantics"]["server_active_flag"] require( semantics["classification"] == "LOW_VOLATILE", "server_active is overclassified", ) require( validator.server_active_observation_status(semantics) == "PARTIAL", "server_active route should remain partial", ) @case("06 server_active semantics must be complete") def _() -> None: changed = copy.deepcopy(manifest) changed["flag_semantics"]["server_active_flag"]["fully_documented"] = False invalid_manifest(changed, "incomplete server_active semantics passed") @case("07 missing reset semantics blocks observation") def _() -> None: semantics = copy.deepcopy( manifest["flag_semantics"]["server_active_flag"] ) semantics["reset_path"] = "UNPROVEN" require( validator.server_active_observation_status(semantics) == "BLOCKED", "unknown reset semantics did not block", ) @case("08 file read without binary framing is invalid") def _() -> None: require( bool( validator.route_readback_errors( candidate(binary_safe_file_response=False), defaults ) ), "text-framed file route passed", ) @case("09 file read without short-read detection is invalid") def _() -> None: require( bool( validator.route_readback_errors( candidate(short_read_behavior="UNPROVEN"), defaults ) ), "short-read-unsafe route passed", ) @case("10 partial host transfer is invalid") def _() -> None: record = { "status": "TRANSFER_INCOMPLETE", "transfer_complete": False, "automatic_resume": False, "automatic_retry": False, "recovery_proven": False, } require( bool(validator.backup_record_errors(record)), "partial transfer was not invalidated", ) @case("11 automatic resume is forbidden") def _() -> None: record = { "status": "INVALID", "automatic_resume": True, "automatic_retry": False, "recovery_proven": False, } require( bool(validator.backup_record_errors(record)), "automatic resume passed", ) @case("12 automatic retry is forbidden") def _() -> None: record = { "status": "INVALID", "automatic_resume": False, "automatic_retry": True, "recovery_proven": False, } require( bool(validator.backup_record_errors(record)), "automatic retry passed", ) @case("13 two readbacks must match size hash and bytes") def _() -> None: record = { "status": "COPIES_MATCH", "transfer_complete": True, "automatic_resume": False, "automatic_retry": False, "closed_and_reopened": True, "exact_byte_count": 8, "sha256": "0" * 64, "sizes_match": True, "hashes_match": True, "bytes_match": False, "recovery_proven": False, } require( bool(validator.backup_record_errors(record)), "byte mismatch passed", ) @case("14 hash without exact byte count is insufficient") def _() -> None: record = { "status": "HOST_COPY_HASHED", "transfer_complete": True, "automatic_resume": False, "automatic_retry": False, "closed_and_reopened": True, "sha256": "0" * 64, "recovery_proven": False, } require( bool(validator.backup_record_errors(record)), "hash without count passed", ) @case("15 host backup is not recovery proof") def _() -> None: record = { "status": "COPIES_MATCH", "transfer_complete": True, "automatic_resume": False, "automatic_retry": False, "closed_and_reopened": True, "exact_byte_count": 8, "sha256": "0" * 64, "sizes_match": True, "hashes_match": True, "bytes_match": True, "recovery_proven": True, } require( bool(validator.backup_record_errors(record)), "backup incorrectly proved recovery", ) @case("16 replacement-dependent recovery is self-dependent") def _() -> None: require( validator.recovery_dependency_classification( "payload_manager", "payload_manager" ) == "SELF_DEPENDENT", "self-dependence was not detected", ) @case("17 package path cannot become live") def _() -> None: changed = copy.deepcopy(manifest) changed["path_inventory"][0]["live"] = True changed["runtime_observed_live_paths"] = [ changed["path_inventory"][0]["path"] ] invalid_manifest(changed, "offline path was promoted to live") @case("18 conflicting paths retain PATH_CONFLICT") def _() -> None: changed = copy.deepcopy(manifest) changed["path_classification"] = "RESOLVED" invalid_manifest(changed, "path conflict was silently resolved") @case("19 Window 1 contains no file transfer") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][0]["file_transfer"] = True invalid_manifest(changed, "Window 1 transfer passed") @case("20 Window 2 contains no device write") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][1]["device_write"] = True invalid_manifest(changed, "Window 2 write passed") @case("21 Window 2 contains no launch") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][1]["payload_launch"] = True invalid_manifest(changed, "Window 2 launch passed") @case("22 Window 2 excludes autoload_status") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][1]["autoload_status_route"] = True invalid_manifest(changed, "Window 2 autoload_status passed") @case("23 Window 3 has no automatic third attempt") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][2]["automatic_third_attempt"] = True invalid_manifest(changed, "automatic third attempt passed") @case("24 components have separate windows") def _() -> None: changed = copy.deepcopy(manifest) changed["operational_windows"][3]["component_session_separate"] = False invalid_manifest(changed, "combined component window passed") @case("25 side-by-side does not authorize installation") def _() -> None: changed = copy.deepcopy(manifest) changed["side_by_side"]["grants_installation_authorization"] = True invalid_manifest(changed, "side-by-side authorized installation") @case("26 no observer artifact appears") def _() -> None: require( manifest["actions"]["observer_created"] is False and manifest["actions"]["target_artifact_created"] is False, "observer artifact recorded", ) require(validator.collect_errors(root) == [], "offline audit invalid") @case("27 no target code appears") def _() -> None: forbidden = {".c", ".cc", ".cpp", ".s", ".asm", ".ld", ".elf"} for relative in validator._phase09d_paths(root): require( Path(relative).suffix.lower() not in forbidden, f"target code/artifact appeared: {relative}", ) @case("28 host tests are not hardware evidence") def _() -> None: changed = copy.deepcopy(manifest) changed["final_decision"]["hardware_evidence_claimed"] = True invalid_manifest(changed, "host test became hardware proof") @case("29 every authorization field stays false") def _() -> None: for field in validator.AUTHORIZATION_FIELDS: changed = copy.deepcopy(manifest) changed["authorization"][field] = True invalid_manifest(changed, f"authorization passed: {field}") @case("30 Manager backup remains installation blocker") def _() -> None: changed = copy.deepcopy(manifest) changed["canonical_state"]["payload_manager_backup"] = "COMPLETE" invalid_manifest(changed, "Manager backup blocker was removed") require(len(cases) == 30, f"expected 30 guardrails, found {len(cases)}") require( validator.validate_schema_instance(schema, manifest) == [], "manifest does not satisfy schema", ) failures: list[str] = [] for name, function in cases: try: function() except Exception as error: # noqa: BLE001 - standalone test harness failures.append(f"{name}: {error}") if failures: for failure in failures: print(f"FAIL: {failure}") return 1 print("Phase-0.9D readback guardrails: 30/30 PASS") return 0 if __name__ == "__main__": raise SystemExit(main())