from __future__ import annotations
import hashlib
import json
import pathlib
import sys
def verify(asset_dir: pathlib.Path) -> int:
crate_path = asset_dir / "ro-crate-metadata.json"
if not crate_path.exists():
sys.stderr.write(
f"no ro-crate-metadata.json in {asset_dir}; "
"pass the asset directory as the first argument\n"
)
return 2
meta = json.loads(crate_path.read_text())
errs = 0
checked = 0
for entity in meta.get("@graph", []):
rel = entity.get("@id", "")
want = entity.get("sha256")
if not want or not isinstance(rel, str):
continue
if rel.startswith("http://") or rel.startswith("https://"):
continue
if rel.startswith("#"):
continue
path = asset_dir / rel
if not path.is_file():
print(f"{rel}: MISSING (manifest expected sha256={want[:12]}...)")
errs += 1
continue
got = hashlib.sha256(path.read_bytes()).hexdigest()
if got != want:
print(f"{rel}: MISMATCH (got {got[:12]}, want {want[:12]})")
errs += 1
else:
checked += 1
if errs:
print(f"{errs} mismatch(es); {checked} file(s) verified")
return 1
print(f"OK ({checked} file(s) verified)")
return 0
def main(argv: list[str]) -> int:
asset_dir = pathlib.Path(argv[1] if len(argv) >= 2 else ".")
return verify(asset_dir)
if __name__ == "__main__":
sys.exit(main(sys.argv))