Package portable Linux runtime and verify Google CPU search

This commit is contained in:
karl committed 2026-10-13 00:43:20 +02:00
1 parent e3558a0104
commit 0b56ab553c
22 files changed
+1585 -16

No files matched your search

+85 -1
View File
@@ -3,6 +3,7 @@ import argparse
import hashlib
import json
import os
import platform
import re
from pathlib import Path
import shutil
@@ -17,6 +18,87 @@ WINDOWS_CRT_FILES = (
"msvcp140_atomic_wait.dll", "msvcp140_codecvt_ids.dll", "vccorlib140.dll",
"vcruntime140.dll", "vcruntime140_1.dll", "vcruntime140_threads.dll",
)
LINUX_CPU_VARIANTS = {"x64", "sse42", "sandybridge", "ivybridge", "piledriver", "haswell",
"skylakex", "cannonlake", "cascadelake", "icelake", "cooperlake", "zen4",
"alderlake", "sapphirerapids"}
LINUX_SYSTEM_LIBRARIES = {"libc.so.6", "libm.so.6", "libdl.so.2", "libpthread.so.0",
"librt.so.1", "libstdc++.so.6", "libgcc_s.so.1", "ld-linux-x86-64.so.2"}
def linux_dispatch(backend):
"""Only normal Linux Vulkan modes use the packaged shared-module layout."""
return (sys.platform.startswith("linux") and platform.machine().lower() in {"amd64", "x86_64"}
and backend in {"auto", "vulkan"})
def elf_dynamic(path):
"""Read ELF metadata without executing the artifact or following ldd hooks."""
output = subprocess.check_output(["readelf", "--dynamic", str(path)], text=True)
values = {}
for key, value in re.findall(r"\((NEEDED|SONAME|RUNPATH|RPATH)\).*?\[([^\]]+)\]", output):
values.setdefault(key, []).append(value)
return values
def bundle_linux_libraries(build):
"""Flatten approved SONAME files beside the worker and record dependency closure.
System libc/C++ ABI remains a declared distro compatibility gate. Vulkan's
loader is optional: only the dynamically loaded GPU module may depend on it.
Preflight precedes flattening; the preceding CMake build itself is not a
transactional release replacement. Staging performs that separate swap.
"""
build = Path(build)
worker = build / "searchi-gemma-worker"
candidates = [build / "bin" / f"lib{name}.so" for name in ("ggml", "ggml-base", "llama", "mtmd")]
candidates += [build / f"libggml-cpu-{variant}.so" for variant in sorted(LINUX_CPU_VARIANTS)]
candidates.append(build / "libggml-vulkan.so")
records = []
names = set()
for link in candidates:
if not link.is_file():
raise RuntimeError(f"Required Linux runtime library is missing: {link.name}")
source = link.resolve()
if not source.is_relative_to(build.resolve()) or not source.is_file():
raise RuntimeError("Linux runtime library escapes its build directory")
metadata = elf_dynamic(source)
sonames = metadata.get("SONAME", [])
module = link.parent == build
if ((not module and len(sonames) != 1) or len(sonames) > 1
or any(not re.fullmatch(r"lib[A-Za-z0-9_-]+\.so(?:\.\d+)*", name) for name in sonames)):
raise RuntimeError("Linux runtime has invalid or missing SONAME")
# Backend discovery uses the unversioned module filename; core linkage
# uses its SONAME. Both destinations are actual files, never symlinks.
name = link.name if module else sonames[0]
if name in names:
raise RuntimeError("Duplicate Linux runtime library")
names.add(name)
destination = build / name
records.append((source, destination, metadata))
all_names = names
for path, metadata in [(worker, elf_dynamic(worker)), *[(destination, metadata) for _, destination, metadata in records]]:
if metadata.get("RPATH") or metadata.get("RUNPATH") != ["$ORIGIN"]:
raise RuntimeError(f"Linux runtime requires origin-only RUNPATH: {path.name}")
needed = set(metadata.get("NEEDED", []))
allowed = all_names | LINUX_SYSTEM_LIBRARIES
if path.name == "libggml-vulkan.so":
allowed = allowed | {"libvulkan.so.1"}
if needed - allowed:
raise RuntimeError(f"Unpackaged Linux runtime dependency for {path.name}: {sorted(needed - allowed)}")
for source, destination, _ in records:
if destination != source:
if destination.is_symlink():
destination.unlink()
shutil.copy2(source, destination)
def checksum(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
inventory = {"platform": "linux", "worker_sha256": checksum(worker),
"libraries": [{"path": path.name, "bytes": path.stat().st_size, "sha256": checksum(path)}
for _, path, _ in sorted(records)]}
temporary = build / "runtime-libraries.json.partial"
temporary.write_text(json.dumps(inventory, indent=2), encoding="utf-8")
os.replace(temporary, build / "runtime-libraries.json")
def bundle_windows_crt(build):
@@ -90,7 +172,7 @@ def main():
reverse = subprocess.run(["git", "apply", "--reverse", "--check", str(patch)], cwd=source, capture_output=True)
if reverse.returncode:
raise RuntimeError("Runtime memory patch cannot be applied or verified")
if os.name == "nt" and args.backend != "cpu":
if (os.name == "nt" and args.backend != "cpu") or linux_dispatch(args.backend):
for patch_name in ["cpu-dispatch.patch", "cpu-only-loader.patch"]:
dispatch_patch = Path(__file__).with_name(patch_name)
check = subprocess.run(["git", "apply", "--check", str(dispatch_patch)], cwd=source, capture_output=True)
@@ -125,6 +207,8 @@ def main():
temporary = directory / "runtime-libraries.json.partial"
temporary.write_text(json.dumps(inventory, indent=2), encoding="utf-8")
os.replace(temporary, directory / "runtime-libraries.json")
if linux_dispatch(args.backend):
bundle_linux_libraries(build)
print(f"Runtime build complete: {build}")
+165
View File
@@ -0,0 +1,165 @@
"""Prove Linux auto CPU fallback with the Vulkan loader physically absent.
Run as root on x86_64 Linux with util-linux unshare/mount/umount and chroot.
This tool never escalates privileges. It launches itself inside a private mount
namespace and verifies that namespace before changing mount propagation. The
sealed chroot includes approved runtime files, standard C/C++ ABI libraries and
a read-only Google model, without Vulkan loaders, ICDs, drivers or GPU devices.
This tests missing-loader fallback, not GPU execution or distro compatibility.
"""
import argparse
import hashlib
import json
import math
import os
from pathlib import Path
import platform
import shutil
import subprocess
import sys
import tempfile
ABI = ("libc.so.6", "libm.so.6", "libdl.so.2", "libpthread.so.0",
"librt.so.1", "libstdc++.so.6", "libgcc_s.so.1")
def require(condition, message):
if not condition:
raise RuntimeError(message)
def checksum(path):
with Path(path).open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def namespace(pid="self"):
return Path(f"/proc/{pid}/ns/mnt").stat().st_ino
def isolated_check(args, commands):
# Check the still-live outer process as well as its recorded namespace.
# A direct child invocation in the outer namespace fails before any mount.
outer = namespace(args.outer_pid)
require(outer == args.outer_namespace and namespace() != outer,
"Private mount namespace was not established; refusing mount changes")
subprocess.run([commands["mount"], "--make-rprivate", "/"], check=True)
from stage_runtime import verify_runtime
worker = args.worker.resolve()
dependencies = verify_runtime(worker, True)
manifest = json.loads(Path(__file__).with_name("model-manifest.json").read_text())
artifact = manifest["files"][0]
model = args.models.resolve() / artifact["path"]
require(model.is_file() and model.stat().st_size == artifact["bytes"]
and checksum(model) == artifact["sha256"], "Google model verification failed")
base = Path(tempfile.gettempdir()).resolve()
root = Path(tempfile.mkdtemp(prefix="searchi-loader-chroot-", dir=base)).resolve()
require(root.parent == base and root.stat().st_uid == 0,
"Invalid owned chroot directory")
mounted = []
try:
app = root / "app"
app.mkdir()
for source in [worker, *dependencies]:
destination = app / source.name
shutil.copy2(source, destination)
require(checksum(source) == checksum(destination), "Copied runtime checksum mismatch")
abi_dir = root / "lib/x86_64-linux-gnu"
abi_dir.mkdir(parents=True)
for name in ABI:
shutil.copy2(Path("/lib/x86_64-linux-gnu") / name, abi_dir / name)
(root / "lib64").mkdir()
shutil.copy2("/lib64/ld-linux-x86-64.so.2", root / "lib64/ld-linux-x86-64.so.2")
(root / "models").mkdir()
mounted_model = root / "models/model.gguf"
mounted_model.touch()
proc = root / "proc"
proc.mkdir()
subprocess.run([commands["mount"], "--bind", str(model), str(mounted_model)], check=True)
mounted.append(mounted_model)
subprocess.run([commands["mount"], "-o", "remount,bind,ro", str(mounted_model)], check=True)
subprocess.run([commands["mount"], "-t", "proc", "-o", "ro,nosuid,nodev,noexec", "proc", str(proc)], check=True)
mounted.append(proc)
require(not (root / "dev").exists() and not (root / "etc").exists(),
"Unexpected devices or driver configuration in chroot")
require({path.name for path in abi_dir.iterdir()} == set(ABI), "Unexpected system library")
require({path.name for path in app.iterdir()} == {worker.name, *(p.name for p in dependencies)},
"Unexpected runtime file")
# The worker runs with no inherited loader/ggml variables and no CPU
# override: the absence of libvulkan must cause its actual auto fallback.
environment = {"PATH": "/usr/bin:/bin", "LANG": "C.UTF-8"}
process = subprocess.Popen([commands["chroot"], str(root), "/app/searchi-gemma-worker",
"--model", "/models/model.gguf", "--threads", "1", "--device", "auto"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, encoding="utf-8", env=environment)
try:
stdout, stderr = process.communicate(json.dumps({"op": "code_query",
"text": "retry failed requests with exponential backoff"}) + "\n", timeout=180)
except BaseException:
process.kill()
process.wait(timeout=10)
raise
require(process.returncode == 0, f"Worker failed: {stderr[-4096:]}")
lines = [json.loads(line) for line in stdout.splitlines()]
require(len(lines) == 2, "Unexpected protocol output")
hello, result = lines
require(hello.get("ready") and hello.get("device") == "cpu"
and not hello.get("vulkan_module_loaded") and result.get("ok")
and result.get("device") == "cpu", "Expected auto fallback to CPU without Vulkan loading")
vectors = result.get("vectors", [])
require(len(vectors) == 1 and len(vectors[0]) == 768
and all(isinstance(v, (float, int)) and math.isfinite(v) for v in vectors[0]),
"Invalid real Google vector")
norm = math.sqrt(sum(value * value for value in vectors[0]))
require(abs(norm - 1) < .001, "Google vector is not normalized")
evidence = {"platform": "linux", "device_requested": "auto", "forced_cpu": False,
"gpu_execution": False, "vulkan_loader_present": False,
"seal": {"system_abi": list(ABI), "proc_read_only": True, "model_read_only": True,
"private_mount_namespace_verified": True, "gpu_devices": False,
"icd_manifests": False, "environment": environment},
"worker_sha256": checksum(worker), "model_sha256": checksum(model),
"hello": hello, "dimensions": len(vectors[0]), "norm": norm,
"limitations": ["Actual GPU and driver recovery untested", "Distribution ABI compatibility untested"]}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"auto_without_loader": "cpu", "cpu_module": hello["cpu_backend_module"],
"vulkan_loaded": False}))
finally:
failures = []
for path in reversed(mounted):
result = subprocess.run([commands["umount"], str(path)], check=False)
if result.returncode:
failures.append(str(path))
# Never recursively remove a directory containing a live bind mount.
require(not failures, f"Mount cleanup failed; preserved owned directory {root}")
require(root.parent == base and root.name.startswith("searchi-loader-chroot-"),
"Refusing cleanup outside owned temporary directory")
shutil.rmtree(root)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--worker", type=Path, required=True)
parser.add_argument("--models", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--outer-pid", type=int, help=argparse.SUPPRESS)
parser.add_argument("--outer-namespace", type=int, help=argparse.SUPPRESS)
args = parser.parse_args()
require(sys.platform.startswith("linux") and platform.machine().lower() in {"amd64", "x86_64"},
"Run this check on x86_64 Linux")
require(os.geteuid() == 0, "Run explicitly as root; this tool does not escalate privileges")
commands = {name: shutil.which(name) for name in ("unshare", "mount", "umount", "chroot")}
require(all(commands.values()), "Install util-linux mount tools and chroot")
if args.outer_pid is not None or args.outer_namespace is not None:
require(args.outer_pid is not None and args.outer_namespace is not None,
"Incomplete namespace handoff")
isolated_check(args, commands)
else:
subprocess.run([commands["unshare"], "--mount", "--fork", sys.executable, str(Path(__file__).resolve()),
"--worker", str(args.worker.resolve()), "--models", str(args.models.resolve()),
"--output", str(args.output.resolve()), "--outer-pid", str(os.getpid()),
"--outer-namespace", str(namespace())], check=True)
if __name__ == "__main__":
main()
+106
View File
@@ -0,0 +1,106 @@
"""Exercise a real Linux distribution worker on CPU, outside its build directory.
This checks genuine Google inference and origin-relative runtime packaging.
It does not certify GPU operation, older processors or a Linux desktop.
"""
import argparse
import hashlib
import json
import math
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import time
def sha256(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--worker", type=Path, required=True)
parser.add_argument("--models", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--baseline", action="store_true")
args = parser.parse_args()
if os.name != "posix" or not Path("/proc/self/exe").exists():
parser.error("Run this check natively on Linux")
# Reuse exactly the staging verifier: hashes and bounded inventory names
# must agree with what enters a distribution.
from stage_runtime import verify_runtime
dependencies = verify_runtime(args.worker.resolve(), True)
manifest = json.loads(Path(__file__).with_name("model-manifest.json").read_text())
model = args.models.resolve() / manifest["files"][0]["path"]
if model.stat().st_size != manifest["files"][0]["bytes"] or sha256(model) != manifest["files"][0]["sha256"]:
raise RuntimeError("Google model checksum mismatch")
with tempfile.TemporaryDirectory(prefix="searchi-linux-smoke-") as temporary:
target = Path(temporary)
copied = []
for source in [args.worker.resolve(), *dependencies]:
# Only exact approved CPU module names are omitted. Core libraries
# and GPU support remain present in the baseline extraction.
if args.baseline and source.name.startswith("libggml-cpu-") and source.name != "libggml-cpu-x64.so":
continue
destination = target / source.name
shutil.copy2(source, destination)
if sha256(destination) != sha256(source):
raise RuntimeError("Extracted runtime checksum mismatch")
copied.append(source.name)
worker = target / args.worker.name
dynamic = subprocess.check_output(["readelf", "-d", str(worker)], text=True)
if "libvulkan" in dynamic or "libggml-vulkan" in dynamic:
raise RuntimeError("Worker requires Vulkan at process startup; CPU fallback cannot work without the loader")
if "$ORIGIN" not in dynamic:
raise RuntimeError("Worker lacks origin-relative runtime lookup")
environment = dict(os.environ, SEARCHI_FORCE_CPU="1", GGML_DISABLE_VULKAN="1")
environment.pop("LD_LIBRARY_PATH", None)
environment.pop("GGML_BACKEND_PATH", None)
started = time.perf_counter()
process = subprocess.Popen([str(worker), "--model", str(model), "--threads", "1", "--device", "cpu"],
cwd=target, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
text=True, encoding="utf-8", env=environment)
try:
stdout, stderr = process.communicate(json.dumps({"op": "code_query", "text": "retry failed requests with exponential backoff"}) + "\n", timeout=180)
except BaseException:
process.kill()
process.wait(timeout=10)
raise
elapsed_ms = (time.perf_counter() - started) * 1000
if process.returncode:
raise RuntimeError(f"Worker failed ({process.returncode}): {stderr[-4096:]}")
lines = [json.loads(line) for line in stdout.splitlines()]
if len(lines) != 2:
raise RuntimeError("Unexpected worker protocol output")
hello, result = lines
if not hello.get("ready") or hello.get("device") != "cpu" or not result.get("ok") or result.get("device") != "cpu":
raise RuntimeError("Expected genuine ready CPU inference")
if hello.get("vulkan_module_loaded"):
raise RuntimeError("CPU check loaded a Vulkan provider")
vectors = result.get("vectors")
vector = vectors[0] if isinstance(vectors, list) and len(vectors) == 1 else None
if not isinstance(vector, list) or len(vector) != 768 or not all(isinstance(value, (int, float)) and math.isfinite(value) for value in vector):
raise RuntimeError("Invalid Google embedding vector")
norm = math.sqrt(sum(value * value for value in vector))
if abs(norm - 1) > 0.001:
raise RuntimeError("Google vector is not normalized")
module = hello.get("cpu_backend_module", "")
if args.baseline and module != "libggml-cpu-x64.so":
raise RuntimeError(f"Baseline extraction selected unexpected CPU module: {module}")
evidence = {"platform": "linux", "cpu_only": True, "baseline_only_extraction": args.baseline,
"worker_sha256": sha256(args.worker), "model_sha256": sha256(model),
"files": sorted(copied), "hello": hello, "dimensions": len(vector), "norm": norm,
"startup_query_exit_ms": elapsed_ms,
"timing_scope": "single diagnostic smoke sample; not a performance benchmark",
"worker_dynamic_section": dynamic,
"limitations": ["GPU untested", "older physical CPUs untested", "desktop and installer untested", "system-loader absence not physically exercised"]}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"ready": True, "cpu_module": module, "dimensions": 768, "baseline": args.baseline}))
if __name__ == "__main__":
main()
+21 -6
View File
@@ -15,6 +15,11 @@ ROOT = Path(__file__).resolve().parents[2]
CRT_LIBRARIES = {"concrt140.dll", "msvcp140.dll", "msvcp140_1.dll", "msvcp140_2.dll", "msvcp140_atomic_wait.dll", "msvcp140_codecvt_ids.dll", "vccorlib140.dll", "vcruntime140.dll", "vcruntime140_1.dll", "vcruntime140_threads.dll"}
def library_name(name):
return isinstance(name, str) and bool(re.fullmatch(
r"(?:[A-Za-z0-9_-]+\.dll|lib[A-Za-z0-9_-]+\.so(?:\.\d+)*)", name))
def _is_link(path):
"""Reject Windows reparse points, including junctions, on Python 3.11+."""
path = Path(path)
@@ -208,7 +213,7 @@ def _previous_owned(destination):
raise RuntimeError("Invalid previous runtime inventory")
for record in records:
name = record.get("path") if isinstance(record, dict) else None
if not isinstance(name, str) or not re.fullmatch(r"[A-Za-z0-9_-]+\.dll", name):
if not library_name(name):
raise RuntimeError("Invalid previous runtime library path")
names.add(name)
return names
@@ -345,7 +350,7 @@ def verify_runtime(source, required=False):
if not isinstance(record, dict):
raise RuntimeError("Invalid runtime library metadata")
name = record.get("path", "")
if not isinstance(name, str) or not re.fullmatch(r"[A-Za-z0-9_-]+\.dll", name) or name.lower() in names:
if not library_name(name) or name.lower() in names:
raise RuntimeError("Invalid or duplicate runtime library path")
names.add(name.lower())
artifact = source.parent / name
@@ -361,8 +366,17 @@ def verify_runtime(source, required=False):
if hashlib.file_digest(stream, "sha256").hexdigest() != checksum:
raise RuntimeError(f"Runtime library checksum mismatch: {name}")
paths.append(artifact)
if required and not ({"ggml-cpu-x64.dll", "ggml-vulkan.dll", "vulkan-1.dll", "ggml.dll", "ggml-base.dll", "llama.dll", "mtmd.dll"} | CRT_LIBRARIES).issubset(names):
raise RuntimeError("Runtime inventory lacks required CPU/GPU libraries")
if required:
if (source.suffix == ".exe") == (manifest.get("platform") == "linux"):
raise RuntimeError("Runtime inventory platform does not match worker")
if manifest.get("platform") == "linux":
core = {"ggml", "ggml-base", "llama", "mtmd"}
present = {name for name in core if any(re.fullmatch(rf"lib{re.escape(name)}\.so(?:\.\d+)*", file) for file in names)}
complete = present == core and {"libggml-cpu-x64.so", "libggml-vulkan.so"}.issubset(names)
else:
complete = ({"ggml-cpu-x64.dll", "ggml-vulkan.dll", "vulkan-1.dll", "ggml.dll", "ggml-base.dll", "llama.dll", "mtmd.dll"} | CRT_LIBRARIES).issubset(names)
if not complete:
raise RuntimeError("Runtime inventory lacks required CPU/GPU libraries")
return [inventory, *paths]
@@ -401,7 +415,8 @@ def main():
license_path = ROOT / ".searchi/references/llama.cpp/LICENSE"
if not license_path.is_file():
raise RuntimeError("Native worker license is missing")
dependencies = verify_runtime(source, os.name == "nt" and args.backend in {"auto", "vulkan"})
required_inventory = (os.name == "nt" or os.sys.platform.startswith("linux")) and args.backend in {"auto", "vulkan"}
dependencies = verify_runtime(source, required_inventory)
crt_notice = source.parent / "MSVC-REDISTRIBUTION.txt"
if os.name == "nt" and args.backend != "cpu":
if not crt_notice.is_file():
@@ -425,7 +440,7 @@ def main():
sources.extend((path, f"embeddinggemma2/{path.name}") for path in artifacts)
def validate(candidate):
verify_runtime(candidate / source.name, os.name == "nt" and args.backend in {"auto", "vulkan"})
verify_runtime(candidate / source.name, required_inventory)
if model_manifest:
for artifact, spec in zip(artifacts, model_manifest["files"], strict=True):
if _record(candidate / "embeddinggemma2" / artifact.name) != (spec["bytes"], spec["sha256"]):
@@ -1,11 +1,87 @@
"""Redistributable preparation tests; no native builds or GPU execution."""
from pathlib import Path
import json
import tempfile
import unittest
from unittest.mock import patch
import build_runtime
from build_runtime import bundle_windows_crt, WINDOWS_CRT_FILES
class LinuxRuntimeTests(unittest.TestCase):
def test_only_normal_linux_vulkan_modes_use_shared_dispatch(self):
with patch.object(build_runtime.sys, "platform", "linux"), patch.object(build_runtime.platform, "machine", return_value="x86_64"):
for backend in ["auto", "vulkan"]:
self.assertTrue(build_runtime.linux_dispatch(backend))
for backend in ["cpu", "cuda", "metal"]:
self.assertFalse(build_runtime.linux_dispatch(backend))
with patch.object(build_runtime.sys, "platform", "darwin"):
self.assertFalse(build_runtime.linux_dispatch("auto"))
with patch.object(build_runtime.sys, "platform", "linux"), patch.object(build_runtime.platform, "machine", return_value="aarch64"):
self.assertFalse(build_runtime.linux_dispatch("auto"))
self.assertFalse(build_runtime.linux_dispatch("vulkan"))
def test_readelf_parses_needed_soname_and_runpath_without_executing_worker(self):
output = " 0x1 (NEEDED) Shared library: [libggml.so.0]\n 0xe (SONAME) Library soname: [libggml-cpu-x64.so]\n 0x1d (RUNPATH) Library runpath: [$ORIGIN]\n"
with patch.object(build_runtime.subprocess, "check_output", return_value=output) as command:
result = build_runtime.elf_dynamic(Path("worker"))
self.assertEqual(result, {"NEEDED": ["libggml.so.0"], "SONAME": ["libggml-cpu-x64.so"], "RUNPATH": ["$ORIGIN"]})
command.assert_called_once_with(["readelf", "--dynamic", "worker"], text=True)
def fixture(self, root):
root = Path(root)
(root / "bin").mkdir()
(root / "searchi-gemma-worker").write_bytes(b"worker")
for name in ["ggml", "ggml-base", "llama", "mtmd"]:
(root / "bin" / f"lib{name}.so").write_bytes(name.encode())
for variant in build_runtime.LINUX_CPU_VARIANTS:
(root / f"libggml-cpu-{variant}.so").write_bytes(variant.encode())
(root / "libggml-vulkan.so").write_bytes(b"vulkan")
return root
def metadata(self, path):
result = {"RUNPATH": ["$ORIGIN"], "NEEDED": ["libstdc++.so.6", "libc.so.6"]}
if path.parent.name == "bin":
result["SONAME"] = [path.name + ".0"]
if path.name == "libggml-vulkan.so":
result["NEEDED"].append("libvulkan.so.1")
return result
def test_flattened_core_and_bounded_modules_have_hashed_inventory(self):
with tempfile.TemporaryDirectory() as directory:
root = self.fixture(directory)
with patch.object(build_runtime, "elf_dynamic", side_effect=self.metadata):
build_runtime.bundle_linux_libraries(root)
manifest = json.loads((root / "runtime-libraries.json").read_text())
self.assertEqual(manifest["platform"], "linux")
self.assertEqual(len(manifest["libraries"]), 5 + len(build_runtime.LINUX_CPU_VARIANTS))
self.assertTrue((root / "libllama.so.0").is_file())
self.assertTrue(all(not (root / item["path"]).is_symlink() for item in manifest["libraries"]))
self.assertTrue(all(len(item["sha256"]) == 64 for item in manifest["libraries"]))
def test_startup_gpu_dependency_and_build_tree_rpath_are_rejected(self):
for problem in ["gpu", "rpath", "missing"]:
with self.subTest(problem=problem), tempfile.TemporaryDirectory() as directory:
root = self.fixture(directory)
previous = root / "libllama.so.0"
previous.write_bytes(b"previous flattened core")
def metadata(path):
result = self.metadata(path)
if path.name == "searchi-gemma-worker":
if problem == "gpu":
result["NEEDED"].append("libvulkan.so.1")
elif problem == "rpath":
result["RUNPATH"] = ["/private/build"]
else:
result["NEEDED"].append("libunpackaged.so.9")
return result
with patch.object(build_runtime, "elf_dynamic", side_effect=metadata), self.assertRaises(RuntimeError):
build_runtime.bundle_linux_libraries(root)
self.assertFalse((root / "runtime-libraries.json").exists())
self.assertEqual(previous.read_bytes(), b"previous flattened core")
class CrtTests(unittest.TestCase):
def fixture(self, directory):
root = Path(directory)
@@ -0,0 +1,28 @@
"""Namespace guards must reject unsafe handoffs before any mount operation."""
import argparse
import unittest
from unittest.mock import patch
import linux_loader_smoke
class NamespaceGuardTests(unittest.TestCase):
def test_same_namespace_refuses_mount_before_runtime_access(self):
args = argparse.Namespace(outer_pid=123, outer_namespace=42)
with patch.object(linux_loader_smoke, "namespace", return_value=42), \
patch.object(linux_loader_smoke.subprocess, "run") as run:
with self.assertRaisesRegex(RuntimeError, "Private mount namespace"):
linux_loader_smoke.isolated_check(args, {"mount": "mount"})
run.assert_not_called()
def test_changed_outer_namespace_refuses_mount(self):
args = argparse.Namespace(outer_pid=123, outer_namespace=42)
with patch.object(linux_loader_smoke, "namespace", return_value=43), \
patch.object(linux_loader_smoke.subprocess, "run") as run:
with self.assertRaisesRegex(RuntimeError, "Private mount namespace"):
linux_loader_smoke.isolated_check(args, {"mount": "mount"})
run.assert_not_called()
if __name__ == "__main__":
unittest.main()
@@ -12,6 +12,44 @@ import stage_runtime
class StagingTests(unittest.TestCase):
def test_linux_inventory_stages_core_and_modules_and_removes_previous_owned_library(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
runtime = root / "build"
runtime.mkdir()
worker = runtime / "searchi-gemma-worker"
worker.write_bytes(b"ELF fixture for integrity, not executable inference")
names = ["libggml.so.0", "libggml-base.so.0", "libllama.so.0", "libmtmd.so.0",
"libggml-cpu-x64.so", "libggml-vulkan.so"]
records = []
for name in names:
path = runtime / name
path.write_bytes(name.encode())
records.append({"path": name, "bytes": path.stat().st_size,
"sha256": hashlib.sha256(path.read_bytes()).hexdigest()})
inventory = runtime / "runtime-libraries.json"
inventory.write_text(json.dumps({"platform": "linux", "worker_sha256": hashlib.sha256(worker.read_bytes()).hexdigest(), "libraries": records}))
dependencies = stage_runtime.verify_runtime(worker, True)
destination = root / "resources"
destination.mkdir()
(destination / "libggml-cpu-old.so").write_bytes(b"old owned backend")
(destination / "runtime-libraries.json").write_text(json.dumps({"libraries": [{"path": "libggml-cpu-old.so"}]}))
(destination / "note.txt").write_bytes(b"unrelated")
stage_runtime.stage_resources(destination, [(worker, worker.name), *[(path, path.name) for path in dependencies]],
lambda candidate: stage_runtime.verify_runtime(candidate / worker.name, True))
self.assertFalse((destination / "libggml-cpu-old.so").exists())
self.assertEqual((destination / "note.txt").read_bytes(), b"unrelated")
self.assertEqual(len(stage_runtime.verify_runtime(destination / worker.name, True)), 7)
(destination / "libggml-vulkan.so").write_bytes(b"corrupt")
with self.assertRaises(RuntimeError):
stage_runtime.verify_runtime(destination / worker.name, True)
def test_runtime_library_names_reject_paths_and_unbounded_suffixes(self):
for name in ["../libggml.so", "libggml.so.x", "libggml.so/1", "libggml.so..1", "ggml.dylib"]:
with self.subTest(name=name):
self.assertFalse(stage_runtime.library_name(name))
self.assertTrue(stage_runtime.library_name("libggml-base.so.0.13.0"))
def resources(self, directory):
root = Path(directory)
destination = root / "src-tauri/resources"
+132
View File
@@ -0,0 +1,132 @@
"""Check a real extracted Linux headless candidate using Google CPU inference.
This is an installed-layout smoke test, not a broad relevance benchmark or
clean-machine certification. No GPU provider or network setup is exercised.
"""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import tarfile
import tempfile
import time
ROOT = Path(__file__).resolve().parents[1]
MAX_FILE = 256 * 1024 * 1024
def sha256(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def extract_checked(archive_path, destination):
from package_linux import safe_name
with tarfile.open(archive_path, "r:gz") as archive:
members = archive.getmembers()
if not 1 <= len(members) <= 128 or len({item.name for item in members}) != len(members):
raise ValueError("Invalid candidate member inventory")
for member in members:
safe_name(member.name)
if not member.isfile() or not 0 < member.size <= MAX_FILE:
raise ValueError("Unexpected candidate member")
manifest_member = archive.getmember("PACKAGE.json")
if manifest_member.size > 65536:
raise ValueError("Oversized candidate manifest")
manifest = json.load(archive.extractfile(manifest_member))
records = manifest["files"]
expected = {record["path"]: record for record in records}
if (manifest.get("platform") != "linux" or manifest.get("architecture") != "x86_64"
or len(expected) != len(records) or set(expected) != {member.name for member in members} - {"PACKAGE.json"}
or sum(member.size for member in members) > 1024 * 1024 * 1024):
raise ValueError("Candidate inventory does not cover archive")
for member in members:
target = destination / member.name
if not target.resolve().is_relative_to(destination.resolve()):
raise ValueError("Candidate path escapes extraction")
target.parent.mkdir(parents=True, exist_ok=True)
with archive.extractfile(member) as source, target.open("xb") as output:
shutil.copyfileobj(source, output, length=65536)
if member.name != "PACKAGE.json":
record = expected[member.name]
mode = int(record["mode"], 8)
if (target.stat().st_size != record["bytes"] or sha256(target) != record["sha256"]
or mode not in {0o644, 0o755} or member.mode != mode):
raise ValueError("Candidate bytes or permissions mismatch")
target.chmod(mode)
return manifest
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--archive", type=Path, required=True)
parser.add_argument("--models", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
if os.name != "posix" or not Path("/proc/self/exe").exists():
parser.error("Run natively on Linux")
models = args.models.resolve()
environment = dict(os.environ, SEARCHI_FORCE_CPU="1", GGML_DISABLE_VULKAN="1")
environment.pop("LD_LIBRARY_PATH", None)
environment.pop("GGML_BACKEND_PATH", None)
environment.pop("SEARCHI_FFMPEG_PATH", None)
environment.pop("SEARCHI_FFPROBE_PATH", None)
timings = {}
with tempfile.TemporaryDirectory(prefix="searchi archive QA ") as directory:
root = Path(directory)
installed = root / "installed"
installed.mkdir()
manifest = extract_checked(args.archive, installed)
cli, worker = installed / "searchi", installed / "searchi-gemma-worker"
corpus = root / "corpus"
corpus.mkdir()
(corpus / "supplier.md").write_text("The supplier partnership may be ended with sixty days written notice.\n", encoding="utf-8")
(corpus / "retry.py").write_text("import time\n\ndef fetch_with_backoff(operation):\n delay = 1\n for attempt in range(5):\n try:\n return operation()\n except Exception:\n time.sleep(delay)\n delay *= 2\n", encoding="utf-8")
shutil.copy2(ROOT / "crates/searchi-semantic/tests/fixtures/digup-speech.wav", corpus / "speech.wav")
db = root / "index.sqlite"
def run(label, arguments, json_output=False):
started = time.perf_counter()
output = subprocess.run([str(cli), *map(str, arguments)], cwd=installed, env=environment,
check=True, capture_output=True, text=True, encoding="utf-8", timeout=180)
timings[label] = (time.perf_counter() - started) * 1000
return json.loads(output.stdout) if json_output else output.stdout
run("help", ["--help"])
run("index", ["index", "--db", db, "--root", corpus])
# Omit explicit decoder paths to exercise installed helper discovery.
report = run("embed", ["embed", "--db", db, "--model-dir", models,
"--embedding-worker", worker, "--cpu-threads", "1"], True)
if report["media_files"] != 1 or report["media_failures"] != 0 or report["passages"] != 2 or report["chunks"] < 3:
raise RuntimeError("Installed mixed document/code/audio indexing failed")
model_arguments = ["--model-dir", models, "--embedding-worker", worker, "--cpu-threads", "1"]
hits = run("semantic_search", ["search", "--db", db,
"Wie beenden wir die Zusammenarbeit mit dem Lieferanten?", "--json", *model_arguments], True)
if not hits or hits[0]["filename"] != "supplier.md" or "sixty days" not in hits[0]["snippet"] or not hits[0]["source"]:
raise RuntimeError("Installed Google semantic search lost the supplier passage")
code = run("code_search", ["search", "--db", db,
"recover from transient network failures with increasing delays", "--code-only", "--json", *model_arguments], True)
if not code or code[0]["filename"] != "retry.py" or code[0]["source"]["kind"] != "line":
raise RuntimeError("Installed scoped code search lost its citation")
restricted = run("strict_filter", ["search", "--db", db, "supplier cancellation",
"--extension", "pdf", "--json", *model_arguments], True)
if restricted:
raise RuntimeError("Installed semantic search violated extension filter")
evidence = {"platform": "linux-x86_64", "cpu_only": True,
"archive_sha256": sha256(args.archive), "archive_bytes": args.archive.stat().st_size,
"verified_files": len(manifest["files"]), "extraction_path_contains_spaces": True,
"automatic_media_helper_discovery": "passed", "embedding_report": report,
"semantic_top_filename": hits[0]["filename"], "code_source": code[0]["source"],
"strict_filter": "passed", "command_elapsed_ms": timings,
"timing_scope": "single deployment smoke samples; not retrieval/performance benchmarks",
"limitations": ["GPU untested", "desktop untested", "clean-machine/ABI coverage untested", "broad retrieval quality untested"]}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"passed": True, "verified_files": evidence["verified_files"], "media_files": report["media_files"]}))
if __name__ == "__main__":
main()
+259
View File
@@ -0,0 +1,259 @@
"""Package an already-built Linux x86-64 headless development candidate.
No artifact is executed. readelf inspects dependency closure; native execution,
ABI compatibility, GPU hardware and production installers remain release gates.
"""
import argparse
import gzip
import hashlib
import io
import json
import os
from pathlib import Path, PurePosixPath
import re
import struct
import subprocess
import tarfile
import tempfile
ROOT = Path(__file__).resolve().parents[1]
MAX_FILE = 256 * 1024 * 1024
MAX_TOTAL = 1024 * 1024 * 1024
CPU_VARIANTS = {"x64", "sse42", "sandybridge", "ivybridge", "piledriver", "haswell",
"skylakex", "cannonlake", "cascadelake", "icelake", "cooperlake", "zen4",
"alderlake", "sapphirerapids"}
SYSTEM = {"libc.so.6", "libm.so.6", "libdl.so.2", "libpthread.so.0", "librt.so.1",
"libmvec.so.1", "libstdc++.so.6", "libgcc_s.so.1", "ld-linux-x86-64.so.2"}
def safe_name(name):
if (not isinstance(name, str) or not name or "\\" in name or ":" in name
or str(PurePosixPath(name)) != name or PurePosixPath(name).is_absolute()
or any(part in {".", ".."} for part in name.split("/"))):
raise ValueError("Unsafe package path")
return name
def regular(path, parent):
path, parent = Path(path).absolute(), Path(parent).resolve()
if not path.is_relative_to(parent) or not path.resolve().is_relative_to(parent):
raise ValueError("Package source escapes its directory")
candidate = path
while candidate != parent:
if candidate.is_symlink():
raise ValueError("Package source contains a symlink")
candidate = candidate.parent
if not path.is_file() or not 0 < path.stat().st_size <= MAX_FILE:
raise ValueError(f"Missing or oversized package source: {path.name}")
def digest(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def elf_x64(path):
with path.open("rb") as stream:
header = stream.read(64)
if (len(header) != 64 or header[:7] != b"\x7fELF\x02\x01\x01"
or struct.unpack_from("<H", header, 18)[0] != 62
or struct.unpack_from("<H", header, 16)[0] not in {2, 3}):
raise ValueError(f"Expected Linux x86-64 ELF artifact: {path.name}")
def dynamic(path):
output = subprocess.check_output(["readelf", "--dynamic", str(path)], text=True, timeout=30)
values = {}
for key, value in re.findall(r"\((NEEDED|SONAME|RUNPATH|RPATH)\).*?\[([^\]]+)\]", output):
values.setdefault(key, []).append(value)
return values
def runtime_files(runtime):
inventory = runtime / "runtime-libraries.json"
regular(inventory, runtime)
if inventory.stat().st_size > 65536:
raise ValueError("Oversized runtime inventory")
inventory_bytes = inventory.read_bytes()
manifest = json.loads(inventory_bytes)
records = manifest.get("libraries") if isinstance(manifest, dict) else None
if not isinstance(manifest, dict) or manifest.get("platform") != "linux" or not isinstance(records, list) or not 1 <= len(records) <= 64:
raise ValueError("Invalid Linux runtime inventory")
expected = {"searchi-gemma-worker": {"sha256": manifest.get("worker_sha256")}}
core = {}
for record in records:
if not isinstance(record, dict):
raise ValueError("Invalid library record")
name = record.get("path")
safe_name(name)
match = re.fullmatch(r"lib(ggml|ggml-base|llama|mtmd)\.so(?:\.\d+)*", name)
if match:
if match[1] in core:
raise ValueError("Duplicate runtime core library")
core[match[1]] = name
elif name != "libggml-vulkan.so" and name not in {f"libggml-cpu-{v}.so" for v in CPU_VARIANTS}:
raise ValueError("Unapproved runtime library")
if name in expected or type(record.get("bytes")) is not int or record["bytes"] <= 0:
raise ValueError("Duplicate or invalid runtime library")
expected[name] = record
if set(core) != {"ggml", "ggml-base", "llama", "mtmd"} or not {"libggml-cpu-x64.so", "libggml-vulkan.so"}.issubset(expected):
raise ValueError("Runtime lacks baseline CPU, Vulkan or core library")
for name, record in expected.items():
path = runtime / name
regular(path, runtime)
checksum = record.get("sha256")
if not isinstance(checksum, str) or not re.fullmatch(r"[0-9a-f]{64}", checksum):
raise ValueError("Invalid runtime checksum")
if digest(path) != checksum or ("bytes" in record and path.stat().st_size != record["bytes"]):
raise ValueError(f"Runtime integrity mismatch: {name}")
record["bytes"] = path.stat().st_size
elf_x64(path)
metadata = dynamic(path)
if metadata.get("RPATH") or metadata.get("RUNPATH") != ["$ORIGIN"]:
raise ValueError("Runtime requires origin-only RUNPATH")
allowed = set(expected) | SYSTEM
if name == "libggml-vulkan.so":
allowed.add("libvulkan.so.1")
if set(metadata.get("NEEDED", [])) - allowed:
raise ValueError(f"Unpackaged runtime dependency: {name}")
if name in core.values() and metadata.get("SONAME") != [name]:
raise ValueError("Core SONAME differs from packaged filename")
expected[inventory.name] = {"sha256": hashlib.sha256(inventory_bytes).hexdigest(), "bytes": len(inventory_bytes)}
return expected
def media_files(root, media):
manifest_path = root / "tools/media-runtime/manifest.json"
regular(manifest_path, root)
if manifest_path.stat().st_size > 65536:
raise ValueError("Oversized media manifest")
manifest = json.loads(manifest_path.read_text())
artifact = manifest["platforms"]["linux-x86_64"]
archive_name = safe_name(artifact["archive"])
if "/" in archive_name or not archive_name.endswith(".tar.xz"):
raise ValueError("Invalid media archive name")
archive = media / archive_name
regular(archive, media)
if archive.stat().st_size != artifact["bytes"] or digest(archive) != artifact["sha256"]:
raise ValueError("Media archive provenance mismatch")
selected = {}
with tarfile.open(archive, "r:xz") as package:
members = 0
declared_total = 0
for member in package:
members += 1
declared_total += member.size
if (members > 10000 or member.size < 0 or member.size > MAX_FILE
or declared_total > MAX_TOTAL):
raise ValueError("Media archive exceeds member or size ceiling")
basename = member.name.replace("\\", "/").split("/")[-1]
if basename in {"ffmpeg", "ffprobe"}:
target = f"bin/{basename}"
elif basename.lower().startswith(("license", "copying")) or basename.lower() in {"readme.txt", "readme.md"}:
target = "licenses/" + safe_name(member.name)
else:
continue
if not member.isfile() or not 0 < member.size <= MAX_FILE or target in selected:
raise ValueError("Invalid or duplicate media member")
path = media / target
regular(path, media)
with package.extractfile(member) as stream:
checksum = hashlib.file_digest(stream, "sha256").hexdigest()
if path.stat().st_size != member.size or digest(path) != checksum:
raise ValueError(f"Media helper/notice differs from pinned archive: {target}")
selected[target] = {"sha256": checksum, "bytes": member.size}
if not {"bin/ffmpeg", "bin/ffprobe"}.issubset(selected) or not any(n.startswith("licenses/") for n in selected):
raise ValueError("Media archive lacks helpers or notices")
selected = {"media-runtime/" + name: (media / name, record) for name, record in selected.items()}
selected["media-runtime/manifest.json"] = (manifest_path, {"sha256": digest(manifest_path), "bytes": manifest_path.stat().st_size})
return selected
def package(root, executable, runtime, media, output, llama_license=None):
root, executable, runtime, media, output = map(Path, (root, executable, runtime, media, output))
regular(executable, executable.parent)
elf_x64(executable)
expected = runtime_files(runtime)
cli_metadata = dynamic(executable)
if (cli_metadata.get("RPATH") or cli_metadata.get("RUNPATH")
or set(cli_metadata.get("NEEDED", [])) - SYSTEM):
raise ValueError("CLI has unexpected native dependency or search path")
selected = {name: (runtime / name, record) for name, record in expected.items()}
selected.update(media_files(root, media))
selected["searchi"] = (executable, {"sha256": digest(executable), "bytes": executable.stat().st_size})
license_path = Path(llama_license) if llama_license else root / ".searchi/references/llama.cpp/LICENSE"
for path, name, parent in [(root / "LICENSE", "LICENSE.txt", root), (license_path, "LLAMA-LICENSE.txt", license_path.parent)]:
regular(path, parent)
selected[name] = (path, {"sha256": digest(path), "bytes": path.stat().st_size})
for name in ("media-runtime/bin/ffmpeg", "media-runtime/bin/ffprobe"):
elf_x64(selected[name][0])
metadata = dynamic(selected[name][0])
if metadata.get("RPATH") or metadata.get("RUNPATH") or set(metadata.get("NEEDED", [])) - SYSTEM:
raise ValueError("Media helper has unpackaged dependencies")
if sum(record["bytes"] for _, record in selected.values()) > MAX_TOTAL:
raise ValueError("Package exceeds total size ceiling")
if output.resolve() in {path.resolve() for path, _ in selected.values()}:
raise ValueError("Package output would overwrite an input")
output.parent.mkdir(parents=True, exist_ok=True)
with tempfile.NamedTemporaryFile(dir=output.parent, suffix=".partial", delete=False) as temporary:
temporary_path = Path(temporary.name)
try:
records = []
with temporary_path.open("wb") as raw, gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=0) as compressed, tarfile.open(fileobj=compressed, mode="w|") as archive:
for name, (path, expected_record) in sorted(selected.items()):
safe_name(name)
regular(path, path.parent)
# Bounded immutable snapshot: archive and manifest describe the same bytes.
with path.open("rb") as stream:
data = stream.read(MAX_FILE + 1)
checksum = hashlib.sha256(data).hexdigest()
if len(data) != expected_record["bytes"] or checksum != expected_record["sha256"]:
raise ValueError(f"Source changed during packaging: {name}")
mode = 0o755 if name in {"searchi", "searchi-gemma-worker", "media-runtime/bin/ffmpeg", "media-runtime/bin/ffprobe"} or ".so" in name else 0o644
add(archive, name, data, mode)
records.append({"path": name, "bytes": len(data), "sha256": checksum, "mode": oct(mode)})
instructions = ("searchi — Find what matters. Locally.\n\n"
"Extract the entire archive into its own folder. This is a headless development candidate, not a production installer.\n"
"Use ./searchi --help. Setup downloads about 865 MB of verified Google model assets:\n"
"./searchi setup --model-dir ./models\n"
"./searchi index --db ./searchi.sqlite --root /path/to/files\n"
"./searchi embed --db ./searchi.sqlite --model-dir ./models --embedding-worker ./searchi-gemma-worker\n"
"./searchi search --db ./searchi.sqlite 'what you remember' --model-dir ./models --embedding-worker ./searchi-gemma-worker\n"
"Media helpers are discovered automatically beside this CLI. Ordinary search stays local.\n"
"The normal runtime includes Vulkan and CPU fallback. Graphics drivers and a compatible system Vulkan loader are optional.\n"
"Requires a compatible Linux libc/C++ ABI; clean-machine and distribution coverage remain open.\n").encode()
add(archive, "START-HERE.txt", instructions, 0o644)
records.append({"path": "START-HERE.txt", "bytes": len(instructions),
"sha256": hashlib.sha256(instructions).hexdigest(), "mode": oct(0o644)})
add(archive, "PACKAGE.json", json.dumps({"platform": "linux", "architecture": "x86_64",
"status": "unsigned headless development candidate; distribution ABI and GPU hardware validation pending",
"system_libraries": sorted(SYSTEM), "optional_gpu_loader": "libvulkan.so.1",
"files": records}, indent=2).encode(), 0o644)
os.replace(temporary_path, output)
finally:
temporary_path.unlink(missing_ok=True)
return "x86_64"
def add(archive, name, data, mode):
info = tarfile.TarInfo(safe_name(name))
info.size, info.mode, info.mtime = len(data), mode, 0
info.uid = info.gid = 0
info.uname = info.gname = ""
archive.addfile(info, io.BytesIO(data))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--executable", type=Path, default=ROOT / "target/release/searchi")
parser.add_argument("--runtime", type=Path, default=ROOT / ".searchi/runtime/auto")
parser.add_argument("--media", type=Path, default=ROOT / ".searchi/media-runtime")
parser.add_argument("--llama-license", type=Path)
parser.add_argument("--output", type=Path, default=ROOT / ".searchi/packages/searchi-linux-x86_64.tar.gz")
args = parser.parse_args()
package(ROOT, args.executable, args.runtime, args.media, args.output, args.llama_license)
print(f"Packaged Linux x86_64 development candidate: {args.output}")
if __name__ == "__main__":
main()
+232
View File
@@ -0,0 +1,232 @@
import hashlib
import io
import json
from pathlib import Path
import struct
import tarfile
import tempfile
import unittest
from unittest import mock
import package_linux as pack
def elf(path, machine=62):
path.parent.mkdir(parents=True, exist_ok=True)
data = bytearray(64)
data[:7] = b"\x7fELF\x02\x01\x01"
struct.pack_into("<HH", data, 16, 3, machine)
path.write_bytes(data)
class LinuxPackageTests(unittest.TestCase):
def fixture(self, directory):
root = Path(directory)
runtime, media = root / "runtime", root / "media"
executable = root / "build/searchi"
elf(executable)
(root / "LICENSE").write_text("application MIT notice")
license = root / ".searchi/references/llama.cpp/LICENSE"
license.parent.mkdir(parents=True)
license.write_text("llama MIT notice")
names = ["libggml.so.0", "libggml-base.so.0", "libllama.so.0", "libmtmd.so.0", "libggml-cpu-x64.so", "libggml-vulkan.so"]
elf(runtime / "searchi-gemma-worker")
records = []
for name in names:
elf(runtime / name)
records.append({"path": name, "bytes": 64, "sha256": pack.digest(runtime / name)})
(runtime / "runtime-libraries.json").write_text(json.dumps({"platform": "linux", "worker_sha256": pack.digest(runtime / "searchi-gemma-worker"), "libraries": records}))
media.mkdir()
elf(media / "bin/ffmpeg")
elf(media / "bin/ffprobe")
notice = media / "licenses/upstream/LICENSE.txt"
notice.parent.mkdir(parents=True)
notice.write_text("LGPL notice")
archive = media / "verified.tar.xz"
with tarfile.open(archive, "w:xz") as output:
for name, path in [("upstream/bin/ffmpeg", media / "bin/ffmpeg"), ("upstream/bin/ffprobe", media / "bin/ffprobe"), ("upstream/LICENSE.txt", notice)]:
output.add(path, arcname=name)
manifest = root / "tools/media-runtime/manifest.json"
manifest.parent.mkdir(parents=True)
manifest.write_text(json.dumps({"provider": "test-fixture", "release": "fixture", "platforms": {"linux-x86_64": {"archive": archive.name, "bytes": archive.stat().st_size, "sha256": pack.digest(archive)}}}))
return root, executable, runtime, media, root / "candidate.tar.gz"
@staticmethod
def metadata(path):
if path.name == "searchi-gemma-worker" or path.name.startswith("lib"):
metadata = {"RUNPATH": ["$ORIGIN"], "NEEDED": ["libc.so.6"]}
if path.name in {"libggml.so.0", "libggml-base.so.0", "libllama.so.0", "libmtmd.so.0"}:
metadata["SONAME"] = [path.name]
if path.name == "libggml-vulkan.so":
metadata["NEEDED"].append("libvulkan.so.1")
return metadata
return {"NEEDED": ["libc.so.6"]}
def run_package(self, fixture):
with mock.patch.object(pack, "dynamic", side_effect=self.metadata):
return pack.package(*fixture)
def test_archive_integrity_modes_no_userdata_and_reproducibility(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
root, executable, runtime, media, output = fixture
(runtime / "settings.json").write_text("private")
(media / "index.sqlite").write_text("private")
self.run_package(fixture)
first = output.read_bytes()
self.run_package(fixture)
self.assertEqual(first, output.read_bytes())
with tarfile.open(output) as archive:
self.assertNotIn("settings.json", archive.getnames())
manifest = json.load(archive.extractfile("PACKAGE.json"))
for record in manifest["files"]:
member = archive.getmember(record["path"])
data = archive.extractfile(member).read()
self.assertEqual(record["sha256"], hashlib.sha256(data).hexdigest())
self.assertEqual(member.uid, 0)
self.assertEqual(member.mtime, 0)
self.assertEqual(archive.getmember("searchi").mode, 0o755)
self.assertEqual(archive.getmember("media-runtime/bin/ffmpeg").mode, 0o755)
self.assertEqual(archive.getmember("LICENSE.txt").mode, 0o644)
def test_tampered_runtime_preserves_previous_archive(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
self.run_package(fixture)
previous = fixture[-1].read_bytes()
(fixture[2] / "libggml-cpu-x64.so").write_bytes(b"tampered")
with self.assertRaisesRegex(ValueError, "integrity mismatch"):
self.run_package(fixture)
self.assertEqual(previous, fixture[-1].read_bytes())
def test_media_helper_tamper_is_rejected_against_pinned_archive(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
(fixture[3] / "bin/ffmpeg").write_bytes(b"tampered")
with self.assertRaisesRegex(ValueError, "differs from pinned archive"):
self.run_package(fixture)
def test_media_archive_provenance_tamper_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
with (fixture[3] / "verified.tar.xz").open("ab") as stream:
stream.write(b"tampered")
with self.assertRaisesRegex(ValueError, "provenance mismatch"):
self.run_package(fixture)
def test_mixed_architecture_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
elf(fixture[1], machine=183)
with self.assertRaisesRegex(ValueError, "x86-64 ELF"):
self.run_package(fixture)
def test_inventory_traversal_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
path = fixture[2] / "runtime-libraries.json"
manifest = json.loads(path.read_text())
manifest["libraries"][0]["path"] = "../private.so"
path.write_text(json.dumps(manifest))
with self.assertRaisesRegex(ValueError, "Unsafe package path"):
self.run_package(fixture)
def test_missing_baseline_cpu_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
path = fixture[2] / "runtime-libraries.json"
manifest = json.loads(path.read_text())
manifest["libraries"] = [r for r in manifest["libraries"] if r["path"] != "libggml-cpu-x64.so"]
path.write_text(json.dumps(manifest))
with self.assertRaisesRegex(ValueError, "lacks baseline"):
self.run_package(fixture)
def test_worker_cannot_link_vulkan_loader(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
def metadata(path):
result = self.metadata(path)
if path.name == "searchi-gemma-worker":
result["NEEDED"].append("libvulkan.so.1")
return result
with mock.patch.object(pack, "dynamic", side_effect=metadata), self.assertRaisesRegex(ValueError, "Unpackaged runtime"):
pack.package(*fixture)
def test_external_runtime_search_path_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
with mock.patch.object(pack, "dynamic", return_value={"RUNPATH": ["/build/lib"]}), self.assertRaisesRegex(ValueError, "origin-only"):
pack.package(*fixture)
def test_glibc_vector_math_is_declared_but_unknown_cli_dependency_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
def vector_math(path):
result = self.metadata(path)
if path.name == "searchi":
result["NEEDED"].append("libmvec.so.1")
return result
with mock.patch.object(pack, "dynamic", side_effect=vector_math):
pack.package(*fixture)
with tarfile.open(fixture[-1]) as archive:
manifest = json.load(archive.extractfile("PACKAGE.json"))
self.assertIn("libmvec.so.1", manifest["system_libraries"])
previous = fixture[-1].read_bytes()
def unknown(path):
result = vector_math(path)
if path.name == "searchi":
result["NEEDED"].append("libunpackaged.so.1")
return result
with mock.patch.object(pack, "dynamic", side_effect=unknown), self.assertRaisesRegex(ValueError, "unexpected native dependency"):
pack.package(*fixture)
self.assertEqual(previous, fixture[-1].read_bytes())
def test_readelf_parser_is_nonexecuting_and_preserves_dependencies(self):
with mock.patch.object(pack.subprocess, "check_output", return_value="(NEEDED) Shared library: [libc.so.6]\n(RUNPATH) Library runpath: [$ORIGIN]\n") as process:
self.assertEqual(pack.dynamic(Path("candidate")), {"NEEDED": ["libc.so.6"], "RUNPATH": ["$ORIGIN"]})
self.assertEqual(process.call_args.args[0], ["readelf", "--dynamic", "candidate"])
def test_missing_pinned_media_notice_rejected(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
(fixture[3] / "licenses/upstream/LICENSE.txt").unlink()
with self.assertRaisesRegex(ValueError, "Missing or oversized"):
self.run_package(fixture)
def test_output_cannot_overwrite_cli(self):
with tempfile.TemporaryDirectory() as directory:
root, executable, runtime, media, _ = self.fixture(directory)
original = executable.read_bytes()
with self.assertRaisesRegex(ValueError, "overwrite an input"):
self.run_package((root, executable, runtime, media, executable))
self.assertEqual(original, executable.read_bytes())
def test_changed_source_during_packaging_preserves_previous_archive(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
self.run_package(fixture)
previous = fixture[-1].read_bytes()
original_add = pack.add
def mutate(archive, name, data, mode):
original_add(archive, name, data, mode)
if name == "LICENSE.txt":
fixture[1].write_bytes(b"changed after preflight")
with mock.patch.object(pack, "add", side_effect=mutate), self.assertRaisesRegex(ValueError, "Source changed"):
self.run_package(fixture)
self.assertEqual(previous, fixture[-1].read_bytes())
def test_unapproved_plugin_rejected_even_with_valid_hash(self):
with tempfile.TemporaryDirectory() as directory:
fixture = self.fixture(directory)
runtime = fixture[2]
elf(runtime / "libarbitrary.so")
inventory = runtime / "runtime-libraries.json"
manifest = json.loads(inventory.read_text())
manifest["libraries"].append({"path": "libarbitrary.so", "bytes": 64, "sha256": pack.digest(runtime / "libarbitrary.so")})
inventory.write_text(json.dumps(manifest))
with self.assertRaisesRegex(ValueError, "Unapproved runtime library"):
self.run_package(fixture)
if __name__ == "__main__":
unittest.main()