File size: 3,013 Bytes
29f25be 48cf96c 29f25be | 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 60 61 62 63 64 65 66 67 68 69 | """Verify the release inventory; optionally check file SHA256 digests."""
import argparse
import hashlib
import json
from pathlib import Path, PurePosixPath
def sha(path):
with Path(path).open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def safe_path(root, name):
relative = PurePosixPath(name)
if (not name or "\\" in name or relative.is_absolute()
or any(part in {".", ".."} for part in name.split("/"))):
raise ValueError(f"Invalid release path: {name}")
result = root.joinpath(*relative.parts)
if not result.resolve().is_relative_to(root.resolve()) or result.is_symlink():
raise ValueError(f"Unsafe release path: {name}")
return result
def verify(directory, hashes=False):
root = Path(directory).resolve()
manifest = json.loads((root / "RELEASE.json").read_text(encoding="utf-8"))
if manifest.get("format") != "vimeml_hf_release_v1" or manifest.get("license") != "gpl-3.0-or-later":
raise ValueError("Unsupported release format or license.")
sums = {}
for line in (root / "SHA256SUMS.txt").read_text(encoding="utf-8").splitlines():
digest, name = line.split(" ", 1)
if len(digest) != 64 or any(c not in "0123456789abcdef" for c in digest) or name in sums:
raise ValueError("Invalid checksum entry.")
sums[name] = digest
if set(sums) != set(manifest["files"]) | {"RELEASE.json"}:
raise ValueError("Checksum inventory differs from RELEASE.json.")
for name, digest in sums.items():
path = safe_path(root, name)
if not path.is_file():
raise ValueError(f"Missing release file: {name}")
if name != "RELEASE.json":
entry = manifest["files"][name]
if entry["bytes"] != path.stat().st_size or entry["sha256"] != digest:
raise ValueError(f"Release inventory mismatch: {name}")
if hashes and sha(path) != digest:
raise ValueError(f"Release checksum mismatch: {name}")
expected = set(sums) | {"SHA256SUMS.txt"}
actual = {p.relative_to(root).as_posix() for p in root.rglob("*") if p.is_file()
and ".cache" not in p.relative_to(root).parts
and "__pycache__" not in p.relative_to(root).parts
and p.suffix != ".pyc" and p.relative_to(root).as_posix() != ".gitattributes"}
if actual != expected:
raise ValueError("Unexpected release file inventory.")
return manifest, sorted(expected)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--release", type=Path, default=Path(__file__).resolve().parent)
parser.add_argument("--hashes", action="store_true", help="Also read and hash every payload file.")
args = parser.parse_args()
manifest, files = verify(args.release, hashes=args.hashes)
print(f"Verified {len(files)} files: {manifest['repo_id']} / source {manifest['source_commit']}")
if __name__ == "__main__":
main()
|