Add meta-framework spec, pydantic schemas, profile/extension YAML, extension registry, ext.compose-ssh backend, SandboxManager with State Hub events, CLI commands, integration docs, capability registry entry, and compose-e2e runbook. Nine unit tests pass. T10 remote smoke test remains for operator.
61 lines
No EOL
1.9 KiB
Python
61 lines
No EOL
1.9 KiB
Python
"""Schema and loader tests."""
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
from sandboxer.extensions.registry import load_all_extensions, load_extension
|
|
from sandboxer.models import Consumer, Profile, SandboxCreateRequest
|
|
from sandboxer.profiles.loader import load_profile
|
|
|
|
|
|
def test_load_compose_e2e_profile() -> None:
|
|
profile = load_profile("profile.compose-e2e")
|
|
assert profile.extension == "ext.compose-ssh"
|
|
assert profile.placement.prefer == ["sandboxer01"]
|
|
|
|
|
|
def test_load_compose_ssh_extension() -> None:
|
|
ext = load_extension("ext.compose-ssh")
|
|
assert ext.handler.endswith("ComposeSSHExtension")
|
|
assert "container" in ext.capabilities.isolation_levels
|
|
|
|
|
|
def test_load_all_extensions_no_duplicates() -> None:
|
|
extensions = load_all_extensions()
|
|
assert "ext.compose-ssh" in extensions
|
|
assert len(extensions) == len(set(extensions))
|
|
|
|
|
|
def test_profile_roundtrip(tmp_path: Path) -> None:
|
|
data = load_profile("profile.compose-e2e").model_dump()
|
|
path = tmp_path / "profile.test.yaml"
|
|
path.write_text(yaml.dump(data))
|
|
loaded = Profile.model_validate(yaml.safe_load(path.read_text()))
|
|
assert loaded.id == "profile.compose-e2e"
|
|
|
|
|
|
def test_sandbox_create_request() -> None:
|
|
req = SandboxCreateRequest(
|
|
profile="profile.compose-e2e",
|
|
inputs={"repo": "/tmp/foo"},
|
|
consumer=Consumer(actor="adm", project="sand-boxer"),
|
|
)
|
|
assert req.inputs["repo"] == "/tmp/foo"
|
|
|
|
|
|
def test_extension_missing_handler(tmp_path: Path) -> None:
|
|
bad = tmp_path / "ext.bad.yaml"
|
|
bad.write_text(
|
|
yaml.dump(
|
|
{
|
|
"id": "ext.bad",
|
|
"title": "Bad",
|
|
"handler": "",
|
|
"capabilities": {"isolation_levels": ["container"], "pricing_model": "self-hosted"},
|
|
}
|
|
)
|
|
)
|
|
with pytest.raises(ValueError, match="missing handler"):
|
|
load_extension("ext.bad", extensions_root=tmp_path) |