fix: verify data-dir pack members by content

This commit is contained in:
Abdessamad Derraz committed 2026-10-10 12:08:13 +02:00
1 parent 3d0170264a
commit 14b32b38ba
2 files changed
+38 -1

No files matched your search

+15 -1
View File
@@ -19,6 +19,7 @@ from ziptools import check_inside_zip
from nativemode import digest_algorithm
from validation import settle_mismatch
from nativemode import hash_mismatch_excludes_file
import functools
import hashlib
from common import filter_systems_by_target
from common import load_emulator_profiles
@@ -35,6 +36,16 @@ import io
from collections.abc import Callable
@functools.lru_cache(maxsize=None)
def _file_sha1(path: str) -> str:
"""SHA-1 of a cached data-directory file, read once per run."""
digest = hashlib.sha1()
with open(path, "rb") as handle:
for chunk in iter(lambda: handle.read(1 << 20), b""):
digest.update(chunk)
return digest.hexdigest()
def _members_are_held(data: bytes, by_md5: dict, held_inside: dict) -> bool:
"""Whether every member of an archive is a dump the collection holds."""
try:
@@ -215,7 +226,10 @@ def verify_pack(
for _dp in _cands:
if not os.path.exists(_dp):
continue
if os.path.getsize(_dp) == size:
# The content, not the size: a member written corrupt
# keeps its length, and a same-sized homonym from another
# cache is another file.
if os.path.getsize(_dp) == size and _file_sha1(_dp) == sha1:
status = "verified_data"
file_name = _bn
break
+23
View File
@@ -43,6 +43,29 @@ class MembersMustBeKnown(unittest.TestCase):
self.assertTrue(any("garbled.bin" in e for e in manifest["errors"]))
class DataMembersAreCheckedByContent(unittest.TestCase):
"""A data-directory member was verified by name and size: bytes altered
while the pack was written kept their length and passed."""
def test_same_size_other_bytes_is_an_error(self):
good = b"A" * 64
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
cache = Path(tmp) / "cache"
(cache / "Sys").mkdir(parents=True)
(cache / "Sys" / "font.bin").write_bytes(good)
registry = {"demo": {"local_cache": str(cache)}}
db = {"files": {}, "indexes": {"by_md5": {}, "by_name": {}}}
pack = Path(tmp) / "P_BIOS_Pack.zip"
with zipfile.ZipFile(pack, "w") as zf:
zf.writestr("system/Sys/font.bin", good)
zf.writestr("system/Sys/other/font.bin", b"B" * 64)
ok, manifest = verify_pack(str(pack), db, registry)
statuses = {f["path"]: f["status"] for f in manifest["files"]}
self.assertEqual(statuses["system/Sys/font.bin"], "verified_data")
self.assertNotEqual(statuses["system/Sys/other/font.bin"], "verified_data")
self.assertFalse(ok)
class SchemaAcceptsEveryStatus(unittest.TestCase):
"""verified_members reached every pack manifest and the schema refused it."""