File size: 1,976 Bytes
f12d3b3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #!/usr/bin/env python3
"""Verify bundled PROTAC artifacts and portability-sensitive source files."""
from __future__ import annotations
import hashlib
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MANIFEST = ROOT / "docs" / "artifacts.json"
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for block in iter(lambda: handle.read(8 * 1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def main() -> int:
entries = json.loads(MANIFEST.read_text())
failures = 0
for entry in entries:
path = ROOT / entry["path"]
if not path.is_file():
print(f"MISSING {entry['path']}")
failures += 1
continue
size_ok = path.stat().st_size == entry["bytes"]
hash_ok = sha256(path) == entry["sha256"]
state = "OK" if size_ok and hash_ok else "FAILED"
print(f"{state:7} {entry['path']}")
failures += int(not (size_ok and hash_ok))
private_roots = tuple("/" + stem for stem in ("scratch/", "Users/", "home/"))
for sub in ("src", "scripts", "md"):
for path in (ROOT / sub).rglob("*.py"):
text = path.read_text(errors="replace")
if any(root in text for root in private_roots):
print(f"PRIVATE {path.relative_to(ROOT)}")
failures += 1
# Optional components are fetched, not redistributed; flag only if partially present.
for name, probe in (("degrademaster", "src/degrademaster/model.py"),
("propk", "src/propk/maplight.py")):
if not (ROOT / probe).is_file():
print(f"ABSENT {name} (optional; run scripts/fetch_third_party.py)")
print("Release verification passed." if not failures else f"Verification found {failures} problem(s).")
return 1 if failures else 0
if __name__ == "__main__":
raise SystemExit(main())
|