#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Twenty-four host-only guardrails for Phase-0.9E-R2.""" from __future__ import annotations import argparse from io import BytesIO import hashlib import importlib.util from pathlib import Path import sys import tempfile from types import ModuleType from typing import Callable import zipfile 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( "phase09er2_validator", root / "tools/validate_phase09er2_correlation.py", ) inspector = load_module( "phase09er2_inspector", root / "tools/inspect_siecaf_header.py" ) manifest = validator.load_json( root / "manifests/runtime/phase-0.9e-r2-inner-correlation.json" ) fingerprints = validator.load_json( root / "manifests/runtime/phase-0.9e-r2-siecaf-fingerprints.json" ) 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 build_archive( *, count: int = 1, metadata_ids: list[int] | None = None, offsets: list[int] | None = None, payload_byte: int = 0xA5, ) -> bytes: alignment = inspector.ALIGNMENT file_offset = alignment file_size = count * alignment metadata_ids = metadata_ids or list(range(10000, 10000 + count)) offsets = offsets or [file_offset + index * alignment for index in range(count)] header = inspector.HEADER.pack( inspector.MAGIC, 1, 1, 0, 3, 0, bytes(range(16)), bytes(range(12)), 0, count, file_offset, file_size, ) metadata = bytearray() hashes = bytearray() for index in range(count): metadata.extend( inspector.SEGMENT_META.pack( metadata_ids[index], 0, 0, offsets[index], alignment, 3, 1, b"\x00" * 12, 0, 123, ) ) hashes.extend( inspector.SECTION_HASH.pack( index, 0, bytes([index + 1]) * 16, b"\x00" * 24, ) ) tables = header + metadata + hashes return ( tables + b"\x00" * (file_offset - len(tables)) + bytes([payload_byte]) * file_size ) @case("01 outer mismatch does not exclude an inner match") def _() -> None: require( "a" * 64 != "b" * 64 and validator.inner_byte_match( left_size=10, right_size=10, left_sha256="c" * 64, right_sha256="c" * 64, full_byte_equal=True, ), "outer mismatch incorrectly excluded an independent inner match", ) @case("02 outer filename is not inner provenance") def _() -> None: require( not validator.inner_byte_match( left_size=10, right_size=10, left_sha256="a" * 64, right_sha256="b" * 64, full_byte_equal=False, ), "filename-equivalent containers established inner provenance", ) @case("03 recompression changes outer bytes without changing inner") def _() -> None: payload = b"same-inner-content" * 128 with tempfile.TemporaryDirectory() as directory: first = Path(directory) / "first.zip" second = Path(directory) / "second.zip" with zipfile.ZipFile(first, "w", compression=zipfile.ZIP_STORED) as out: out.writestr("archive.dat", payload) with zipfile.ZipFile(second, "w", compression=zipfile.ZIP_DEFLATED) as out: out.writestr("archive.dat", payload) require( hashlib.sha256(first.read_bytes()).digest() != hashlib.sha256(second.read_bytes()).digest(), "different ZIP encodings unexpectedly matched", ) with zipfile.ZipFile(first) as left, zipfile.ZipFile(second) as right: require( left.read("archive.dat") == right.read("archive.dat"), "recompression changed the inner bytes", ) @case("04 inner byte match requires size hash and complete bytes") def _() -> None: require( validator.inner_byte_match( left_size=1, right_size=1, left_sha256="a" * 64, right_sha256="a" * 64, full_byte_equal=True, ) and not validator.inner_byte_match( left_size=1, right_size=1, left_sha256="a" * 64, right_sha256="a" * 64, full_byte_equal=False, ), "complete-byte requirement failed", ) @case("05 size-only match is not a byte match") def _() -> None: require( validator.classify_inner_comparison( download_valid=True, inner_present=True, left_size=10, right_size=10, left_sha256="a" * 64, right_sha256="b" * 64, full_byte_equal=False, ) == "INNER_ARCHIVE_SIZE_ONLY_MATCH", "size-only result was promoted", ) @case("06 structural equality is not content equality") def _() -> None: left = build_archive(payload_byte=0x11) right = build_archive(payload_byte=0x22) left_result = inspector.inspect_siecaf(BytesIO(left), len(left)) right_result = inspector.inspect_siecaf(BytesIO(right), len(right)) require( inspector.compare_structures(left_result, right_result)["classification"] == "SIECAF_STRUCTURAL_EXACT" and hashlib.sha256(left).digest() != hashlib.sha256(right).digest(), "structure was treated as decrypted/content identity", ) @case("07 malformed segment table is rejected") def _() -> None: malformed = build_archive()[: inspector.HEADER.size + 5] result = inspector.inspect_siecaf(BytesIO(malformed), len(malformed)) require(result["classification"] == "SIECAF_MALFORMED", str(result)) @case("08 integer overflow is rejected") def _() -> None: header = inspector.HEADER.pack( inspector.MAGIC, 1, 1, 0, 3, 0, b"\x00" * 16, b"\x00" * 12, 0, inspector.UINT64_MAX, inspector.ALIGNMENT, inspector.ALIGNMENT, ) result = inspector.inspect_siecaf(BytesIO(header), len(header)) require(result["classification"] == "SIECAF_MALFORMED", str(result)) @case("09 out-of-range offset is rejected") def _() -> None: value = build_archive(offsets=[inspector.ALIGNMENT * 2]) result = inspector.inspect_siecaf(BytesIO(value), len(value)) require(result["classification"] == "SIECAF_MALFORMED", str(result)) @case("10 overlapping ranges are reported") def _() -> None: value = build_archive( count=2, offsets=[inspector.ALIGNMENT, inspector.ALIGNMENT] ) result = inspector.inspect_siecaf(BytesIO(value), len(value)) require( result["classification"] == "SIECAF_MALFORMED" and result["overlaps"], str(result), ) @case("11 duplicate section identity is reported") def _() -> None: value = build_archive(count=2, metadata_ids=[10000, 10000]) result = inspector.inspect_siecaf(BytesIO(value), len(value)) require( result["classification"] == "SIECAF_MALFORMED" and result["duplicate_metadata_section_keys"], str(result), ) @case("12 official inner match would not make MediaFire outer official") def _() -> None: require( manifest["outer_zip_official"] is False, "outer MediaFire ZIP was promoted to official", ) @case("13 community source family is not an official community asset") def _() -> None: itsplk = manifest["community_families"][0] require( itsplk["classification"] == "THIRD_PARTY_BUILD_FROM_PUBLIC_SOURCE_POSSIBLE" and itsplk["system_backup_distributed_by_project"] is False, "third-party build possibility became an official release", ) @case("14 browser history is not fully exported") def _() -> None: browser = manifest["local_download_provenance"]["browser_history"] require( browser["full_history_exported"] is False and browser["matching_records"] == 0, "browser-history boundary changed", ) @case("15 signed URL material is redacted") def _() -> None: host = manifest["local_download_provenance"]["zone_identifier"]["host_url"] require( "" in host["path_redacted"] and len(host["full_value_sha256"]) == 64, "signed path was not safely represented", ) @case("16 no large backup is tracked") def _() -> None: for relative in validator.git(root, "ls-files").splitlines(): path = root / relative require( not path.is_file() or path.stat().st_size <= validator.MAX_TRACKED_FILE_SIZE, f"large tracked file: {relative}", ) @case("17 no downloaded file was executed") def _() -> None: require( manifest["actions"]["downloaded_file_executed"] is False, "download execution was recorded", ) @case("18 ps5-bar-tool was not executed") def _() -> None: require( manifest["actions"]["ps5_bar_tool_executed"] is False and fingerprints["parser_evidence"]["ps5_bar_tool_executed"] is False, "ps5-bar-tool execution was recorded", ) @case("19 no PS5 hostname or IP was used") def _() -> None: require( manifest["actions"]["ps5_connected"] is False and manifest["actions"]["ps5_ip_used"] is False, "PS5 network use was recorded", ) @case("20 no target source appears") def _() -> None: try: validator.git(root, "cat-file", "-e", f"{validator.BASELINE}^{{commit}}") except RuntimeError: # A parentless public release intentionally has no private history. # The historical delta remains enforced in the canonical repository. return changed = set( filter( None, validator.git( root, "diff", "--name-only", "--diff-filter=ACMR", validator.BASELINE, ).splitlines(), ) ) for relative in changed: normalized = relative.replace("\\", "/") require( not normalized.startswith(validator.FORBIDDEN_PREFIXES) and Path(normalized).suffix.lower() not in validator.FORBIDDEN_SUFFIXES, f"target/binary material appeared: {normalized}", ) @case("21 every authorization remains false") def _() -> None: for value in (manifest, fingerprints): for field in validator.AUTHORIZATION_FIELDS: require( value["authorization"][field] is False, f"authorization changed: {field}", ) @case("22 automatic retry remains false") def _() -> None: require( manifest["authorization"]["automatic_retry"] is False and manifest["actions"]["automatic_retry_used"] is False, "automatic retry was enabled or used", ) @case("23 outer metadata alone cannot open Phase 0.9F") def _() -> None: require( not validator.phase09f_reconsideration_allowed( inner_source_bound=False, mediafire_maker_source_bound=False, auditable_bootstrap_closure=True, ), "outer metadata opened Phase 0.9F", ) @case("24 runtime deployment remains unproven") def _() -> None: require( manifest["runtime_deployment_verified"] is False and manifest["current_device_contents_verified"] is False and manifest["runtime_firmware_9_60"] == "UNPROVEN", "host-only evidence became runtime proof", ) for name, function in cases: try: function() except Exception as error: raise RuntimeError(f"{name}: {error}") from error print(f"Phase-0.9E-R2 guardrails: {len(cases)}/{len(cases)} PASS") return 0 if __name__ == "__main__": raise SystemExit(main())