491 lines
20 KiB
Python
491 lines
20 KiB
Python
"""Offline guards for DGR-027's pinned llama.cpp dependency boundary."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import importlib.util
|
|
import json
|
|
import pathlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|
LLAMA_DIR = ROOT / "packages/node/native/llama"
|
|
SCRIPT = ROOT / "scripts/llama_cpp_dependency.py"
|
|
|
|
|
|
def _sha256(path: pathlib.Path) -> str:
|
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
|
|
|
|
def _load_dependency_module():
|
|
spec = importlib.util.spec_from_file_location("llama_cpp_dependency_ctest", SCRIPT)
|
|
assert spec and spec.loader
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def _cmake_available() -> bool:
|
|
if shutil.which("cmake"):
|
|
return True
|
|
sibling = pathlib.Path(sys.executable).parent / "cmake"
|
|
return sibling.is_file()
|
|
|
|
|
|
requires_cmake = pytest.mark.skipif(
|
|
not _cmake_available(), reason="cmake toolchain is required to build the native CTest lane"
|
|
)
|
|
|
|
|
|
def test_lock_and_patch_manifest_are_self_consistent_and_exact() -> None:
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
commit = (LLAMA_DIR / "UPSTREAM_COMMIT").read_text().strip()
|
|
patches = (LLAMA_DIR / "patches/series").read_text().splitlines()
|
|
sums = {
|
|
name: digest
|
|
for digest, name in (
|
|
line.split(maxsplit=1)
|
|
for line in (LLAMA_DIR / "patches/SHA256SUMS").read_text().splitlines()
|
|
if line and not line.startswith("#")
|
|
)
|
|
}
|
|
|
|
assert commit == lock["commit"]
|
|
assert len(commit) == 40
|
|
assert lock["retrieval"]["method"] == "git-clone-detached-commit"
|
|
assert lock["retrieval"]["workspace"] == "build/llama.cpp"
|
|
assert lock["expected_source"]["git_tree"] == lock["commit_tree"]
|
|
assert lock["upstream_license"] == "MIT"
|
|
assert patches == lock["patch_series"]
|
|
assert patches == sorted(patches)
|
|
assert patches
|
|
for patch_name in patches:
|
|
patch = LLAMA_DIR / "patches" / patch_name
|
|
assert sums[patch_name] == _sha256(patch)
|
|
assert "Subject: [PATCH" in patch.read_text()
|
|
|
|
|
|
def test_fetch_refuses_a_workspace_outside_the_ignored_build_root(tmp_path: pathlib.Path) -> None:
|
|
completed = subprocess.run(
|
|
[sys.executable, str(SCRIPT), "fetch", "--workspace", str(tmp_path / "llama.cpp")],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
assert completed.returncode == 2
|
|
assert "--workspace must equal" in completed.stderr
|
|
|
|
|
|
def test_workspace_refuses_a_symlinked_build_ancestor(tmp_path: pathlib.Path, monkeypatch) -> None:
|
|
spec = importlib.util.spec_from_file_location("llama_cpp_dependency_symlink", SCRIPT)
|
|
assert spec and spec.loader
|
|
dependency = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(dependency)
|
|
root = tmp_path / "repo"
|
|
outside = tmp_path / "outside"
|
|
root.mkdir()
|
|
outside.mkdir()
|
|
(root / "build").symlink_to(outside, target_is_directory=True)
|
|
monkeypatch.setattr(dependency, "ROOT", root)
|
|
|
|
try:
|
|
dependency._workspace_source(
|
|
root / "build/llama.cpp",
|
|
{"retrieval": {"workspace": "build/llama.cpp"}},
|
|
)
|
|
except dependency.DependencyError as error:
|
|
assert "may not traverse a symlink" in str(error)
|
|
else:
|
|
raise AssertionError("symlinked build ancestor must be refused")
|
|
|
|
(root / "build").unlink()
|
|
workspace = root / "build/llama.cpp"
|
|
workspace.mkdir(parents=True)
|
|
(workspace / "source").symlink_to(outside, target_is_directory=True)
|
|
try:
|
|
dependency._workspace_source(
|
|
workspace,
|
|
{"retrieval": {"workspace": "build/llama.cpp"}},
|
|
)
|
|
except dependency.DependencyError as error:
|
|
assert "source checkout may not be a symlink" in str(error)
|
|
else:
|
|
raise AssertionError("symlinked source checkout must be refused")
|
|
|
|
|
|
def test_fetch_refuses_a_branch_or_repository_override() -> None:
|
|
completed = subprocess.run(
|
|
[sys.executable, str(SCRIPT), "fetch", "--source-repository", "main"],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
assert completed.returncode == 2
|
|
assert "unrecognized arguments" in completed.stderr
|
|
|
|
|
|
def test_fetch_reuses_only_a_verified_cached_tree_offline(
|
|
tmp_path: pathlib.Path, monkeypatch
|
|
) -> None:
|
|
spec = importlib.util.spec_from_file_location("llama_cpp_dependency", SCRIPT)
|
|
assert spec and spec.loader
|
|
dependency = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(dependency)
|
|
|
|
root = tmp_path / "repo"
|
|
source = root / "build/llama.cpp/source"
|
|
upstream = tmp_path / "upstream"
|
|
upstream.mkdir()
|
|
subprocess.run(["git", "init", "-q", str(upstream)], check=True)
|
|
subprocess.run(["git", "-C", str(upstream), "config", "user.email", "test@example.invalid"], check=True)
|
|
subprocess.run(["git", "-C", str(upstream), "config", "user.name", "test"], check=True)
|
|
(upstream / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.14)\n")
|
|
(upstream / "LICENSE").write_text("MIT\n")
|
|
(upstream / "tool.sh").write_text("#!/bin/sh\nexit 0\n")
|
|
(upstream / "tool.sh").chmod(0o755)
|
|
subprocess.run(["git", "-C", str(upstream), "add", "."], check=True)
|
|
subprocess.run(["git", "-C", str(upstream), "commit", "-qm", "fixture"], check=True)
|
|
commit = subprocess.run(
|
|
["git", "-C", str(upstream), "rev-parse", "HEAD"], check=True, capture_output=True, text=True
|
|
).stdout.strip()
|
|
tree = subprocess.run(
|
|
["git", "-C", str(upstream), "rev-parse", "HEAD^{tree}"], check=True, capture_output=True, text=True
|
|
).stdout.strip()
|
|
blob = subprocess.run(
|
|
["git", "-C", str(upstream), "rev-parse", "HEAD:CMakeLists.txt"],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
).stdout.strip()
|
|
source.parent.mkdir(parents=True)
|
|
subprocess.run(["git", "clone", "-q", str(upstream), str(source)], check=True)
|
|
|
|
llama_dir = root / "packages/node/native/llama"
|
|
patch_dir = llama_dir / "patches"
|
|
patch_dir.mkdir(parents=True)
|
|
(llama_dir / "UPSTREAM_COMMIT").write_text(f"{commit}\n")
|
|
(patch_dir / "series").write_text("0001-fixture.patch\n")
|
|
patch = patch_dir / "0001-fixture.patch"
|
|
patch.write_text("fixture patch\n")
|
|
(patch_dir / "SHA256SUMS").write_text(f"{_sha256(patch)} {patch.name}\n")
|
|
(llama_dir / "UPSTREAM_LOCK.json").write_text(json.dumps({
|
|
"upstream": str(upstream),
|
|
"commit": commit,
|
|
"commit_tree": tree,
|
|
"expected_source": {"git_tree": tree},
|
|
"retrieval": {"method": "git-clone-detached-commit", "workspace": "build/llama.cpp"},
|
|
"patched_tree": tree,
|
|
"patch_series": [patch.name],
|
|
"required_upstream_blobs": {"CMakeLists.txt": blob},
|
|
"patched_paths": [],
|
|
"build": {},
|
|
"upstream_license": "MIT",
|
|
}))
|
|
monkeypatch.setattr(dependency, "ROOT", root)
|
|
monkeypatch.setattr(dependency, "LLAMA_DIR", llama_dir)
|
|
monkeypatch.setattr(dependency, "LOCK_PATH", llama_dir / "UPSTREAM_LOCK.json")
|
|
monkeypatch.setattr(dependency, "PATCH_DIR", patch_dir)
|
|
|
|
try:
|
|
dependency.fetch(root / "build/llama.cpp")
|
|
except dependency.DependencyError as error:
|
|
assert "detached HEAD" in str(error)
|
|
else:
|
|
raise AssertionError("attached branch cache must be refused")
|
|
subprocess.run(["git", "-C", str(source), "checkout", "--detach", "-q", commit], check=True)
|
|
assert dependency.fetch(root / "build/llama.cpp") == source
|
|
|
|
tracked_path = source / "CMakeLists.txt"
|
|
for flag, clear_flag in (
|
|
("--assume-unchanged", "--no-assume-unchanged"),
|
|
("--skip-worktree", "--no-skip-worktree"),
|
|
):
|
|
subprocess.run(["git", "-C", str(source), "update-index", flag, "CMakeLists.txt"], check=True)
|
|
tracked_path.write_text("injected tracked build input\n")
|
|
try:
|
|
dependency.fetch(root / "build/llama.cpp")
|
|
except dependency.DependencyError as error:
|
|
assert "tracked source content differs" in str(error)
|
|
else:
|
|
raise AssertionError(f"tracked cache injection hidden by {flag} must be refused")
|
|
subprocess.run(["git", "-C", str(source), "update-index", clear_flag, "CMakeLists.txt"], check=True)
|
|
subprocess.run(["git", "-C", str(source), "checkout", "--", "CMakeLists.txt"], check=True)
|
|
|
|
executable_path = source / "tool.sh"
|
|
for flag, clear_flag in (
|
|
("--assume-unchanged", "--no-assume-unchanged"),
|
|
("--skip-worktree", "--no-skip-worktree"),
|
|
):
|
|
subprocess.run(["git", "-C", str(source), "update-index", flag, "tool.sh"], check=True)
|
|
executable_path.chmod(0o644)
|
|
try:
|
|
dependency.fetch(root / "build/llama.cpp")
|
|
except dependency.DependencyError as error:
|
|
assert "executable mode differs" in str(error)
|
|
else:
|
|
raise AssertionError(f"tracked mode change hidden by {flag} must be refused")
|
|
subprocess.run(["git", "-C", str(source), "update-index", clear_flag, "tool.sh"], check=True)
|
|
subprocess.run(["git", "-C", str(source), "checkout", "--", "tool.sh"], check=True)
|
|
|
|
(source / "untracked.txt").write_text("edited\n")
|
|
try:
|
|
dependency.fetch(root / "build/llama.cpp")
|
|
except dependency.DependencyError as error:
|
|
assert "local edits" in str(error)
|
|
else:
|
|
raise AssertionError("dirty cached source must be refused")
|
|
(source / "untracked.txt").unlink()
|
|
(source / ".git/info/exclude").write_text("injected.cmake\n")
|
|
(source / "injected.cmake").write_text("unmanifested input\n")
|
|
try:
|
|
dependency.fetch(root / "build/llama.cpp")
|
|
except dependency.DependencyError as error:
|
|
assert "unmanifested files" in str(error)
|
|
else:
|
|
raise AssertionError("ignored cached source input must be refused")
|
|
|
|
|
|
def test_dependency_script_reports_the_locked_boundary_without_network() -> None:
|
|
completed = subprocess.run(
|
|
[sys.executable, str(SCRIPT), "inspect"],
|
|
cwd=ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
report = json.loads(completed.stdout)
|
|
|
|
assert report["commit"] == (LLAMA_DIR / "UPSTREAM_COMMIT").read_text().strip()
|
|
assert report["patch_count"] == len(
|
|
(LLAMA_DIR / "patches/series").read_text().splitlines()
|
|
)
|
|
assert report["model_downloads"] is False
|
|
assert report["semantic_certification"] is False
|
|
assert "dense" in report["glm_stock_limitations"].lower()
|
|
|
|
|
|
def test_patch_stack_does_not_contain_meshnet_control_plane_code() -> None:
|
|
forbidden = ("tracker", "route session", "grpc", "http", "billing", "wallet")
|
|
patch_text = "\n".join(
|
|
(LLAMA_DIR / "patches" / name).read_text().lower()
|
|
for name in (LLAMA_DIR / "patches/series").read_text().splitlines()
|
|
)
|
|
assert not any(term in patch_text for term in forbidden)
|
|
|
|
|
|
def test_build_config_locks_an_explicit_cpu_only_deterministic_lane() -> None:
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
build = lock["build"]
|
|
flag_values = dict(flag[len("-D"):].split("=", 1) for flag in build["configure_flags"])
|
|
|
|
assert flag_values["GGML_CPU"] == "ON"
|
|
for backend in ("GGML_CUDA", "GGML_HIP", "GGML_VULKAN", "GGML_METAL", "GGML_BLAS"):
|
|
assert flag_values[backend] == "OFF"
|
|
assert flag_values["LLAMA_BUILD_TESTS"] == "ON"
|
|
|
|
assert build["ctest_regex"] == "^test-meshnet-range-ownership$"
|
|
assert "test-meshnet-range-ownership" in build["native_targets"]
|
|
assert pathlib.Path(build["smoke_binary"]).name in build["native_targets"]
|
|
assert "tests/test-meshnet-range-ownership.cpp" in lock["patched_paths"]
|
|
|
|
|
|
@requires_cmake
|
|
def test_ctest_lane_raises_an_actionable_error_for_a_failing_named_test(tmp_path: pathlib.Path) -> None:
|
|
dependency = _load_dependency_module()
|
|
|
|
project = tmp_path / "project"
|
|
project.mkdir()
|
|
(project / "CMakeLists.txt").write_text(
|
|
"cmake_minimum_required(VERSION 3.14)\n"
|
|
"project(ctest_lane_fixture NONE)\n"
|
|
"enable_testing()\n"
|
|
"add_test(NAME meshnet-fixture-pass COMMAND ${CMAKE_COMMAND} -E true)\n"
|
|
"add_test(NAME meshnet-fixture-fail COMMAND ${CMAKE_COMMAND} -E false)\n"
|
|
)
|
|
build_dir = tmp_path / "build"
|
|
subprocess.run(
|
|
[dependency._cmake(), "-S", str(project), "-B", str(build_dir)],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
base_lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
|
|
def _lock_with_regex(regex: str):
|
|
patched = dict(base_lock)
|
|
patched["build"] = {**base_lock["build"], "ctest_regex": regex}
|
|
return patched
|
|
|
|
dependency._load_lock = lambda: _lock_with_regex("^meshnet-fixture-pass$")
|
|
dependency.ctest_lane(build_dir)
|
|
|
|
dependency._load_lock = lambda: _lock_with_regex("^meshnet-fixture-fail$")
|
|
try:
|
|
dependency.ctest_lane(build_dir)
|
|
except dependency.DependencyError as error:
|
|
assert "meshnet-fixture-fail" in str(error)
|
|
else:
|
|
raise AssertionError("a failing named CTest lane must raise DependencyError")
|
|
|
|
|
|
def test_accelerator_presets_isolate_one_backend_without_touching_the_cpu_default() -> None:
|
|
dependency = _load_dependency_module()
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
presets = lock["accelerator_presets"]
|
|
|
|
assert set(presets) == {"cuda", "rocm", "vulkan", "metal"}
|
|
base_flags = list(lock["build"]["configure_flags"])
|
|
base_values = dict(flag[len("-D"):].split("=", 1) for flag in base_flags)
|
|
|
|
for name, preset in presets.items():
|
|
flags = dependency.accelerator_configure_flags(lock, name)
|
|
|
|
# The CPU default's own flag list is never mutated by building a preset.
|
|
assert lock["build"]["configure_flags"] == base_flags
|
|
|
|
new_values = dict(flag[len("-D"):].split("=", 1) for flag in flags)
|
|
backend_flag = preset["backend_flag"]
|
|
assert base_values[backend_flag] == "OFF"
|
|
assert new_values[backend_flag] == "ON"
|
|
for other_flag, value in base_values.items():
|
|
if other_flag != backend_flag:
|
|
assert new_values[other_flag] == value, f"{name}: {other_flag} drifted from the CPU default"
|
|
|
|
|
|
def test_accelerator_configure_flags_rejects_an_unknown_lane() -> None:
|
|
dependency = _load_dependency_module()
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
try:
|
|
dependency.accelerator_configure_flags(lock, "bogus")
|
|
except dependency.DependencyError as error:
|
|
assert "unknown accelerator lane" in str(error)
|
|
else:
|
|
raise AssertionError("an unknown accelerator lane must be refused")
|
|
|
|
|
|
def test_accelerator_status_reports_unavailable_sdks_without_raising(monkeypatch) -> None:
|
|
dependency = _load_dependency_module()
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
monkeypatch.setattr(dependency.shutil, "which", lambda name: None)
|
|
|
|
for name in ("cuda", "rocm", "vulkan"):
|
|
env_var = lock["accelerator_presets"][name]["sdk_probe"]["env_var"]
|
|
monkeypatch.delenv(env_var, raising=False)
|
|
binary = lock["accelerator_presets"][name]["sdk_probe"]["binary"]
|
|
assert dependency.accelerator_status(name, lock) == {
|
|
"lane": name,
|
|
"available": False,
|
|
"reason": f"{binary} is unavailable on PATH",
|
|
}
|
|
|
|
monkeypatch.setattr(dependency.sys, "platform", "linux")
|
|
assert dependency.accelerator_status("metal", lock) == {
|
|
"lane": "metal",
|
|
"available": False,
|
|
"reason": "platform 'linux' is not 'darwin'",
|
|
}
|
|
|
|
|
|
def test_accelerator_status_honors_an_explicit_sdk_override(tmp_path, monkeypatch) -> None:
|
|
dependency = _load_dependency_module()
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
fake_nvcc = tmp_path / "nvcc"
|
|
fake_nvcc.write_text("#!/bin/sh\nexit 0\n")
|
|
fake_nvcc.chmod(0o755)
|
|
monkeypatch.setenv("CUDACXX", str(fake_nvcc))
|
|
|
|
assert dependency.accelerator_status("cuda", lock) == {
|
|
"lane": "cuda",
|
|
"available": True,
|
|
"sdk_binary": str(fake_nvcc),
|
|
}
|
|
|
|
|
|
def test_accelerator_status_rejects_an_unknown_lane() -> None:
|
|
dependency = _load_dependency_module()
|
|
lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
try:
|
|
dependency.accelerator_status("bogus", lock)
|
|
except dependency.DependencyError as error:
|
|
assert "unknown accelerator lane" in str(error)
|
|
else:
|
|
raise AssertionError("an unknown accelerator lane must be refused")
|
|
|
|
|
|
def test_accelerator_build_refuses_to_compile_an_unavailable_lane(tmp_path, monkeypatch) -> None:
|
|
dependency = _load_dependency_module()
|
|
source = tmp_path / "source"
|
|
(source / "cmake").mkdir(parents=True)
|
|
(source / "cmake" / "meshnet-patch-stack.cmake").write_text("# marker\n")
|
|
monkeypatch.setattr(dependency, "_verify_source", lambda *a, **k: None)
|
|
monkeypatch.setattr(dependency, "_verify_patched_source", lambda *a, **k: None)
|
|
monkeypatch.setattr(dependency.shutil, "which", lambda name: None)
|
|
monkeypatch.delenv("CUDACXX", raising=False)
|
|
|
|
build_dir = tmp_path / "build-cuda"
|
|
try:
|
|
dependency.accelerator_build(source, "cuda", build_dir)
|
|
except dependency.DependencyError as error:
|
|
assert "SDK is unavailable" in str(error)
|
|
else:
|
|
raise AssertionError("accelerator_build must refuse to compile an unavailable lane")
|
|
assert not build_dir.exists()
|
|
|
|
|
|
@requires_cmake
|
|
def test_accelerator_build_compiles_the_available_lane_with_isolated_evidence(tmp_path, monkeypatch) -> None:
|
|
dependency = _load_dependency_module()
|
|
|
|
# A tiny synthetic project stands in for the patched llama.cpp checkout —
|
|
# it only needs the meshnet patch-stack marker and one target, proving
|
|
# accelerator_build's configure/build/evidence wiring without a multi-minute
|
|
# llama.cpp compile or a real GPU SDK.
|
|
source = tmp_path / "source"
|
|
(source / "cmake").mkdir(parents=True)
|
|
(source / "cmake" / "meshnet-patch-stack.cmake").write_text("# marker\n")
|
|
(source / "CMakeLists.txt").write_text(
|
|
"cmake_minimum_required(VERSION 3.14)\n"
|
|
"project(accelerator_lane_fixture NONE)\n"
|
|
"option(GGML_CUDA \"\" OFF)\n"
|
|
"if(GGML_CUDA)\n"
|
|
" file(WRITE ${CMAKE_BINARY_DIR}/lane-flag-on.txt \"on\")\n"
|
|
"endif()\n"
|
|
"add_custom_target(fixture-target ALL COMMAND ${CMAKE_COMMAND} -E true)\n"
|
|
)
|
|
|
|
base_lock = json.loads((LLAMA_DIR / "UPSTREAM_LOCK.json").read_text())
|
|
fake_lock = dict(base_lock)
|
|
fake_lock["build"] = {
|
|
**base_lock["build"],
|
|
"generator": "Unix Makefiles",
|
|
"configure_flags": ["-DGGML_CUDA=OFF"],
|
|
"native_targets": ["fixture-target"],
|
|
}
|
|
monkeypatch.setattr(dependency, "_load_lock", lambda: fake_lock)
|
|
monkeypatch.setattr(dependency, "_patches", lambda lock: [])
|
|
monkeypatch.setattr(dependency, "_verify_source", lambda *a, **k: None)
|
|
monkeypatch.setattr(dependency, "_verify_patched_source", lambda *a, **k: None)
|
|
monkeypatch.setenv("CUDACXX", str(dependency._cmake()))
|
|
|
|
build_dir = tmp_path / "build-cuda"
|
|
result = dependency.accelerator_build(source, "cuda", build_dir)
|
|
|
|
assert result == build_dir
|
|
assert (build_dir / "lane-flag-on.txt").is_file()
|
|
metadata = json.loads((build_dir / "meshnet-build-metadata.json").read_text())
|
|
assert metadata["lane"] == "cuda"
|
|
assert metadata["backend_flag"] == "GGML_CUDA"
|
|
assert metadata["configure_flags"] == ["-DGGML_CUDA=ON"]
|
|
assert metadata["hardware_execution"] is False
|
|
assert metadata["hardware_certified"] is False
|
|
assert metadata["semantic_certification"] is False
|
|
assert "registered-dark" in metadata["note"]
|