This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user