diff --git a/scripts/release_artifacts.py b/scripts/release_artifacts.py index 5562e3f..c82b8f3 100644 --- a/scripts/release_artifacts.py +++ b/scripts/release_artifacts.py @@ -187,7 +187,8 @@ def _verify_installed_files(artifact: Path, distribution: importlib.metadata.Dis if encoded_size and len(content) != int(encoded_size): raise SystemExit(f"installed file size differs from verified wheel: {relative}") verified_files += 1 - verified_native |= relative.startswith("msgspec_toon/_native") + normalized_relative = relative.replace("\\", "/") + verified_native |= normalized_relative.startswith("msgspec_toon/_native") if verified_files == 0 or not verified_native: raise SystemExit("verified wheel RECORD does not cover the native extension") diff --git a/tests/test_release_artifacts.py b/tests/test_release_artifacts.py index 4c4679f..f68c6e2 100644 --- a/tests/test_release_artifacts.py +++ b/tests/test_release_artifacts.py @@ -343,3 +343,31 @@ def locate_file(self, path: str) -> Path: installed.write_bytes(b"tampered-native-extension") with pytest.raises(SystemExit, match="differs from verified wheel"): artifacts_module._verify_installed_files(artifact, Distribution()) + + +def test_windows_record_path_covers_the_installed_native_extension( + artifacts_module: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + record_relative = r"msgspec_toon\_native.pyd" + installed_relative = "msgspec_toon/_native.pyd" + content = b"verified-windows-native-extension" + digest = base64.urlsafe_b64encode(hashlib.sha256(content).digest()).rstrip(b"=").decode() + artifact = tmp_path / "candidate.whl" + with zipfile.ZipFile(artifact, "w") as wheel: + wheel.writestr(installed_relative, content) + wheel.writestr( + "msgspec_toon-0.1.0.dist-info/RECORD", + f"{record_relative},sha256={digest},{len(content)}\n" + "msgspec_toon-0.1.0.dist-info/RECORD,,\n", + ) + prefix = tmp_path / "prefix" + installed = prefix / installed_relative + installed.parent.mkdir(parents=True) + installed.write_bytes(content) + + class Distribution: + def locate_file(self, path: str) -> Path: + return prefix / path.replace("\\", "/") + + monkeypatch.setattr(artifacts_module.sys, "prefix", str(prefix)) + artifacts_module._verify_installed_files(artifact, Distribution())