#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-3.0-or-later """Create deterministic, offline-only Phase-0.7 review archives.""" from __future__ import annotations import argparse import hashlib import json import shutil import subprocess import zipfile from pathlib import Path ARCHIVE_TIMESTAMP = (2026, 7, 17, 0, 0, 0) ARTIFACTS = { "chimera-elfldr-phase07.elf": { "source": "outputs/phase07/artifacts/chimera-elfldr-phase07-a.elf", "sha256": "63e810982471eb40cae3a20aa9df9a0a02892f420e429874fae4e99aa400b561", "size": 397000, }, "chimera-gfx-lifecycle-probe.elf": { "source": "outputs/phase07/artifacts/chimera-gfx-lifecycle-probe.elf", "sha256": "bfb4a5cc768e162fe4c2fddf41c3978e152722918a39085277fd172cb95a7182", "size": 112680, }, "chimera-payload-manager-phase07.elf": { "source": "outputs/phase07/artifacts/chimera-pldmgr-phase07-a.elf", "sha256": "8fecf8241a46246eddbd21e8bb4d875f5d76f1f4f4c6a11384df1f131aa5e5b1", "size": 99560, }, } STOCK_ELFLDR = { "source": "work/upstream/release-assets/elfldr-ps5-v0.23.elf", "sha256": "092d16ee0ede0c494947efd38d1a17bbd7cc4b022d3858ea898833c188c703e8", "size": 397000, } BLOCKED_SHA256 = ( "4be1c17b4964f2b68c39b5145bc4af4619c32512d60269ecf5c39728b390fa63" ) 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 verify(path: Path, expected: dict[str, object]) -> None: if not path.is_file(): raise RuntimeError(f"missing package input: {path}") if path.stat().st_size != expected["size"]: raise RuntimeError(f"unexpected size: {path}") if sha256(path) != expected["sha256"]: raise RuntimeError(f"unexpected SHA-256: {path}") def copy(root: Path, relative_source: str, destination: Path) -> None: source = root / relative_source if not source.is_file(): raise RuntimeError(f"missing package input: {source}") destination.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(source, destination) def write_json(path: Path, document: object) -> None: path.write_text( json.dumps(document, indent=2, sort_keys=True) + "\n", encoding="utf-8", newline="\n", ) def write_sums(directory: Path) -> None: entries = [] for path in sorted(directory.rglob("*")): if path.is_file() and path.name != "SHA256SUMS.txt": relative = path.relative_to(directory).as_posix() entries.append(f"{sha256(path)} {relative}") (directory / "SHA256SUMS.txt").write_text( "\n".join(entries) + "\n", encoding="utf-8", newline="\n" ) def deterministic_zip(source: Path, destination: Path) -> None: with zipfile.ZipFile( destination, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9 ) as archive: for path in sorted(source.rglob("*")): if not path.is_file(): continue relative = (Path(source.name) / path.relative_to(source)).as_posix() info = zipfile.ZipInfo(relative, ARCHIVE_TIMESTAMP) info.compress_type = zipfile.ZIP_DEFLATED info.external_attr = 0o100644 << 16 archive.writestr(info, path.read_bytes(), compresslevel=9) def clean_destination(root: Path, destination: Path) -> None: resolved_root = root.resolve() resolved = destination.resolve() if resolved_root not in resolved.parents: raise RuntimeError(f"refusing destination outside repository: {resolved}") if destination.exists(): shutil.rmtree(destination) def git_head(root: Path) -> str: status = subprocess.run( ["git", "status", "--porcelain", "--untracked-files=no"], cwd=root, check=True, capture_output=True, text=True, ) if status.stdout.strip(): raise RuntimeError("tracked worktree must be clean before packaging") result = subprocess.run( ["git", "rev-parse", "HEAD"], cwd=root, check=True, capture_output=True, text=True, ) return result.stdout.strip() def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--root", type=Path, required=True) args = parser.parse_args() root = args.root.resolve() head = git_head(root) packages = root / "outputs" / "phase07" / "packages" installation = packages / "phase07-installation-review" rollback = packages / "phase07-rollback-review" clean_destination(root, installation) clean_destination(root, rollback) packages.mkdir(parents=True, exist_ok=True) for filename, expected in ARTIFACTS.items(): source = root / str(expected["source"]) verify(source, expected) copy(root, str(expected["source"]), installation / "artifacts" / filename) review_files = [ "docs/approvals/phase07-hardened-installation-request.md", "docs/approvals/phase07-lifecycle-transfer-execution-request.md", "docs/runtime/phase-0.7-hardening.md", "docs/runtime/controlled-runtime-policy.md", "manifests/artifact-denylist.json", "manifests/artifacts/chimera-elfldr-phase07-fw-9.60.json", "manifests/artifacts/chimera-gfx-lifecycle-probe-phase07-fw-9.60.json", "manifests/artifacts/chimera-payload-manager-phase07-fw-9.60.json", "manifests/runtime/controlled-ps5-runtime-profile.json", "manifests/runtime/phase-0.7-kernelwrite-proof-matrix.json", "manifests/runtime/phase-0.7-offline-audit.json", "packaging/phase07/README-installation-review.md", ] for relative in review_files: copy(root, relative, installation / relative) audit_directory = root / "outputs" / "phase07" / "audit" if not audit_directory.is_dir(): raise RuntimeError("full Phase-0.7 audit reports are absent") (installation / "audit").mkdir(parents=True, exist_ok=True) for report in sorted(audit_directory.glob("*")): if report.is_file(): shutil.copyfile(report, installation / "audit" / report.name) install_manifest = { "artifacts": { name: { "sha256": item["sha256"], "size": item["size"], } for name, item in ARTIFACTS.items() }, "blocked_sha256": BLOCKED_SHA256, "decision": "READY_FOR_HARDENED_RUNTIME_DEPLOYMENT", "execution_authorized": False, "firmware": "9.60", "installation_authorized": False, "repository_head": head, "schema_version": 1, } write_json(installation / "PACKAGE-MANIFEST.json", install_manifest) write_sums(installation) stock_source = root / str(STOCK_ELFLDR["source"]) verify(stock_source, STOCK_ELFLDR) copy( root, str(STOCK_ELFLDR["source"]), rollback / "stock" / "elfldr-ps5-v0.23.elf", ) copy( root, "packaging/phase07/README-rollback.md", rollback / "README-rollback.md", ) rollback_manifest = { "existing_payload_manager_backup": { "available_offline": False, "required_before_installation": True, "sha256": "518740adbacccb9094fadb07dd424c53ee290f38306449ccc9d6957fdf813c0b", "size": 2050320, }, "installation_authorized": False, "repository_head": head, "rollback_authorized": False, "schema_version": 1, "stock_elfldr": { "available_offline": True, "sha256": STOCK_ELFLDR["sha256"], "size": STOCK_ELFLDR["size"], }, } write_json(rollback / "ROLLBACK-MANIFEST.json", rollback_manifest) write_sums(rollback) installation_zip = packages / "phase07-installation-review.zip" rollback_zip = packages / "phase07-rollback-review.zip" for archive in (installation_zip, rollback_zip): if archive.exists(): archive.unlink() deterministic_zip(installation, installation_zip) deterministic_zip(rollback, rollback_zip) package_index = { "archives": { installation_zip.name: { "sha256": sha256(installation_zip), "size": installation_zip.stat().st_size, }, rollback_zip.name: { "sha256": sha256(rollback_zip), "size": rollback_zip.stat().st_size, }, }, "execution_authorized": False, "installation_authorized": False, "repository_head": head, "schema_version": 1, } write_json(packages / "package-index.json", package_index) print(json.dumps(package_index, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())