Ship portable CPU dispatch and verified shared runtime dependencies
This commit is contained in:
1 parent
278b09f82c
commit
0bba1a0aa7
19 files changed
+675
-17
No files matched your search
@@ -7,7 +7,7 @@ import unittest
|
||||
from unittest import mock
|
||||
import zipfile
|
||||
|
||||
from package_windows import package
|
||||
from package_windows import package, CRT_LIBRARIES
|
||||
|
||||
|
||||
def executable(path, machine=0x8664):
|
||||
@@ -20,6 +20,15 @@ def executable(path, machine=0x8664):
|
||||
path.write_bytes(data)
|
||||
|
||||
|
||||
def inventory(resources):
|
||||
worker = resources / "searchi-gemma-worker.exe"
|
||||
records = []
|
||||
for name in ["ggml-cpu-x64.dll", "ggml-vulkan.dll", "vulkan-1.dll", "ggml.dll", "ggml-base.dll", "llama.dll", "mtmd.dll", *sorted(CRT_LIBRARIES)]:
|
||||
data = (resources / name).read_bytes()
|
||||
records.append({"path": name, "bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()})
|
||||
(resources / "runtime-libraries.json").write_text(json.dumps({"worker_sha256": hashlib.sha256(worker.read_bytes()).hexdigest(), "libraries": records}))
|
||||
|
||||
|
||||
class PackageTests(unittest.TestCase):
|
||||
def fixture(self, directory):
|
||||
root = Path(directory)
|
||||
@@ -27,13 +36,16 @@ class PackageTests(unittest.TestCase):
|
||||
app = root / "build/app.exe"
|
||||
executable(app)
|
||||
(root / "LICENSE").write_text("application notice")
|
||||
for name in ["searchi-gemma-worker.exe", "vulkan-1.dll", "media-runtime/bin/ffmpeg.exe", "media-runtime/bin/ffprobe.exe"]:
|
||||
for name in ["searchi-gemma-worker.exe", "vulkan-1.dll", "ggml-cpu-x64.dll", "ggml-vulkan.dll", "ggml.dll", "ggml-base.dll", "llama.dll", "mtmd.dll", "media-runtime/bin/ffmpeg.exe", "media-runtime/bin/ffprobe.exe"]:
|
||||
executable(resources / name)
|
||||
for name in ["LLAMA-LICENSE.txt", "VULKAN-LICENSE.txt", "licenses/Inter-OFL.txt", "licenses/Fluent-MIT.txt", "media-runtime/licenses/LICENSE.txt", "media-runtime/manifest.json"]:
|
||||
for name in sorted(CRT_LIBRARIES):
|
||||
executable(resources / name)
|
||||
for name in ["LLAMA-LICENSE.txt", "MSVC-REDISTRIBUTION.txt", "VULKAN-LICENSE.txt", "licenses/Inter-OFL.txt", "licenses/Fluent-MIT.txt", "media-runtime/licenses/LICENSE.txt", "media-runtime/manifest.json"]:
|
||||
path = resources / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text("notice")
|
||||
(resources / "settings.json").write_text("private settings")
|
||||
inventory(resources)
|
||||
return root, resources, app, root / "archive.zip"
|
||||
|
||||
def test_complete_archive_excludes_settings_and_verifies_recorded_bytes(self):
|
||||
@@ -53,6 +65,7 @@ class PackageTests(unittest.TestCase):
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
executable(resources / "searchi-gemma-worker.exe", 0xAA64)
|
||||
inventory(resources)
|
||||
with self.assertRaisesRegex(ValueError, "architecture differs"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
@@ -109,10 +122,86 @@ class PackageTests(unittest.TestCase):
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
executable(resources / "vulkan-1.dll", 0xAA64)
|
||||
inventory(resources)
|
||||
with self.assertRaisesRegex(ValueError, "architecture differs: vulkan-1.dll"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
|
||||
def test_inventory_includes_dispatch_libraries_but_not_unlisted_dll(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
executable(resources / "private-plugin.dll")
|
||||
package(root, app, output)
|
||||
with zipfile.ZipFile(output) as archive:
|
||||
self.assertIn("ggml-cpu-x64.dll", archive.namelist())
|
||||
self.assertIn("ggml-vulkan.dll", archive.namelist())
|
||||
self.assertIn("runtime-libraries.json", archive.namelist())
|
||||
self.assertIn("msvcp140.dll", archive.namelist())
|
||||
self.assertIn("MSVC-REDISTRIBUTION.txt", archive.namelist())
|
||||
self.assertNotIn("private-plugin.dll", archive.namelist())
|
||||
|
||||
def test_missing_inventory_or_corrupt_library_preserves_archive(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
(resources / "ggml-cpu-x64.dll").write_bytes(b"corrupt")
|
||||
with self.assertRaisesRegex(ValueError, "checksum mismatch"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
(resources / "runtime-libraries.json").unlink()
|
||||
with self.assertRaisesRegex(ValueError, "inventory"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
|
||||
def test_dependency_change_during_copy_preserves_archive(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
original_open = zipfile.ZipFile.open
|
||||
|
||||
def mutate_library(archive, name, mode="r", *args, **kwargs):
|
||||
if name == "ggml-cpu-x64.dll" and mode == "w":
|
||||
library = resources / name
|
||||
library.write_bytes(library.read_bytes() + b"changed")
|
||||
return original_open(archive, name, mode, *args, **kwargs)
|
||||
|
||||
with mock.patch.object(zipfile.ZipFile, "open", mutate_library):
|
||||
with self.assertRaisesRegex(ValueError, "changed while packaging"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
self.assertEqual(list(output.parent.glob("*.partial")), [])
|
||||
|
||||
def test_missing_crt_or_notice_preserves_previous_archive(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
(resources / "msvcp140.dll").unlink()
|
||||
with self.assertRaisesRegex(ValueError, "msvcp140"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
executable(resources / "msvcp140.dll")
|
||||
(resources / "MSVC-REDISTRIBUTION.txt").unlink()
|
||||
with self.assertRaisesRegex(ValueError, "MSVC-REDISTRIBUTION"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
|
||||
def test_inventory_change_during_copy_preserves_previous_archive(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root, resources, app, output = self.fixture(directory)
|
||||
output.write_bytes(b"previous package")
|
||||
original_open = zipfile.ZipFile.open
|
||||
|
||||
def mutate_inventory(archive, name, mode="r", *args, **kwargs):
|
||||
if name == "runtime-libraries.json" and mode == "w":
|
||||
manifest = resources / name
|
||||
manifest.write_bytes(manifest.read_bytes() + b" ")
|
||||
return original_open(archive, name, mode, *args, **kwargs)
|
||||
|
||||
with mock.patch.object(zipfile.ZipFile, "open", mutate_inventory):
|
||||
with self.assertRaisesRegex(ValueError, "changed while packaging"):
|
||||
package(root, app, output)
|
||||
self.assertEqual(output.read_bytes(), b"previous package")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user