PingPongRealWorldRL / runtime /provenance.py
KurisiTOMA's picture
chore: publish H2 real-world RL system
d8290eb verified
Raw History Blame Contribute Delete
1.85 kB
"""Fail-closed verification of immutable deployment artifacts."""
from __future__ import annotations
import hashlib
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
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_artifacts(manifest: str | Path | None = None) -> dict[str, str]:
path = Path(manifest) if manifest is not None else PROJECT_ROOT / "ARTIFACTS.sha256"
if not path.is_file():
raise FileNotFoundError(f"artifact manifest is missing: {path}")
verified: dict[str, str] = {}
for line_number, raw in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
line = raw.strip()
if not line or line.startswith("#"):
continue
parts = line.split(maxsplit=1)
if len(parts) != 2 or len(parts[0]) != 64:
raise RuntimeError(f"invalid artifact manifest line {line_number}: {raw!r}")
expected, relative = parts[0].lower(), parts[1].lstrip(" *")
artifact = (PROJECT_ROOT / relative).resolve()
if PROJECT_ROOT not in artifact.parents:
raise RuntimeError(f"manifest path escapes deployment root: {relative}")
if not artifact.is_file():
raise FileNotFoundError(f"manifest artifact is missing: {artifact}")
actual = _sha256(artifact)
if actual != expected:
raise RuntimeError(
f"artifact hash mismatch for {relative}: expected {expected}, got {actual}"
)
verified[relative] = actual
if not verified:
raise RuntimeError("artifact manifest contains no files")
return verified
__all__ = ["verify_artifacts"]