41 lines
1.4 KiB
Python
41 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Check provenance and reproducible digests of the sole current local bundle."""
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
BUNDLE = ROOT / "contracts" / "local"
|
|
MANIFEST = BUNDLE / "manifest.json"
|
|
|
|
|
|
def digest(path: Path) -> str:
|
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
|
|
|
|
def main() -> None:
|
|
manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
|
|
for relative, expected in manifest["sources"].items():
|
|
path = ROOT / relative
|
|
actual = digest(path)
|
|
if actual != expected:
|
|
raise SystemExit(f"source hash mismatch: {relative}: {actual} != {expected}")
|
|
|
|
paths = sorted(
|
|
(p for p in BUNDLE.rglob("*.json")
|
|
if p != MANIFEST and (p.parent == BUNDLE or p.relative_to(BUNDLE).parts[0] == "examples")),
|
|
key=lambda p: p.relative_to(BUNDLE).as_posix(),
|
|
)
|
|
if len(paths) < 10:
|
|
raise SystemExit("missing current contract examples or schemas")
|
|
listing = "".join(f"{p.relative_to(BUNDLE).as_posix()} {digest(p)}\n" for p in paths)
|
|
actual = hashlib.sha256(listing.encode("utf-8")).hexdigest()
|
|
if actual != manifest["bundle_sha256"]:
|
|
raise SystemExit(f"contract bundle hash mismatch: {actual} != {manifest['bundle_sha256']}")
|
|
print(f"current local contract: {len(paths)} JSON files, source and bundle hashes valid")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|