a11oy / scripts /payload_manifest.py
betterwithage's picture
sync(space): full source mirror — resolve all GitHub<->Space drift (CTO)
a6a5d8e verified
Raw
History Blame
2.7 kB
#!/usr/bin/env python3
"""Build or verify deterministic SHA-256 manifests for payload directories."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
def sha256_file(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def collect_files(root: Path, output: Path) -> list[dict[str, object]]:
files: list[dict[str, object]] = []
output = output.resolve()
for path in sorted(root.rglob("*")):
if not path.is_file():
continue
if path.resolve() == output:
continue
rel = path.relative_to(root).as_posix()
files.append(
{
"path": rel,
"size": path.stat().st_size,
"sha256": sha256_file(path),
}
)
return files
def build_manifest(root: Path, output: Path) -> dict[str, object]:
files = collect_files(root, output)
aggregate_input = "\n".join(
f"{entry['path']}\0{entry['size']}\0{entry['sha256']}" for entry in files
).encode("utf-8")
return {
"manifestVersion": 1,
"payloadRoot": root.name,
"generator": "scripts/payload_manifest.py",
"fileCount": len(files),
"aggregateSha256": hashlib.sha256(aggregate_input).hexdigest(),
"files": files,
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("payload_dir", type=Path)
parser.add_argument("--output", required=True, type=Path)
parser.add_argument("--verify", action="store_true")
args = parser.parse_args()
root = args.payload_dir.resolve()
output = args.output.resolve()
manifest = build_manifest(root, output)
serialized = json.dumps(manifest, indent=2, sort_keys=False) + "\n"
if args.verify:
existing = output.read_text(encoding="utf-8")
if existing != serialized:
rel_output = output.relative_to(Path.cwd()) if output.is_relative_to(Path.cwd()) else output
print(f"Payload manifest is stale: {rel_output}")
print(
"Run: python3 scripts/payload_manifest.py "
f"{args.payload_dir} --output {args.output}"
)
return 1
print(f"Verified payload manifest: {output.relative_to(Path.cwd())}")
return 0
output.write_text(serialized, encoding="utf-8")
print(f"Wrote payload manifest: {output.relative_to(Path.cwd())}")
return 0
if __name__ == "__main__":
raise SystemExit(main())