fix: restart Dever releases at 0.0.1 with complete signed assets
This commit is contained in:
1 parent
5589b657db
commit
faf8b168a7
22 files changed
+582
-94
No files matched your search
@@ -0,0 +1,105 @@
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import io
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
SOURCE = Path(__file__).resolve().parents[2] / "sdk/python-runtime.py"
|
||||
SPECIFICATION = importlib.util.spec_from_file_location("python_runtime", SOURCE)
|
||||
runtime = importlib.util.module_from_spec(SPECIFICATION)
|
||||
SPECIFICATION.loader.exec_module(runtime)
|
||||
|
||||
|
||||
class PythonRuntimeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temporary.cleanup)
|
||||
self.root = Path(self.temporary.name)
|
||||
|
||||
def archive(self, names):
|
||||
path = self.root / "python.tar.gz"
|
||||
with tarfile.open(path, "w:gz") as archive:
|
||||
for name in names:
|
||||
member = tarfile.TarInfo(name)
|
||||
member.size = 4
|
||||
archive.addfile(member, io.BytesIO(b"test"))
|
||||
return path
|
||||
|
||||
def test_only_runtime_files_are_selected(self):
|
||||
for name in ["python/bin/python3.13", "python/lib/libpython3.13.so.1.0",
|
||||
"python/lib/python3.13/LICENSE.txt", "python/lib/python3.13/asyncio/tasks.py"]:
|
||||
self.assertTrue(runtime.selected(name, "3.13"), name)
|
||||
for name in ["python/bin/python3", "python/bin/pip3", "python/include/python3.13/Python.h",
|
||||
"python/lib/python3.13/site-packages/pip/__init__.py",
|
||||
"python/lib/python3.13/test/test_os.py", "python/lib/python3.13/__pycache__/os.pyc"]:
|
||||
self.assertFalse(runtime.selected(name, "3.13"), name)
|
||||
|
||||
def test_wheel_tags_include_compatible_abis_without_claiming_newer_glibc(self):
|
||||
tags = runtime.wheel_tags("3.13", "linux-x86_64", (2, 17))
|
||||
self.assertEqual(tags[0], "cp313-cp313-manylinux_2_17_x86_64")
|
||||
self.assertEqual(len(tags), len(set(tags)))
|
||||
for tag in ["cp313-cp313-manylinux2014_x86_64", "cp39-abi3-manylinux_2_17_x86_64",
|
||||
"cp38-abi3-manylinux1_x86_64", "cp313-none-manylinux_2_17_x86_64",
|
||||
"cp313-cp313-linux_x86_64", "py313-none-any", "py3-none-any", "py38-none-any"]:
|
||||
self.assertIn(tag, tags)
|
||||
for tag in ["cp314-abi3-manylinux_2_17_x86_64", "cp312-cp312-manylinux_2_17_x86_64",
|
||||
"cp313-cp313-manylinux_2_28_x86_64"]:
|
||||
self.assertNotIn(tag, tags)
|
||||
arm_tags = runtime.wheel_tags("3.13", "linux-aarch64", (2, 17))
|
||||
self.assertIn("cp39-abi3-manylinux2014_aarch64", arm_tags)
|
||||
self.assertIn("cp313-cp313-linux_aarch64", arm_tags)
|
||||
self.assertFalse(any("manylinux1_" in tag or "manylinux2010_" in tag for tag in arm_tags))
|
||||
with self.assertRaises(ValueError):
|
||||
runtime.wheel_tags("3.13", "linux-aarch64", (2, 16))
|
||||
|
||||
def test_extraction_rejects_traversal_and_duplicates(self):
|
||||
for names in [["python/../escape"], ["/python/bin/python3.13"],
|
||||
["python/bin/python3.13", "python/bin/python3.13"]]:
|
||||
with self.subTest(names=names), self.assertRaises(ValueError):
|
||||
runtime.extract(self.archive(names), self.root / "output", "3.13")
|
||||
|
||||
def test_wrong_hash_does_not_create_output(self):
|
||||
archive = self.archive([])
|
||||
output = self.root / "output"
|
||||
with self.assertRaisesRegex(ValueError, "SHA-256"):
|
||||
runtime.prepare(archive, "0" * 64, "3.13.5", "linux-x86_64", (2, 17), SOURCE, output)
|
||||
self.assertFalse(output.exists())
|
||||
|
||||
def test_failure_cleans_owned_output_and_preserves_existing_output(self):
|
||||
archive = self.archive([])
|
||||
output = self.root / "output"
|
||||
digest = hashlib.sha256(archive.read_bytes()).hexdigest()
|
||||
with self.assertRaisesRegex(ValueError, "interpreter or license"):
|
||||
runtime.prepare(archive, digest, "3.13.5", "linux-x86_64", (2, 17), SOURCE, output)
|
||||
self.assertFalse(output.exists())
|
||||
output.mkdir()
|
||||
(output / "keep").write_text("existing")
|
||||
with self.assertRaises(FileExistsError):
|
||||
runtime.prepare(archive, digest, "3.13.5", "linux-x86_64", (2, 17), SOURCE, output)
|
||||
self.assertEqual((output / "keep").read_text(), "existing")
|
||||
|
||||
def test_newer_glibc_is_rejected_before_python_executes(self):
|
||||
binary = self.root / "python"
|
||||
binary.write_bytes(b"\x7fELF")
|
||||
text = "Machine: Advanced Micro Devices X86-64\nName: GLIBC_2.38\n"
|
||||
result = subprocess.CompletedProcess([], 0, text, "")
|
||||
with patch.object(runtime.subprocess, "run", return_value=result):
|
||||
with self.assertRaisesRegex(ValueError, "GLIBC_2.38"):
|
||||
runtime.check_elf(binary, SOURCE, "linux-x86_64", (2, 17))
|
||||
result.stdout = "Machine: AArch64\nName: GLIBC_2.17\n"
|
||||
with patch.object(runtime.subprocess, "run", return_value=result):
|
||||
with self.assertRaisesRegex(ValueError, "wrong target"):
|
||||
runtime.check_elf(binary, SOURCE, "linux-x86_64", (2, 17))
|
||||
result.stdout = "Machine: Advanced Micro Devices X86-64\nName: GLIBC_PRIVATE\n"
|
||||
with patch.object(runtime.subprocess, "run", return_value=result):
|
||||
with self.assertRaisesRegex(ValueError, "private glibc"):
|
||||
runtime.check_elf(binary, SOURCE, "linux-x86_64", (2, 17))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user