fix: fail a pack member the collection cannot name

This commit is contained in:
Abdessamad Derraz committed 2026-10-06 05:05:14 +02:00
1 parent 64516f2bdc
commit 62bae63bbf
2 files changed
+78

No files matched your search

+32
View File
@@ -31,6 +31,25 @@ from packresolve import resolve_file
from common import resolve_platform_cores
from common import sanitize_pack_path
import zipfile
def _members_are_held(data: bytes, by_md5: dict, db: dict) -> bool:
"""Whether every member of an archive is a dump the collection holds."""
import io
held_inside = build_zip_contents_index(db)
try:
with zipfile.ZipFile(io.BytesIO(data)) as archive:
members = [i for i in archive.infolist() if not i.is_dir()]
if not members:
return False
for info in members:
digest = hashlib.md5(archive.read(info)).hexdigest()
if digest not in by_md5 and digest not in held_inside:
return False
except (zipfile.BadZipFile, OSError):
return False
return True
def verify_pack(
zip_path: str, db: dict, data_registry: dict | None = None
) -> tuple[bool, dict]:
@@ -183,6 +202,19 @@ def verify_pack(
except (zipfile.BadZipFile, OSError):
continue
# An archive the builder assembled (a MAME clone set): every
# member must be a dump the collection holds, loose or inside a
# romset.
if status == "untracked" and name.endswith(".zip"):
if _members_are_held(zf.read(name), by_md5, db):
status = "verified_members"
file_name = os.path.basename(name)
if status == "untracked":
# Bytes nothing recognises: written wrong, or a source that
# no longer matches. Counted and passed, it went unseen.
errors.append(f"{name}: content matches no collected file")
manifest["files"].append(
{
"path": name,
+46
View File
@@ -0,0 +1,46 @@
"""Every pack member is bytes the collection recognises.
A member whose sha1 and md5 matched nothing was counted `untracked` with
zero errors and the pack passed, so bytes altered while the ZIP was written
went unseen. Archives the builder assembles (MAME clone sets) are
recognised by their members.
"""
from __future__ import annotations
import hashlib
import io
import sys
import tempfile
import unittest
import zipfile
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
class MembersMustBeKnown(unittest.TestCase):
def test_unknown_bytes_are_an_error_and_assembled_sets_pass(self):
from packverify import verify_pack
known = b"known rom" * 10
md5 = hashlib.md5(known).hexdigest()
inner = io.BytesIO()
with zipfile.ZipFile(inner, "w") as zf:
zf.writestr("rom.bin", known)
db = {"files": {}, "indexes": {"by_md5": {md5: "s"}, "by_name": {}}}
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
pack = Path(tmp) / "P_BIOS_Pack.zip"
with zipfile.ZipFile(pack, "w") as zf:
zf.writestr("clone.zip", inner.getvalue())
zf.writestr("garbled.bin", b"no such dump")
ok, manifest = verify_pack(str(pack), db)
statuses = {f["path"]: f["status"] for f in manifest["files"]}
self.assertEqual(statuses["clone.zip"], "verified_members")
self.assertFalse(ok)
self.assertTrue(any("garbled.bin" in e for e in manifest["errors"]))
if __name__ == "__main__":
unittest.main()