diff --git a/scripts/validate_pr.py b/scripts/validate_pr.py index 5d22f5cf2..e31edce6c 100644 --- a/scripts/validate_pr.py +++ b/scripts/validate_pr.py @@ -422,8 +422,7 @@ def validate_file( result.crc32 = hashes["crc32"] ext = os.path.splitext(filepath)[1].lower() - if ext in BLOCKED_EXTENSIONS: - result.add_check(False, f"Blocked file extension: {ext}") + blocked = ext in BLOCKED_EXTENSIONS too_large = result.size > MAX_FILE_SIZE if too_large: @@ -495,6 +494,22 @@ def validate_file( or profile_hashes.get("crc32", {}).get((result.crc32, None)) ) + if blocked: + # An executable is refused unless an emulator profile pins its exact + # bytes: PICO-8's pico8.exe and SDL2.dll are declared by sha1 from the + # official archive. A weak hash (md5, crc32) never vouches for code. + pinned = ( + profile_hashes.get("sha1", {}).get(result.sha1) + or profile_hashes.get("sha256", {}).get(hashes.get("sha256", "")) + ) + if pinned: + result.add_check( + True, + f"Executable whose bytes an emulator profile pins by sha1: {', '.join(sorted(pinned))}", + ) + else: + result.add_check(False, f"Blocked file extension: {ext}") + # The files of a ZIP no list declares whole, when the upload is one. members: list[str] | None = None if sha1_known: diff --git a/tests/test_validate_pr.py b/tests/test_validate_pr.py index ddb73a493..1a0fb66f4 100644 --- a/tests/test_validate_pr.py +++ b/tests/test_validate_pr.py @@ -79,6 +79,26 @@ class FileShapeChecks(_Fixture): self.assertFalse(result.passed) self.assertIn("Blocked file extension", result.to_markdown()) + def test_an_executable_a_profile_pins_by_sha1_passes(self): + """PICO-8's pico8.exe and SDL2.dll come from the official archive and + the lexaloffle profile pins their sha1: known bytes, not a payload.""" + import hashlib + data = b"MZ pinned" + rel = self._bios_file("bios/Lexaloffle/PICO-8/pico8.exe", data) + pins = {"sha1": {hashlib.sha1(data).hexdigest(): {"lexaloffle"}}} + result = validate_pr.validate_file(rel, None, EMPTY_HASHES, pins) + self.assertNotIn("Blocked file extension", result.to_markdown()) + self.assertIn("pins by sha1: lexaloffle", result.to_markdown()) + + def test_an_executable_known_only_by_md5_stays_refused(self): + import hashlib + data = b"MZ weak" + rel = self._bios_file("bios/Sony/PS/tool.exe", data) + pins = {"md5": {hashlib.md5(data).hexdigest(): {"someemu"}}} + result = validate_pr.validate_file(rel, None, EMPTY_HASHES, pins) + self.assertFalse(result.passed) + self.assertIn("Blocked file extension", result.to_markdown()) + def test_oversized_file_is_refused(self): rel = self._bios_file("bios/Sony/PS/big.bin") original = validate_pr.MAX_FILE_SIZE