Require ELF closure verification when staging Linux speech runtime

This commit is contained in:
karl committed 2026-10-13 21:30:48 +02:00
1 parent e71cace91f
commit 61afa08b8b
3 files changed
+84

No files matched your search

+12
View File
@@ -1,6 +1,7 @@
"""Verify and atomically stage the isolated normal speech runtime; no inference."""
import argparse
import hashlib
import importlib.util
import json
from pathlib import Path
import re
@@ -28,6 +29,15 @@ def input_path(root, name):
return Path(root) / 'tools' / (name if '/' in name else 'speech-runtime/' + name)
def verify_linux_closure(directory):
# Load our pinned builder, never code from the candidate runtime directory.
path = ROOT / 'tools/speech-runtime/build.py'
spec = importlib.util.spec_from_file_location('searchi_speech_build', path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
module.verify_linux_closure(directory)
def inventory(directory):
path = Path(directory) / 'runtime-manifest.json'
if path.is_symlink() or not path.is_file() or not 0 < path.stat().st_size <= 512 * 1024:
@@ -84,6 +94,8 @@ def verify_directory(directory, root=ROOT, platform='windows', architecture='x86
'VULKAN-LICENSE.txt', 'MSVC-REDISTRIBUTION.txt'} | CRT_LIBRARIES
if platform == 'windows' and not windows_libraries.issubset(names):
raise ValueError('Speech runtime lacks required shared libraries')
if platform == 'linux':
verify_linux_closure(directory)
records = {'speech-runtime/' + record['path']: record for record in manifest['files']}
manifest_path = directory / 'runtime-manifest.json'
records['speech-runtime/runtime-manifest.json'] = {
+59
View File
@@ -3,12 +3,71 @@ from pathlib import Path
import shutil
import tempfile
import unittest
from unittest import mock
import stage_speech_worker as speech
import test_package_windows as windows
class SpeechStagingTests(unittest.TestCase):
def linux_fixture(self, directory):
root, resources, _, _ = windows.PackageTests().fixture(directory)
runtime = resources / 'speech-runtime'
manifest_path = runtime / 'runtime-manifest.json'
manifest = json.loads(manifest_path.read_text())
for record in manifest['files']:
(runtime / record['path']).unlink()
manifest['files'] = []
for name in ('searchi-speech-worker', 'libggml-cpu-x64.so', 'libggml-vulkan.so'):
path = runtime / name
path.write_bytes(b'ELF fixture inspected by mocked readelf')
manifest['files'].append({'path': name, 'bytes': path.stat().st_size,
'sha256': speech.digest(path)})
manifest_path.write_text(json.dumps(manifest))
return root, runtime
def test_linux_hash_valid_inventory_requires_elf_closure(self):
with tempfile.TemporaryDirectory() as directory:
root, runtime = self.linux_fixture(directory)
with mock.patch.object(speech, 'identity', return_value=('linux', 'x86_64', None)), \
mock.patch.object(speech, 'verify_linux_closure') as closure:
records = speech.verify_directory(runtime, root, platform='linux')
closure.assert_called_once_with(runtime)
self.assertIn('speech-runtime/searchi-speech-worker', records)
def test_linux_closure_failure_and_missing_readelf_are_not_bypassed(self):
for error in (ValueError('Unpackaged Linux speech dependency'),
FileNotFoundError('readelf is required')):
with self.subTest(error=type(error)), tempfile.TemporaryDirectory() as directory:
root, runtime = self.linux_fixture(directory)
with mock.patch.object(speech, 'identity', return_value=('linux', 'x86_64', None)), \
mock.patch.object(speech, 'verify_linux_closure', side_effect=error):
with self.assertRaises(type(error)):
speech.verify_directory(runtime, root, platform='linux')
def test_windows_does_not_require_elf_tools(self):
with tempfile.TemporaryDirectory() as directory:
root, resources, _, _ = windows.PackageTests().fixture(directory)
with mock.patch.object(speech, 'verify_linux_closure') as closure:
speech.verify_directory(resources / 'speech-runtime', root)
closure.assert_not_called()
def test_loaded_builder_checks_every_linux_elf_and_rejects_build_tree_runpath(self):
with tempfile.TemporaryDirectory() as directory:
_, runtime = self.linux_fixture(directory)
valid = '(RUNPATH) Library runpath: [$ORIGIN]\n(NEEDED) Shared library: [libc.so.6]\n'
with mock.patch('subprocess.check_output', return_value=valid) as readelf:
speech.verify_linux_closure(runtime)
self.assertEqual(readelf.call_count, 3)
self.assertEqual({call.args[0][2] for call in readelf.call_args_list},
{str(runtime / name) for name in
('searchi-speech-worker', 'libggml-cpu-x64.so', 'libggml-vulkan.so')})
self.assertTrue(all(call.args[0][:2] == ['readelf', '--dynamic']
for call in readelf.call_args_list))
with mock.patch('subprocess.check_output', return_value=valid.replace('$ORIGIN', '/build/whisper')):
with self.assertRaisesRegex(ValueError, 'origin-only RUNPATH'):
speech.verify_linux_closure(runtime)
def test_replacement_prunes_obsolete_declared_code_and_keeps_closed_inventory(self):
with tempfile.TemporaryDirectory() as directory:
root, resources, _, _ = windows.PackageTests().fixture(directory)