activity-core/scripts/verify_custodian_bundle.py

35 lines
1.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Verify actual installed bytes of the fixed Custodian command bundle; no execution."""
import argparse
import hashlib
import json
from pathlib import Path
FILES = {"scripts/security_flow_daily.py", "scripts/security_flow_report.py",
"scripts/sync_resolved_decisions.py", "scripts/weekly_allocation_report.py"}
def verify(root, expected_revision=None):
root = Path(root)
manifest = json.loads((root / "manifest.json").read_text())
if manifest.get("schema") != "activity-core.custodian-command-bundle.v1" or set(manifest.get("files", {})) != FILES:
raise ValueError("unexpected bundle contract")
if expected_revision and manifest.get("source_revision") != expected_revision:
raise ValueError("unexpected source revision")
for relative, expected in manifest["files"].items():
path = root / relative
if any(p.is_symlink() for p in [path, *path.parents]) or not path.is_file():
raise ValueError("bundle path is not a regular installed file")
if hashlib.sha256(path.read_bytes()).hexdigest() != expected:
raise ValueError("installed bundle hash mismatch")
return {"source_revision": manifest["source_revision"], "verified_files": len(FILES),
"manifest_sha256": hashlib.sha256((root / "manifest.json").read_bytes()).hexdigest()}
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True)
parser.add_argument("--expected-revision")
args = parser.parse_args()
print(json.dumps(verify(args.root, args.expected_revision), sort_keys=True))