Files
chimera-gfx-Public/tests/test_phase09_transaction.py
T
Chimera GFX release export a6037502d7
phase0-ci / build-and-audit (push) Successful in 2m14s
Publish Chimera GFX source
2026-09-03 03:27:14 +02:00

764 lines
26 KiB
Python

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-or-later
"""Host-only regression tests for the Phase-0.9A anti-brick design."""
from __future__ import annotations
import argparse
import hashlib
import importlib.util
import json
import sys
from pathlib import Path
from types import ModuleType
from typing import Any, Callable
IMMUTABLE = {
"docs/runtime/phase-0.8-read-only-preflight.md": (
"3fbe086175a6048176075f447ec1482074928e3b5282db97ea2169395fe1d508"
),
"manifests/runtime/phase-0.8-read-only-preflight.json": (
"47d7f452f8799979fe99b3e6d56859f03544112725bf7e5b349eba5ed81b3322"
),
"tests/test_phase08_preflight.py": (
"8a4ad7c70de28ffe3148fd3fd1f68c36a872c53c691c9068e1ff163970863c48"
),
}
DENIED_SHA256 = (
"4be1c17b4964f2b68c39b5145bc4af4619c32512d60269ecf5c39728b390fa63"
)
TEMPLATES = {
"docs/approvals/phase-0.9-observation-template.md": (
"PHASE09_OBSERVATION_TEMPLATE",
"observation",
),
"docs/approvals/phase-0.9-backup-creation-template.md": (
"PHASE09_BACKUP_CREATION_TEMPLATE",
"backup_creation",
),
"docs/approvals/phase-0.9-staging-template.md": (
"PHASE09_STAGING_TEMPLATE",
"staging",
),
"docs/approvals/phase-0.9-switch-template.md": (
"PHASE09_SWITCH_TEMPLATE",
"live_switch",
),
"docs/approvals/phase-0.9-one-shot-execution-template.md": (
"PHASE09_ONE_SHOT_EXECUTION_TEMPLATE",
"one_shot_execution",
),
}
FALSE_AUTH_FIELDS = (
"authorized",
"installation_authorized",
"execution_authorized",
"transfer_authorized",
"lifecycle_authorized",
"automatic_retry",
)
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def load_json(path: Path) -> dict[str, Any]:
result = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(result, dict):
raise RuntimeError(f"{path}: expected JSON object")
return result
def extract_contract(path: Path, name: str) -> dict[str, Any]:
text = path.read_text(encoding="utf-8")
begin = f"<!-- BEGIN {name} -->"
end = f"<!-- END {name} -->"
if text.count(begin) != 1 or text.count(end) != 1:
raise RuntimeError(f"{path}: expected one {name} contract")
fenced = text.split(begin, 1)[1].split(end, 1)[0].strip()
if not fenced.startswith("```json\n") or not fenced.endswith("\n```"):
raise RuntimeError(f"{path}: malformed JSON fence")
result = json.loads(fenced[len("```json\n") : -len("\n```")])
if not isinstance(result, dict):
raise RuntimeError(f"{path}: expected object in contract")
return result
def load_simulator(root: Path) -> ModuleType:
path = root / "tools/simulate_phase09_transaction.py"
spec = importlib.util.spec_from_file_location("phase09_simulator", path)
if spec is None or spec.loader is None:
raise RuntimeError("could not load Phase-0.9A simulator")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
previous = sys.dont_write_bytecode
sys.dont_write_bytecode = True
try:
spec.loader.exec_module(module)
finally:
sys.dont_write_bytecode = previous
return module
def require(condition: bool, message: str) -> None:
if not condition:
raise RuntimeError(message)
def require_blocked(report: dict[str, Any], scenario: str) -> None:
require(
report["state"] in {"BLOCKED", "ROLLBACK_REQUIRED"},
f"{scenario}: state did not fail closed: {report['state']}",
)
require(
report["target_execution_performed"] is False,
f"{scenario}: target execution was claimed",
)
require(
report["automatic_retry"] is False,
f"{scenario}: automatic retry was enabled",
)
require(
report["crash_invariant"]
in {
"A_OLD_LIVE_COMPLETE",
"B_NEW_LIVE_COMPLETE_AND_BACKUP_INTACT",
"C_REJECTED_UNSAFE_OR_UNPROVEN",
},
f"{scenario}: crash invariant missing",
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--root", type=Path, required=True)
args = parser.parse_args()
root = args.root.resolve()
manifest = load_json(
root / "manifests/runtime/phase-0.9-anti-brick-design.json"
)
denylist = load_json(root / "manifests/artifact-denylist.json")
simulator = load_simulator(root)
passed: list[str] = []
def check(name: str, test: Callable[[], None]) -> None:
test()
passed.append(name)
def immutable_evidence() -> None:
for relative, expected in IMMUTABLE.items():
require(sha256(root / relative) == expected, f"immutable drift: {relative}")
check("immutable Phase-0.8 evidence", immutable_evidence)
check(
"design-only top-level state",
lambda: require(
manifest["status"] == "DESIGN_ONLY"
and manifest["phase"] == "PHASE_0_9A_OFFLINE_ANTI_BRICK"
and manifest["historical_status"] == "READ_ONLY_PREFLIGHT_BLOCKED",
"design or historical status changed",
),
)
def false_activity_and_authority() -> None:
for field in (
"hardware_observed",
"ps5_connected",
"device_write_performed",
"files_transferred",
"target_execution_performed",
"target_artifact_created",
"installation_authorized",
"lifecycle_authorized",
"execution_authorized",
"transfer_authorized",
"automatic_retry",
"lifecycle_probe_in_scope",
"graphics_in_scope",
"retroarch_in_scope",
"host_simulation_is_hardware_evidence",
):
require(manifest.get(field) is False, f"{field} is not false")
check("all activity and authorization fields false", false_activity_and_authority)
def nested_authorizations_false() -> None:
controlled = {
"authorized",
"installation_authorized",
"execution_authorized",
"transfer_authorized",
"lifecycle_authorized",
"automatic_retry",
}
def visit(value: Any, location: str) -> None:
if isinstance(value, dict):
for key, child in value.items():
if key in controlled:
require(child is False, f"{location}.{key} is not false")
visit(child, f"{location}.{key}")
elif isinstance(value, list):
for index, child in enumerate(value):
visit(child, f"{location}[{index}]")
visit(manifest, "manifest")
check("nested authorization and retry fields false", nested_authorizations_false)
def permanent_denylist() -> None:
entries = denylist["entries"]
require(denylist["fail_closed"] is True, "denylist is not fail closed")
require(len(entries) == 1, "denylist entry count changed")
entry = entries[0]
require(entry["sha256"] == DENIED_SHA256, "denied hash changed")
require(entry["status"] == "BLOCKED", "denied hash not blocked")
require(entry["permanent"] is True, "denied hash not permanent")
require(entry["execution_eligible"] is False, "denied hash eligible")
require(
manifest["permanent_denylist_binding"]
== {
"sha256": DENIED_SHA256,
"status": "BLOCKED",
"permanent": True,
"execution_eligible": False,
},
"manifest denylist binding changed",
)
check("permanent denylist remains exact", permanent_denylist)
check(
"firmware and stock identities remain unproven",
lambda: require(
manifest["firmware_runtime_behavior"] == "UNPROVEN"
and manifest["stock_identification"] == "reference_only",
"firmware or stock evidence was promoted",
),
)
check(
"Payload Manager backup remains hard blocker",
lambda: require(
manifest["payload_manager_backup"] == "HARD_BLOCKER",
"Payload Manager backup hard blocker changed",
),
)
def threat_model_complete() -> None:
items = manifest["threat_model_items"]
require(len(items) == 56, f"expected 56 threat items, got {len(items)}")
ids = {item["id"] for item in items}
require(len(ids) == len(items), "duplicate threat item ID")
require(
{item["profile"] for item in items}
== {
"A_WRONG_TARGET",
"B_WRONG_PREIMAGE",
"C_BACKUP_FAILURE",
"D_WRITE_POWER_LOSS",
"E_PROCESS_LIFECYCLE",
"F_ROLLBACK_FAILURE",
"G_OPERATOR_ERROR",
},
"threat profiles incomplete",
)
require(
all(
item["severity"] in {"CATASTROPHIC", "HIGH", "MEDIUM", "LOW"}
and item["reason"]
for item in items
),
"threat severity or reason missing",
)
check("complete classified threat model", threat_model_complete)
def invariants_complete() -> None:
invariants = manifest["anti_brick_invariants"]
require(len(invariants) == 20, "anti-brick invariant count changed")
require(
[item["id"] for item in invariants]
== [f"AB-{number:03d}" for number in range(1, 21)],
"anti-brick invariant IDs changed",
)
check("AB-001 through AB-020 present", invariants_complete)
check(
"transaction state set exact",
lambda: require(
tuple(manifest["transaction_states"]) == simulator.STATES,
"manifest and simulator state sets differ",
),
)
def transition_skip_rejected() -> None:
machine = simulator.StateMachine()
try:
machine.transition("LIVE_OBJECTS_VERIFIED")
except simulator.TransitionError:
return
raise RuntimeError("state machine accepted an approval-gate skip")
check("authorization states cannot be skipped", transition_skip_rejected)
check(
"no retry, autoload or combined transition",
lambda: require(
{
"automatic_retry",
"autoload",
"combined_component_installation",
"lifecycle_transition",
"graphics_transition",
"retroarch_transition",
}.issubset(set(manifest["forbidden_transitions"])),
"forbidden transition set incomplete",
),
)
def templates_fail_closed() -> None:
for relative, (marker, action) in TEMPLATES.items():
template = extract_contract(root / relative, marker)
require(template["template_only"] is True, f"{relative}: not template")
require(
template["template_action"] == action,
f"{relative}: wrong action binding",
)
for field in FALSE_AUTH_FIELDS:
require(template[field] is False, f"{relative}: {field} not false")
required = template["required_fields"]
require(required, f"{relative}: required fields absent")
require(
all(value is None for value in required.values()),
f"{relative}: request data was prefilled",
)
require(
template["fixed_exclusions"]["automatic_retry"] is True,
f"{relative}: retry exclusion missing",
)
require(
template["fixed_exclusions"]["autoload"] is True,
f"{relative}: autoload exclusion missing",
)
require(
template["fixed_exclusions"]["lifecycle_probe"] is True,
f"{relative}: lifecycle exclusion missing",
)
check("all five templates are false and unfilled", templates_fail_closed)
def exact_live_identity_required() -> None:
for fault in (
"missing_live_path",
"missing_mount_id",
"missing_object_id",
"wrong_size",
"wrong_preimage_hash",
):
report = simulator.simulate_transaction(
"hardened_elfldr", [fault], prove_virtual_switch_model=True
)
require_blocked(report, fault)
require(report["virtual_writes"] == [], f"{fault}: write occurred")
check("no write without exact full live identity", exact_live_identity_required)
check(
"reference-only stock hash never authorizes write",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["reference_only_preimage"],
prove_virtual_switch_model=True,
),
"reference_only_preimage",
),
)
def staging_needs_backup() -> None:
for fault in (
"backup_same_object_as_live",
"short_backup_write",
"backup_hash_mismatch",
"backup_not_reopened",
):
report = simulator.simulate_transaction(
"controlled_payload_manager",
[fault],
prove_virtual_switch_model=True,
)
require_blocked(report, fault)
require(
"virtual_candidate_stage" not in report["virtual_writes"],
f"{fault}: staging occurred without verified backup",
)
check("no staging without separate reopened backup", staging_needs_backup)
def separate_approvals() -> None:
for fault in (
"authorization_missing",
"authorization_wrong_hash",
"authorization_expired",
):
require_blocked(
simulator.simulate_transaction(
"hardened_elfldr", [fault], prove_virtual_switch_model=True
),
fault,
)
check("missing mismatched or expired approval stops", separate_approvals)
check(
"no switch while atomicity is unproven",
lambda: require_blocked(
simulator.simulate_transaction("hardened_elfldr"),
"default unproven platform",
),
)
check(
"directory durability unknown stops",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["directory_durability_unknown"],
prove_virtual_switch_model=True,
),
"directory_durability_unknown",
),
)
def synthetic_happy_path_stops_before_execution() -> None:
report = simulator.simulate_transaction(
"hardened_elfldr", prove_virtual_switch_model=True
)
require(
report["status"] == "DESIGN_MODEL_STOP_BEFORE_EXECUTION",
"synthetic model did not stop before execution",
)
require(
report["state"] == "MANUAL_EXECUTION_NOT_AUTHORIZED",
"execution approval gate was bypassed",
)
require(
report["crash_invariant"]
== "B_NEW_LIVE_COMPLETE_AND_BACKUP_INTACT",
"synthetic old/new invariant failed",
)
require(report["target_execution_performed"] is False, "execution claimed")
check("post-switch model stops before execution", synthetic_happy_path_stops_before_execution)
def no_retry_or_autoload() -> None:
for fault in ("retry_active", "autoload_active", "timeout"):
report = simulator.simulate_transaction(
"hardened_elfldr", [fault], prove_virtual_switch_model=True
)
require_blocked(report, fault)
require(report["automatic_retry"] is False, f"{fault}: retry enabled")
require(report["autoload"] is False, f"{fault}: autoload enabled")
check("autoload retry and timeout always stop", no_retry_or_autoload)
check(
"component transactions cannot be combined",
lambda: require(
set(simulator.COMPONENTS)
== {"hardened_elfldr", "controlled_payload_manager"}
and manifest["component_order"]["combined_install_all"] is False,
"combined transaction surface exists",
),
)
check(
"second component waits for acceptance or rollback",
lambda: require_blocked(
simulator.simulate_transaction(
"controlled_payload_manager",
["second_component_before_first_accepted"],
prove_virtual_switch_model=True,
),
"second_component_before_first_accepted",
),
)
check(
"lifecycle probe excluded from candidate set",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["lifecycle_probe_candidate"],
prove_virtual_switch_model=True,
),
"lifecycle_probe_candidate",
),
)
check(
"graphics SDL and RetroArch inactive",
lambda: require(
manifest["graphics_in_scope"] is False
and manifest["retroarch_in_scope"] is False
and manifest["lifecycle_probe_in_scope"] is False,
"later-phase scope became active",
),
)
def power_loss_contract_complete() -> None:
boundaries = manifest["power_loss_boundaries"]
require(len(boundaries) == 14, "power-loss boundary count changed")
require(
[item["id"] for item in boundaries]
== list(simulator.POWER_LOSS_BOUNDARIES),
"power-loss boundary order or identity changed",
)
require(
all(item["result"] == "UNPROVEN" for item in boundaries),
"a PS5 power-loss boundary was promoted",
)
require(
any(item["result"] in {"UNSAFE", "UNPROVEN"} for item in boundaries),
"unproven boundaries no longer block",
)
check("all power-loss boundaries explicit and blocking", power_loss_contract_complete)
def virtual_power_loss_invariant() -> None:
for boundary in simulator.POWER_LOSS_BOUNDARIES:
report = simulator.simulate_power_loss_boundary(
"hardened_elfldr",
boundary,
prove_virtual_switch_model=True,
)
require(
report["crash_invariant"]
in {
"A_OLD_LIVE_COMPLETE",
"B_NEW_LIVE_COMPLETE_AND_BACKUP_INTACT",
},
f"{boundary}: virtual model lost old/new invariant",
)
require(report["automatic_start"] is False, f"{boundary}: auto start")
require(report["automatic_retry"] is False, f"{boundary}: retry")
check("virtual power-loss old-or-new invariant", virtual_power_loss_invariant)
check(
"in-place overwrite forbidden",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["in_place_overwrite"],
prove_virtual_switch_model=True,
),
"in_place_overwrite",
),
)
check(
"two-step rename gap forbidden",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["two_step_rename_gap"],
prove_virtual_switch_model=True,
),
"two_step_rename_gap",
),
)
def identity_race_rejected() -> None:
for fault in ("symlink_substitution", "object_swap_after_preflight"):
require_blocked(
simulator.simulate_transaction(
"hardened_elfldr", [fault], prove_virtual_switch_model=True
),
fault,
)
check("symlink and object-swap races rejected", identity_race_rejected)
check(
"active target rejected",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["target_process_active"],
prove_virtual_switch_model=True,
),
"target_process_active",
),
)
check(
"candidate mismatch rejected",
lambda: require_blocked(
simulator.simulate_transaction(
"controlled_payload_manager",
["candidate_hash_mismatch"],
prove_virtual_switch_model=True,
),
"candidate_hash_mismatch",
),
)
check(
"wrong component mapping rejected",
lambda: require_blocked(
simulator.simulate_transaction(
"controlled_payload_manager",
["wrong_component_artifact_mapping"],
prove_virtual_switch_model=True,
),
"wrong_component_artifact_mapping",
),
)
check(
"unknown firmware rejected",
lambda: require_blocked(
simulator.simulate_transaction(
"hardened_elfldr",
["unknown_firmware"],
prove_virtual_switch_model=True,
),
"unknown_firmware",
),
)
check(
"live hash mismatch never promotes backup",
lambda: require(
simulator.simulate_transaction(
"hardened_elfldr",
["wrong_preimage_hash"],
prove_virtual_switch_model=True,
)["virtual_writes"]
== [],
"mismatched live hash reached backup creation",
),
)
check(
"recovery dependency on replaced component rejected",
lambda: require_blocked(
simulator.simulate_transaction(
"controlled_payload_manager",
["recovery_depends_on_replaced_component"],
prove_virtual_switch_model=True,
),
"recovery_depends_on_replaced_component",
),
)
def failed_post_switch_goes_to_rollback_required() -> None:
report = simulator.simulate_transaction(
"hardened_elfldr",
["live_verification_failure"],
prove_virtual_switch_model=True,
)
require(
report["state"] == "ROLLBACK_REQUIRED",
"failed live verification did not require rollback",
)
require(report["target_execution_performed"] is False, "execution claimed")
check("post-switch failure requires rollback", failed_post_switch_goes_to_rollback_required)
def rollback_mismatch_catastrophic() -> None:
report = simulator.simulate_transaction(
"hardened_elfldr",
["rollback_hash_mismatch"],
prove_virtual_switch_model=True,
)
require(report["state"] == "BLOCKED", "rollback mismatch not blocked")
require(report["risk"] == "CATASTROPHIC", "rollback risk not catastrophic")
require(
report["blockers"][0]["code"] == "ROLLBACK_VERIFY_FAILED",
"rollback mismatch blocker changed",
)
check("rollback hash mismatch catastrophic blocked", rollback_mismatch_catastrophic)
def complete_fault_suite() -> None:
for component in simulator.COMPONENTS:
suite = simulator.run_fault_suite(component)
require(
len(suite["fault_results"]) == len(simulator.FAULTS),
f"{component}: fault suite incomplete",
)
require(
len(suite["power_loss_results"])
== len(simulator.POWER_LOSS_BOUNDARIES),
f"{component}: power-loss suite incomplete",
)
require(suite["hardware_evidence"] is False, "hardware proof claimed")
require(suite["device_write_performed"] is False, "device write claimed")
require(
suite["target_execution_performed"] is False,
"target execution claimed",
)
require(suite["automatic_retry"] is False, "suite retry enabled")
check("all declared faults injected for both components", complete_fault_suite)
def simulator_has_no_io_or_target_surface() -> None:
source = (
root / "tools/simulate_phase09_transaction.py"
).read_text(encoding="utf-8")
prohibited = (
"import socket",
"import subprocess",
"import requests",
"urllib",
"ctypes",
"os.system",
".write_text(",
".write_bytes(",
"open(",
"9021",
"8084",
"8085",
)
for token in prohibited:
require(token not in source, f"simulator contains prohibited surface: {token}")
check("simulator cannot perform filesystem network or target I/O", simulator_has_no_io_or_target_surface)
def docs_keep_platform_unproven() -> None:
docs = "\n".join(
(root / relative).read_text(encoding="utf-8")
for relative in (
"docs/runtime/phase-0.9-anti-brick-threat-model.md",
"docs/runtime/phase-0.9-installation-transaction-design.md",
"docs/runtime/phase-0.9-recovery-and-rollback-contract.md",
)
)
require(
"BLOCKER: NO PROVEN POWER-LOSS-SAFE SWITCH" in docs,
"power-loss-safe switch blocker missing",
)
require(
"Host simulation is not hardware evidence" in docs
or "Host simulation is not hardware" in docs,
"host/hardware evidence boundary missing",
)
for forbidden in ("READY_FOR_INSTALLATION", "DEPLOYMENT_READY"):
require(forbidden not in docs, f"forbidden positive status: {forbidden}")
check("documentation never promotes host model to PS5 proof", docs_keep_platform_unproven)
require(len(passed) >= 28, "too few Phase-0.9A guardrail tests")
print(
"Phase-0.9A host-only anti-brick tests passed: "
f"{len(passed)} guardrails, {len(simulator.FAULTS)} fault types x "
f"{len(simulator.COMPONENTS)} components, "
f"{len(simulator.POWER_LOSS_BOUNDARIES)} power-loss boundaries; "
"hardware evidence not claimed"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())