241 lines
10 KiB
Python
241 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Validate the consumed Phase-1.0O device-result evidence record."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
from typing import Any
|
|
|
|
|
|
PHASE = "PHASE_1_0O_WRITE_FREE_DEFAULTS_ONE_SHOT_DEVICE_RESULT"
|
|
STATUS = "ONE_SHOT_AUTHORIZATION_CONSUMED_I04_REACHED_FLIP_SUBMIT_FAILED"
|
|
SOURCE_COMMIT = "12cf1d783c41eb303987e49a5a920805a59ef7a4"
|
|
RUNNER_COMMIT = "606909706f91d7213751c245081333f56c2cce89"
|
|
ARTIFACT_SHA256 = "c99a0856309a357ad2667d89b4924e4063ad214cae09c8a419457b0732f583cd"
|
|
TRACE_SHA256 = "3d0b8811ae11f5cac2c2d331e252e1789a10588cab0e6045828a6b6af0fe1eb6"
|
|
STAGES = (
|
|
"D00", "D01", "D02", "I00", "I01", "I02", "I03", "I04",
|
|
"I05", "I06", "I07", "I08", "I09", "I10", "D10", "I11",
|
|
"I12", "I13", "I14", "D03", "D05", "D06", "D07", "D12", "D04",
|
|
)
|
|
AUTHORIZATION_FIELDS = (
|
|
"ps5_connection_authorized", "device_transfer_authorized",
|
|
"device_execution_authorized", "result_receive_authorized",
|
|
"installation_authorized", "autoload_authorized",
|
|
"device_write_authorized", "automatic_retry",
|
|
)
|
|
|
|
|
|
def load_json(path: Path) -> dict[str, Any]:
|
|
value = json.loads(path.read_text(encoding="utf-8"))
|
|
if not isinstance(value, dict):
|
|
raise ValueError("result manifest is not an object")
|
|
return value
|
|
|
|
|
|
def all_false(record: dict[str, Any], fields: tuple[str, ...]) -> bool:
|
|
return all(record.get(field) is False for field in fields)
|
|
|
|
|
|
def artifact_is_consumed_and_ineligible(record: dict[str, Any]) -> bool:
|
|
return (
|
|
record.get("name") == "retroarch_ps5_write_diag.elf"
|
|
and record.get("size") == 1845208
|
|
and record.get("sha256") == ARTIFACT_SHA256
|
|
and record.get("execution_eligible") is False
|
|
and record.get("transfer_eligible") is False
|
|
and record.get("installation_eligible") is False
|
|
and record.get("tracked") is False
|
|
)
|
|
|
|
|
|
def authorization_is_consumed(record: dict[str, Any]) -> bool:
|
|
return (
|
|
record.get("run_id") == "phase10o-20260722-write-free-01"
|
|
and record.get("active_manifest_sha256")
|
|
== "64bb022b2c7de5627c42800406c5db444611a89e98fbfb99ca301e7a90fbfbef"
|
|
and record.get("local_approval_sha256")
|
|
== "0dc47462e4d5be47def77195aca74c4e320d4c21b45c4decbc319f6d16dbf064"
|
|
and record.get("attempt_receipt_sha256")
|
|
== "92ba19c3306f99ec73d269f62d7b63c433b83f9a358f6f43faf1c41875613fbb"
|
|
and record.get("consumed") is True
|
|
and record.get("authority_inherited_by_future_action") is False
|
|
)
|
|
|
|
|
|
def transport_is_exact_one_shot(record: dict[str, Any]) -> bool:
|
|
return (
|
|
record.get("connect_count") == 1
|
|
and record.get("sendall_count") == 1
|
|
and record.get("bytes_sent") == 1845208
|
|
and record.get("shutdown_write_count") == 1
|
|
and record.get("recv_call_count") == 14
|
|
and record.get("received_byte_count") == 3953
|
|
and record.get("raw_stream_stored_bytes") == 3953
|
|
and record.get("raw_stream_sha256")
|
|
== "61941124ea06b22f8e27df795705329bd5b39e76b86770872dbbf4a611d02c1e"
|
|
and record.get("raw_stream_truncated") is False
|
|
and record.get("remote_eof_observed") is True
|
|
and record.get("retry_count") == 0
|
|
and record.get("reconnect_count") == 0
|
|
and record.get("close_called") is True
|
|
)
|
|
|
|
|
|
def protocol_result_is_exact(record: dict[str, Any]) -> bool:
|
|
raw = record.get("raw_results", {})
|
|
return (
|
|
record.get("name") == "PHASE_1_0N_WRITE_FREE_DEFAULTS"
|
|
and record.get("magic") == "CHD10J01"
|
|
and record.get("frame_size") == 64
|
|
and record.get("frame_count") == 25
|
|
and record.get("stages") == list(STAGES)
|
|
and raw == {
|
|
"D02_platform_init": 0,
|
|
"D10_core_init": 1,
|
|
"I11_core_init": 0,
|
|
"D05_videoout_handle": 1309671680,
|
|
"D06_buffer_registration": 0,
|
|
"D07_flip_submit": -1,
|
|
"D07_saved_errno": 0,
|
|
"D12_shutdown_reason": 5,
|
|
"D12_first_error": 104,
|
|
"D04_sdl_init": -1,
|
|
}
|
|
and record.get("terminal_flag_frame") == "D12_SEQUENCE_24"
|
|
and record.get("frame_after_terminal") == "D04_SEQUENCE_25"
|
|
and record.get("valid_terminal_frame_received_classification") is False
|
|
and record.get("remote_eof_after_frames") is True
|
|
)
|
|
|
|
|
|
def source_binding_is_bounded(record: dict[str, Any]) -> bool:
|
|
return (
|
|
record.get("phase10m_write_free_correction_passed_i04") is True
|
|
and record.get("write_firewall_triggered") is False
|
|
and record.get("d13_present") is False
|
|
and record.get("sdl_video_entry_reached") is True
|
|
and record.get("videoout_open_returned_positive_handle") is True
|
|
and record.get("videoout_buffer_registration_raw") == 0
|
|
and record.get("diagnostic_pattern_copied_before_submit") is True
|
|
and record.get("first_flip_call") == "sceVideoOutSubmitFlip(handle,0,1,0)"
|
|
and record.get("first_flip_submit_raw") == -1
|
|
and record.get("first_flip_saved_errno") == 0
|
|
and record.get("first_flip_wait_called") is False
|
|
and record.get("e104_is_generic_framebuffer_fail_label_after_early_flip_failure") is True
|
|
and record.get("sdl_init_raw") == -1
|
|
and all(record.get(field) == "UNPROVEN" for field in (
|
|
"visible_presentation", "complete_cleanup", "safe_exit",
|
|
))
|
|
)
|
|
|
|
|
|
def git(root: Path, *args: str) -> str:
|
|
result = subprocess.run(
|
|
["git", *args], cwd=root, capture_output=True, text=True, check=False)
|
|
if result.returncode:
|
|
raise RuntimeError(result.stderr.strip() or "git failed")
|
|
return result.stdout
|
|
|
|
|
|
def validate(root: Path, retroarch_root: Path | None = None) -> list[str]:
|
|
errors: list[str] = []
|
|
path = root / "manifests/retroarch/phase-1.0o-write-free-device-result.json"
|
|
try:
|
|
record = load_json(path)
|
|
except (OSError, ValueError, json.JSONDecodeError) as error:
|
|
return [str(error)]
|
|
if record.get("phase") != PHASE or record.get("status") != STATUS:
|
|
errors.append("phase/status mismatch")
|
|
if record.get("source_commit") != SOURCE_COMMIT or record.get("runner_commit") != RUNNER_COMMIT:
|
|
errors.append("source or runner commit mismatch")
|
|
if not artifact_is_consumed_and_ineligible(record.get("artifact", {})):
|
|
errors.append("artifact identity or post-run eligibility mismatch")
|
|
if not authorization_is_consumed(record.get("authorization", {})):
|
|
errors.append("one-shot authorization is not immutably consumed")
|
|
if not all_false(record.get("current_authorizations", {}), AUTHORIZATION_FIELDS):
|
|
errors.append("a current authorization remains active")
|
|
actions = record.get("performed_actions", {})
|
|
if not all(actions.get(field) is True for field in (
|
|
"ps5_connected", "device_request_performed", "files_transferred",
|
|
"target_execution_performed", "result_received_from_device",
|
|
"display_memory_mutated_by_diagnostic_pattern",
|
|
"videoout_flip_submit_attempted",
|
|
)) or not all(actions.get(field) is False for field in (
|
|
"persistent_staging_performed", "installation_performed",
|
|
"autoload_performed", "retry_performed", "reconnect_performed",
|
|
"videoout_flip_submit_succeeded",
|
|
)):
|
|
errors.append("performed action boundary mismatch")
|
|
if not transport_is_exact_one_shot(record.get("transport", {})):
|
|
errors.append("transport is not exact one-shot evidence")
|
|
trace = record.get("trace", {})
|
|
if not (
|
|
trace.get("tracked") is False and trace.get("size") == 18031
|
|
and trace.get("sha256") == TRACE_SHA256
|
|
and trace.get("parser_errors") == []
|
|
and trace.get("runner_terminal_classification")
|
|
== "INCOMPLETE_LAST_FRAME_AFTER_TERMINAL"
|
|
and trace.get("individual_frames_usable_as_device_evidence") is True
|
|
):
|
|
errors.append("trace boundary is incomplete or promoted")
|
|
if not protocol_result_is_exact(record.get("protocol_result", {})):
|
|
errors.append("protocol result does not match the immutable trace")
|
|
if not source_binding_is_bounded(record.get("source_binding", {})):
|
|
errors.append("source inference is broadened or incomplete")
|
|
tests = record.get("tests", {})
|
|
if not (
|
|
tests.get("chimera_gfx_ctest") == "58_OF_58_PASS"
|
|
and tests.get("phase10o_guardrails") == 20
|
|
and tests.get("device_result_not_generated_by_host_test") is True
|
|
):
|
|
errors.append("test evidence is incomplete or promoted")
|
|
tracked = git(root, "ls-files").splitlines()
|
|
if any(path.lower().endswith((".elf", ".self", ".sprx", ".pkg", ".map")) for path in tracked):
|
|
errors.append("target artifact or map is tracked")
|
|
if retroarch_root is not None:
|
|
try:
|
|
patch = git(retroarch_root, "show", f"{SOURCE_COMMIT}:pkg/ps5/sdl2-ps5-early-diag.patch")
|
|
platform = git(retroarch_root, "show", f"{SOURCE_COMMIT}:frontend/drivers/platform_ps5_smoke.c")
|
|
configuration = git(retroarch_root, "show", f"{SOURCE_COMMIT}:configuration.c")
|
|
runner = git(retroarch_root, "show", f"{RUNNER_COMMIT}:tools/ps5_diag_duplex.py")
|
|
for token in (
|
|
"CHIMERA_PS5_FIRST_FRAME_INDEX 0u",
|
|
"sceVideoOutSubmitFlip(",
|
|
"submit_errno = submit_result != 0 ? errno : 0",
|
|
"goto framebuffer_fail",
|
|
):
|
|
if token not in patch:
|
|
errors.append(f"SDL source binding missing: {token}")
|
|
if "CHIMERA_SMOKE_E104_FRAMEBUFFER_ALLOC" not in platform:
|
|
errors.append("generic E104 source label is missing")
|
|
if "#if !defined(CHIMERA_PS5_NO_FILESYSTEM_WRITES)" not in configuration:
|
|
errors.append("write-free defaults correction is missing")
|
|
if "WRITE_FREE_ACTIVE_PHASE" not in runner or "EXACT_ONE_SHOT_PHASE_1_0N" not in runner:
|
|
errors.append("N runner source binding is missing")
|
|
except RuntimeError as error:
|
|
errors.append(str(error))
|
|
return errors
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--root", type=Path, required=True)
|
|
parser.add_argument("--retroarch-root", type=Path)
|
|
args = parser.parse_args()
|
|
errors = validate(args.root.resolve(), args.retroarch_root)
|
|
if errors:
|
|
for error in errors:
|
|
print(f"ERROR: {error}")
|
|
return 1
|
|
print("Phase-1.0O consumed device-result validation passed")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|