Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,12 @@ python -m pyisolate.conformance --grade
pyisolate-doctor --grade
```

The `--grade` output replaces a vague secure/insecure claim with an 8-point
The `--grade` output replaces a vague secure/insecure claim with a 10-point
score over the guarantees that are actually active on the host: free-threading,
eBPF-LSM, cgroup v2, Landlock fallback, no-GIL extension safety, broker crypto,
quota enforcement, and crash isolation. Use it in CI or admission checks to
attach evidence to each guarantee rather than relying on a single pass/fail bit.
eBPF-LSM, cgroup v2, Landlock fallback, Landlock network egress, no-GIL extension
safety, broker crypto, quota enforcement, crash isolation, and microVM readiness.
Use it in CI or admission checks to attach evidence to each guarantee rather than
relying on a single pass/fail bit.

### Policy editor

Expand Down
49 changes: 49 additions & 0 deletions pyisolate/conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,13 @@ def grade(self) -> GradeReport:
quota_enforcement = self._probe_timeout_and_kill_behavior()
ebpf_lsm = self._probe_ebpf_lsm(bpf_availability)
landlock_fallback = self._probe_landlock_fallback(ebpf_lsm.passed)
landlock_net_egress = self._probe_landlock_net_egress()
no_gil_extension_safety = self._probe_no_gil_extension_safety(
python_build, policy_enforcement
)
broker_crypto = self._probe_broker_crypto()
crash_isolation = self._probe_crash_isolation()
microvm_ready = self._probe_microvm_readiness()

probe_components = [
(
Expand All @@ -134,6 +136,12 @@ def grade(self) -> GradeReport:
landlock_fallback,
landlock_fallback.passed,
),
(
"landlock_net_egress",
"Landlock network egress",
landlock_net_egress,
landlock_net_egress.passed,
),
(
"no_gil_extension_safety",
"no-GIL extension safety",
Expand All @@ -153,6 +161,12 @@ def grade(self) -> GradeReport:
crash_isolation,
crash_isolation.passed,
),
(
"microvm_ready",
"microVM readiness",
microvm_ready,
microvm_ready.passed,
),
]
components = [
GradeComponent(
Expand Down Expand Up @@ -336,6 +350,41 @@ def _probe_landlock_fallback(self, ebpf_lsm_active: bool = False) -> ProbeResult
},
)

def _probe_landlock_net_egress(self) -> ProbeResult:
from pyisolate.runtime import landlock

abi = landlock.abi_version()
supported = landlock.net_supported()
return ProbeResult(
name="landlock_net_egress",
passed=supported,
required=False,
details=(
"Landlock TCP-egress rules confine process-backend connect() to "
"the policy's ports (Landlock ABI >= 4)"
),
evidence={
"landlock_abi": abi,
"net_supported": supported,
"min_abi": 4,
},
)

def _probe_microvm_readiness(self) -> ProbeResult:
from pyisolate.runtime import microvm

support = microvm.detect_microvm_support()
return ProbeResult(
name="microvm_ready",
passed=support.ready,
required=False,
details=(
"A supported VMM and an accessible /dev/kvm are present, so the "
"microVM hardware boundary can be launched"
),
evidence=support.as_dict(),
)

def _probe_cgroup_behavior(self) -> ProbeResult:
from pyisolate import cgroup

Expand Down
64 changes: 62 additions & 2 deletions tests/test_conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,25 @@ def test_grade_report_scores_named_guarantees(monkeypatch):
"_probe_crash_isolation",
lambda self: ProbeResult("crash_isolation", True, True, "crash ok", {}),
)
monkeypatch.setattr(
ConformanceSuite,
"_probe_landlock_net_egress",
lambda self: ProbeResult(
"landlock_net_egress", False, False, "no net egress", {}
),
)
monkeypatch.setattr(
ConformanceSuite,
"_probe_microvm_readiness",
lambda self: ProbeResult("microvm_ready", False, False, "no kvm", {}),
)
monkeypatch.setattr("pyisolate.conformance.sys.version_info", (3, 13, 0))

report = ConformanceSuite().grade()
payload = report.to_dict()

assert report.score == 7
assert report.max_score == 8
assert report.max_score == 10
assert payload["active_guarantees"] == [
"free_threading",
"ebpf_lsm",
Expand All @@ -141,19 +153,67 @@ def test_grade_report_scores_named_guarantees(monkeypatch):
"quota_enforcement",
"crash_isolation",
]
assert payload["inactive_guarantees"] == ["landlock_fallback"]
assert payload["inactive_guarantees"] == [
"landlock_fallback",
"landlock_net_egress",
"microvm_ready",
]
assert [component["label"] for component in payload["components"]] == [
"free-threading",
"eBPF-LSM",
"cgroup v2",
"Landlock fallback",
"Landlock network egress",
"no-GIL extension safety",
"broker crypto",
"quota enforcement",
"crash isolation",
"microVM readiness",
]


def test_probe_landlock_net_egress_reflects_support(monkeypatch):
from pyisolate.runtime import landlock

suite = ConformanceSuite()
monkeypatch.setattr(landlock, "abi_version", lambda: 4)
monkeypatch.setattr(landlock, "net_supported", lambda: True)
result = suite._probe_landlock_net_egress()
assert result.name == "landlock_net_egress"
assert result.passed is True
assert result.evidence["landlock_abi"] == 4
assert result.evidence["min_abi"] == 4

monkeypatch.setattr(landlock, "net_supported", lambda: False)
assert suite._probe_landlock_net_egress().passed is False


def test_probe_microvm_readiness_reflects_support(monkeypatch):
from pyisolate.runtime import microvm

suite = ConformanceSuite()
monkeypatch.setattr(
microvm,
"detect_microvm_support",
lambda: microvm.MicroVMSupport(
vmm_kind="firecracker", vmm_path="/usr/bin/firecracker", kvm=True
),
)
result = suite._probe_microvm_readiness()
assert result.name == "microvm_ready"
assert result.passed is True
assert result.evidence["vmm_kind"] == "firecracker"

monkeypatch.setattr(
microvm,
"detect_microvm_support",
lambda: microvm.MicroVMSupport(
vmm_kind=None, vmm_path=None, kvm=False, reasons=("no vmm",)
),
)
assert suite._probe_microvm_readiness().passed is False


def test_conformance_cli_grade(monkeypatch, capsys):
monkeypatch.setattr(
ConformanceSuite,
Expand Down
Loading