diff --git a/scripts/packverify.py b/scripts/packverify.py index 087357f7..8a0d4d15 100644 --- a/scripts/packverify.py +++ b/scripts/packverify.py @@ -17,7 +17,7 @@ from packpaths import _register_path from ziptools import build_zip_contents_index from ziptools import check_inside_zip from nativemode import digest_algorithm -from validation import settle_mismatch +from validation import baseline_verdict from nativemode import hash_mismatch_excludes_file import functools import hashlib @@ -482,9 +482,11 @@ def _intentional_hash_exclusion( data_dir_registry=data_dir_registry, offline=True, ) - # The builder ships what the frontend would accept: the exact inner - # ROM of a zipped_file entry, or a file its own digest matches. - if settle_mismatch(entry, local_path, status, verification_mode) != "hash_mismatch": + # The builder's own verdict: a zipped_file archive is refused when the + # member is missing whatever the outer resolution said, a hash + # mismatch when the frontend's digest disagrees too. + _status, refusal = baseline_verdict(entry, local_path, status, verification_mode) + if refusal is None: return False return True diff --git a/scripts/validation.py b/scripts/validation.py index 6cd3d532..27ec20f7 100644 --- a/scripts/validation.py +++ b/scripts/validation.py @@ -694,26 +694,6 @@ def inner_rom_check(file_entry: dict, local_path: str) -> str: return result -def settle_mismatch( - file_entry: dict, local_path: str | None, status: str, verification_mode: str -) -> str: - """Upgrade a hash mismatch the frontend itself would accept. - - Batocera pins the md5 of a ROM inside the archive (zipped_file), and a - frontend that hashes one digest accepts a file whose other declared - hashes disagree. - """ - if status != "hash_mismatch" or not local_path: - return status - if file_entry.get("zipped_file"): - return "zip_exact" if inner_rom_check(file_entry, local_path) == "ok" else status - if hash_mismatch_excludes_file(verification_mode) and frontend_digest_matches( - file_entry, local_path, digest_algorithm(verification_mode) - ): - return "frontend_digest_exact" - return status - - def baseline_verdict( file_entry: dict, local_path: str | None, status: str, verification_mode: str ) -> tuple[str, str | None]: diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index b343fb5d..09832941 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -738,6 +738,26 @@ class OneBaselineVerdict(unittest.TestCase): ("name_exact", None), ) + def test_the_pack_check_reads_the_same_verdict(self): + """--verify-packs called the archive missing: its own rule looked + inside only after a hash_mismatch, and an archive found by name + without d32.rom is one the builder left out on purpose.""" + import hashlib + + from scripts.packverify import _intentional_hash_exclusion + + entry = {"name": "dragon32.zip", "zipped_file": "d32.rom", "md5": ""} + with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory: + path = self._archive(Path(directory), "other.rom") + sha1 = hashlib.sha1(Path(path).read_bytes()).hexdigest() + db = {"files": {sha1: {"path": path, "name": "dragon32.zip", "sha1": sha1}}, + "indexes": {"by_name": {"dragon32.zip": [sha1]}, "by_md5": {}, + "by_path_suffix": {}, "by_crc32": {}}} + self.assertTrue(_intentional_hash_exclusion([entry], db, verification_mode="md5")) + self.assertFalse( + _intentional_hash_exclusion([entry], db, verification_mode="existence") + ) + def test_a_release_asset_keeps_its_answer(self): from scripts.slots import apply_override