65 lines
3.0 KiB
Python
65 lines
3.0 KiB
Python
"""Check the complete vendored crate against the pinned official archive.
|
|||
|
|
|
||
|
|
Usage: python tools/glib-regression/verify_vendor.py PATH_TO_glib-0.18.5.crate
|
||
|
|
Reads archive members without extracting them or modifying the Cargo cache.
|
||
|
|
"""
|
||
|
|
import hashlib
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import tarfile
|
||
|
|
|
||
|
|
ARCHIVE_SHA = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
||
|
|
PREFIX = "glib-0.18.5/"
|
||
|
|
MODIFIED = "src/variant_iter.rs"
|
||
|
|
|
||
|
|
|
||
|
|
def verify(archive_path, vendor_root, record_path):
|
||
|
|
archive = archive_path.read_bytes()
|
||
|
|
if hashlib.sha256(archive).hexdigest() != ARCHIVE_SHA:
|
||
|
|
raise ValueError("Official archive checksum mismatch")
|
||
|
|
originals = {}
|
||
|
|
with tarfile.open(fileobj=io.BytesIO(archive), mode="r:gz") as source:
|
||
|
|
for member in source:
|
||
|
|
if member.isdir():
|
||
|
|
continue
|
||
|
|
if not member.isfile() or not member.name.startswith(PREFIX):
|
||
|
|
raise ValueError("Unexpected archive member")
|
||
|
|
name = member.name[len(PREFIX):]
|
||
|
|
path = Path(name)
|
||
|
|
if path.is_absolute() or ".." in path.parts or name in originals:
|
||
|
|
raise ValueError("Invalid or duplicate archive path")
|
||
|
|
originals[name] = source.extractfile(member).read()
|
||
|
|
actual_paths = {p.relative_to(vendor_root).as_posix()
|
||
|
|
for p in vendor_root.rglob("*") if p.is_file()}
|
||
|
|
if actual_paths != set(originals):
|
||
|
|
raise ValueError("Vendored file inventory differs from official crate")
|
||
|
|
record = json.loads(record_path.read_text(encoding="utf-8"))
|
||
|
|
records = {row["path"]: row for row in record["files"]}
|
||
|
|
if (record["archive_sha256"] != ARCHIVE_SHA or
|
||
|
|
len(records) != len(record["files"]) or set(records) != set(originals)):
|
||
|
|
raise ValueError("Provenance inventory differs")
|
||
|
|
for name, original in originals.items():
|
||
|
|
expected = original
|
||
|
|
if name == MODIFIED:
|
||
|
|
for before, after in [(b"let p: *mut libc::c_char", b"let mut p: *mut libc::c_char"),
|
||
|
|
(b" &p,", b" &mut p,")]:
|
||
|
|
if expected.count(before) != 1:
|
||
|
|
raise ValueError("Upstream patch context differs")
|
||
|
|
expected = expected.replace(before, after, 1)
|
||
|
|
actual = (vendor_root / name).read_bytes()
|
||
|
|
if actual != expected:
|
||
|
|
raise ValueError("Unexpected vendor modification: " + name)
|
||
|
|
if (records[name]["upstream_sha256"] != hashlib.sha256(original).hexdigest() or
|
||
|
|
records[name]["patched_sha256"] != hashlib.sha256(actual).hexdigest()):
|
||
|
|
raise ValueError("Provenance checksum mismatch: " + name)
|
||
|
|
return len(originals)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
root = Path(__file__).resolve().parents[2]
|
||
|
|
vendor = root / "apps/desktop/src-tauri/vendor"
|
||
|
|
count = verify(Path(sys.argv[1]), vendor / "glib",
|
||
|
|
vendor / "glib-backport/SEARCHI-BACKPORT.json")
|
||
|
|
print(f"Verified {count} official files; only the exact two-line upstream fix differs.")
|