mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-30 14:40:38 +02:00
259 lines
8.8 KiB
Python
259 lines
8.8 KiB
Python
"""CPU-testable contracts for the experimental Jetson support path."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.metadata
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
try:
|
|
import tomllib
|
|
except ModuleNotFoundError: # pragma: no cover - exercised by the Python 3.10 CI lane
|
|
import tomli as tomllib
|
|
|
|
from scripts import jetson_support
|
|
from scripts import run_conditional_gate
|
|
from scripts import setup_jetson
|
|
|
|
|
|
ROOT = Path(__file__).parents[1]
|
|
|
|
|
|
def test_host_evidence_is_allow_listed(monkeypatch, tmp_path):
|
|
tegra = tmp_path / "nv_tegra_release"
|
|
tegra.write_text("# R36 (release), REVISION: 4.3\nserial=secret\n")
|
|
os_release = tmp_path / "os-release"
|
|
os_release.write_text(
|
|
'ID=ubuntu\nVERSION_ID="22.04"\nPRETTY_NAME="Ubuntu 22.04"\nSECRET=value\n'
|
|
)
|
|
monkeypatch.setattr(jetson_support.platform, "machine", lambda: "aarch64")
|
|
monkeypatch.setattr(jetson_support.platform, "python_version", lambda: "3.10.12")
|
|
monkeypatch.setattr(jetson_support, "_capture", lambda command, **kwargs: "6.2+b17")
|
|
|
|
facts = jetson_support.collect_host_facts(
|
|
tegra_release=tegra,
|
|
os_release=os_release,
|
|
)
|
|
|
|
assert facts == {
|
|
"architecture": "aarch64",
|
|
"python_version": "3.10.12",
|
|
"os": {
|
|
"id": "ubuntu",
|
|
"version_id": "22.04",
|
|
"pretty_name": "Ubuntu 22.04",
|
|
},
|
|
"l4t_release": "# R36 (release), REVISION: 4.3",
|
|
"jetpack_package": "6.2+b17",
|
|
}
|
|
assert "secret" not in json.dumps(facts).lower()
|
|
|
|
|
|
def test_runtime_evidence_reports_cuda_without_device_identity(monkeypatch):
|
|
properties = SimpleNamespace(name="Orin", total_memory=64 * 1024**3)
|
|
fake_cuda = SimpleNamespace(
|
|
is_available=lambda: True,
|
|
device_count=lambda: 1,
|
|
get_device_properties=lambda _index: properties,
|
|
get_device_capability=lambda _index: (8, 7),
|
|
)
|
|
fake_torch = SimpleNamespace(
|
|
__version__="2.8.0a0+nv25.06",
|
|
version=SimpleNamespace(cuda="12.6"),
|
|
cuda=fake_cuda,
|
|
)
|
|
monkeypatch.setitem(sys.modules, "torch", fake_torch)
|
|
|
|
def missing_package(_name):
|
|
raise importlib.metadata.PackageNotFoundError
|
|
|
|
monkeypatch.setattr(jetson_support.importlib.metadata, "version", missing_package)
|
|
|
|
facts = jetson_support.collect_runtime_facts()
|
|
|
|
assert facts["cuda_available"] is True
|
|
assert facts["device_name"] == "Orin"
|
|
assert facts["compute_capability"] == [8, 7]
|
|
assert facts["total_memory_gb"] == 64.0
|
|
assert set(facts) == {
|
|
"torch_imported",
|
|
"torch_version",
|
|
"torch_cuda_version",
|
|
"cuda_available",
|
|
"cuda_device_count",
|
|
"device_name",
|
|
"compute_capability",
|
|
"total_memory_gb",
|
|
"bitsandbytes_version",
|
|
}
|
|
|
|
|
|
def test_report_validation_blocks_non_jetson_or_non_cuda_and_warns_on_bnb():
|
|
report = {
|
|
"host": {"architecture": "x86_64", "l4t_release": None},
|
|
"runtime": {
|
|
"torch_imported": True,
|
|
"torch_cuda_version": None,
|
|
"cuda_available": False,
|
|
"bitsandbytes_version": "0.47.0",
|
|
},
|
|
}
|
|
|
|
errors, warnings = jetson_support.validate_report(report)
|
|
|
|
assert len(errors) == 3
|
|
assert any("ARM64" in error for error in errors)
|
|
assert any("Jetson L4T" in error for error in errors)
|
|
assert any("not a CUDA build" in error for error in errors)
|
|
assert warnings and "unsupported" in warnings[0]
|
|
|
|
|
|
def test_gate_evidence_and_issue_body_cannot_copy_arbitrary_fields(tmp_path):
|
|
evidence = tmp_path / "gate.json"
|
|
evidence.write_text(json.dumps({
|
|
"gate": "jetson-runtime",
|
|
"status": "passed",
|
|
"git_sha": "a" * 40,
|
|
"counts": {"tests": 1, "token": "nested-secret"},
|
|
"token": "must-not-escape",
|
|
"hostname": "must-not-escape",
|
|
}))
|
|
|
|
summary = jetson_support._gate_summary(evidence)
|
|
body = jetson_support.issue_body({"gate_evidence": summary})
|
|
|
|
assert summary == {
|
|
"gate": "jetson-runtime",
|
|
"status": "passed",
|
|
"git_sha": "a" * 40,
|
|
"counts": {"tests": 1},
|
|
}
|
|
assert "must-not-escape" not in body
|
|
assert "nested-secret" not in body
|
|
assert "excludes environment variables" in body
|
|
|
|
|
|
def test_dependency_export_rejects_torch_and_bitsandbytes(tmp_path):
|
|
requirements = tmp_path / "requirements.txt"
|
|
requirements.write_text("transformers==4.56.0\npytest==8.4.1\n")
|
|
setup_jetson._require_exclusions(requirements)
|
|
|
|
for forbidden in (
|
|
"torch==2.8.0",
|
|
"torch @ https://example.invalid/torch.whl",
|
|
"bitsandbytes[diagnostics]==0.47.0",
|
|
):
|
|
requirements.write_text(forbidden + "\n")
|
|
with pytest.raises(RuntimeError, match="forbidden packages"):
|
|
setup_jetson._require_exclusions(requirements)
|
|
|
|
|
|
def test_jetson_bootstrap_preserves_vendor_runtime_and_uses_locked_no_deps(
|
|
monkeypatch,
|
|
tmp_path,
|
|
):
|
|
project = tmp_path / "project"
|
|
(project / "scripts").mkdir(parents=True)
|
|
(project / "scripts" / "jetson_support.py").write_text("# fixture\n")
|
|
(project / "uv.lock").write_text("# fixture\n")
|
|
venv = tmp_path / "jetson-venv"
|
|
commands: list[list[str]] = []
|
|
|
|
def fake_run(command, *, cwd):
|
|
command = list(command)
|
|
commands.append(command)
|
|
if command[1:4] == ["-m", "venv", "--system-site-packages"]:
|
|
(venv / "bin").mkdir(parents=True)
|
|
(venv / "pyvenv.cfg").write_text("include-system-site-packages = true\n")
|
|
if "--output-file" in command:
|
|
output = Path(command[command.index("--output-file") + 1])
|
|
output.write_text("transformers==4.56.0\n")
|
|
|
|
monkeypatch.setattr(setup_jetson, "_run", fake_run)
|
|
|
|
setup_jetson.prepare(
|
|
project=project,
|
|
venv=venv,
|
|
python="vendor-python",
|
|
uv_python="tool-python",
|
|
reuse=False,
|
|
)
|
|
|
|
assert commands[0][0] == "vendor-python"
|
|
assert "--check" in commands[0]
|
|
export = next(command for command in commands if "export" in command)
|
|
assert export.count("--no-emit-package") == 2
|
|
assert "torch" in export and "bitsandbytes" in export
|
|
installs = [command for command in commands if "install" in command]
|
|
assert len(installs) == 2
|
|
assert all("--no-deps" in command for command in installs)
|
|
assert any("check" in command for command in commands)
|
|
|
|
|
|
def test_bootstrap_rejects_unsafe_or_non_vendor_reusable_targets(tmp_path):
|
|
project = tmp_path / "project"
|
|
project.mkdir()
|
|
with pytest.raises(ValueError, match="unsafe"):
|
|
setup_jetson._require_safe_target(project, project)
|
|
|
|
existing = tmp_path / "existing"
|
|
existing.mkdir()
|
|
(existing / "pyvenv.cfg").write_text("include-system-site-packages = false\n")
|
|
with pytest.raises(ValueError, match="does not expose JetPack"):
|
|
setup_jetson._require_new_or_reusable_venv(existing, reuse=True)
|
|
|
|
|
|
def test_bitsandbytes_is_opt_in_for_quantization_only():
|
|
metadata = tomllib.loads((ROOT / "pyproject.toml").read_text())
|
|
base = metadata["project"]["dependencies"]
|
|
extras = metadata["project"]["optional-dependencies"]
|
|
|
|
assert not any(value.startswith("bitsandbytes") for value in base)
|
|
assert extras["quantization"] == ["bitsandbytes>=0.46.1"]
|
|
|
|
|
|
def test_jetson_issue_form_requires_reproducible_sanitized_hardware_evidence():
|
|
form = yaml.safe_load(
|
|
(ROOT / ".github" / "ISSUE_TEMPLATE" / "jetson-runtime.yml").read_text(),
|
|
)
|
|
fields = {value.get("id"): value for value in form["body"] if value.get("id")}
|
|
|
|
assert set(fields) == {
|
|
"device",
|
|
"jetpack",
|
|
"commit",
|
|
"reproduction",
|
|
"expected",
|
|
"actual",
|
|
"evidence",
|
|
"confirmations",
|
|
}
|
|
assert all(value.get("validations", {}).get("required") for value in fields.values())
|
|
confirmations = fields["confirmations"]["attributes"]["options"]
|
|
assert all(option["required"] for option in confirmations)
|
|
assert any("secrets" in option["label"] for option in confirmations)
|
|
|
|
|
|
def test_jetson_conditional_prerequisites_are_physical_and_cuda(monkeypatch, tmp_path):
|
|
fake_torch = SimpleNamespace(cuda=SimpleNamespace(is_available=lambda: True))
|
|
monkeypatch.setitem(sys.modules, "torch", fake_torch)
|
|
monkeypatch.setattr(run_conditional_gate.platform, "machine", lambda: "aarch64")
|
|
tegra = tmp_path / "nv_tegra_release"
|
|
tegra.write_text("# R36\n")
|
|
monkeypatch.setattr(run_conditional_gate, "JETSON_RELEASE", tegra)
|
|
assert run_conditional_gate.missing_prerequisites("jetson-runtime") == []
|
|
|
|
monkeypatch.setattr(run_conditional_gate.platform, "machine", lambda: "x86_64")
|
|
fake_torch.cuda.is_available = lambda: False
|
|
tegra.unlink()
|
|
assert run_conditional_gate.missing_prerequisites("jetson-runtime") == [
|
|
"a CUDA-capable PyTorch runtime",
|
|
"an ARM64 host",
|
|
"a Jetson L4T runtime",
|
|
]
|