from __future__ import annotations """CAP_SYS_PTRACE three-state contract tests (V2R2C2 P0). Covers the capability boundary that lets the trusted candidate builder read the peer's /proc//{cgroup,exe,cmdline} across uids: State A (no CAP / cross-uid read denied): fail closed -> cgroup /proc//cgroup PermissionError(EACCES) -> PEER_CGROUP_UNAVAILABLE exe /proc//exe PermissionError(EACCES) -> PEER_PROCESS_UNAVAILABLE cmdline /proc//cmdline PermissionError(EACCES) -> PEER_PROCESS_UNAVAILABLE State B (minimal CAP, legitimate peer): resolved, readiness READY. State C (CAP present, illegitimate peer): DENIED — capability never bypasses the identity policy. State B/C identity enforcement is exercised by the existing test_trusted_candidate_builder.py (readiness READY + *_DENIED). State A here is modelled with a monkeypatched PermissionError(EACCES) rather than by guessing a high pid: a missing CAP_SYS_PTRACE / cross-uid read yields exactly PermissionError(errno.EACCES) from the kernel, so the resolvers must fail closed against that concrete error on each of the three /proc views. This removes the prior assume-a-large-pid heuristic, which could not deterministically produce EACCES. """ import errno import os from pathlib import Path import sys import pytest ROOT = Path(__file__).resolve().parents[1] APP = ROOT / "active-runtime" / "app" if str(APP) not in sys.path: sys.path.insert(0, str(APP)) import aios_trusted_candidate_builder as mod # noqa: E402 from aios_trusted_candidate_builder import ( # noqa: E402 BuilderError, _resolve_cgroups, _resolve_process_identity, ) def _eacces() -> PermissionError: return PermissionError(errno.EACCES, "cross-uid /proc read denied") def test_state_a_cgroup_read_denied_fails_closed(monkeypatch: pytest.MonkeyPatch): # /proc//cgroup read raises PermissionError(EACCES) -> PEER_CGROUP_UNAVAILABLE. real_read_text = Path.read_text def denied_cgroup(self, *a, **k): if str(self) == "/proc/7/cgroup": raise _eacces() return real_read_text(self, *a, **k) monkeypatch.setattr(Path, "read_text", denied_cgroup) with pytest.raises(BuilderError, match="PEER_CGROUP_UNAVAILABLE"): _resolve_cgroups(7) def test_state_a_exe_read_denied_fails_closed(monkeypatch: pytest.MonkeyPatch): # /proc//exe realpath raises PermissionError(EACCES) -> PEER_PROCESS_UNAVAILABLE. def denied_realpath(path): if str(path) == "/proc/7/exe": raise _eacces() return os.path.realpath(path) monkeypatch.setattr(os.path, "realpath", denied_realpath) with pytest.raises(BuilderError, match="PEER_PROCESS_UNAVAILABLE"): _resolve_process_identity(7) def test_state_a_cmdline_read_denied_fails_closed(monkeypatch: pytest.MonkeyPatch): # /proc//cmdline read_bytes raises PermissionError(EACCES) # -> PEER_PROCESS_UNAVAILABLE (cmdline branch, distinct from exe branch). real_read_bytes = Path.read_bytes def denied_cmdline(self, *a, **k): if str(self) == "/proc/7/cmdline": raise _eacces() return real_read_bytes(self, *a, **k) monkeypatch.setattr(Path, "read_bytes", denied_cmdline) with pytest.raises(BuilderError, match="PEER_PROCESS_UNAVAILABLE"): _resolve_process_identity(7) def test_captrace_unit_is_live_baseline_with_minimal_capability_only(): unit = ( ROOT / "deploy" / "systemd" / "aios-trusted-candidate-builder.service" ).read_text(encoding="utf-8") assert "AmbientCapabilities=CAP_SYS_PTRACE" in unit assert "CapabilityBoundingSet=CAP_SYS_PTRACE" in unit # Minimum-capability contract: NoNewPrivileges stays and the capability # set is the live root baseline (User=root / Group=root), no invented # ProtectProc / ProcSubset / credential paths / socket ownership. assert "NoNewPrivileges=true" in unit assert "User=root" in unit assert "Group=root" in unit assert "RestrictAddressFamilies=AF_UNIX" in unit assert "ProtectProc" not in unit assert "ProcSubset" not in unit # No wildcard capability declaration beyond the single CAP_SYS_PTRACE. assert "CapabilityBoundingSet=CAP_" not in unit.replace( "CapabilityBoundingSet=CAP_SYS_PTRACE", "" ) assert "AmbientCapabilities=CAP_" not in unit.replace( "AmbientCapabilities=CAP_SYS_PTRACE", "" ) # No divergent non-root -ptrace unit is tracked. assert not (ROOT / "deploy" / "systemd" / "aios-trusted-candidate-builder-ptrace.service").exists() def test_captrace_security_document_marks_capability_high_sensitivity(): doc = ( ROOT / "docs" / "security" / "trusted-builder-captrace.md" ).read_text(encoding="utf-8") assert "PEER_PROCESS_UNAVAILABLE" in doc assert "PEER_CGROUP_UNAVAILABLE" in doc assert "READY" in doc for denied in ("PEER_IDENTITY_DENIED", "PEER_CGROUP_DENIED", "PEER_PROCESS_DENIED"): assert denied in doc # Capability must never bypass identity policy. assert "must never bypass" in doc # The instruction requires CAP_SYS_PTRACE be described as high-sensitivity: # the doc must frame it as carrying inspection/debug authority and must NOT # positively claim it "grants no control authority". assert "high-sensitivity" in doc assert "broadens the process's observation and debugging authority" in doc assert "grants no control authority" not in doc assert "grants no write or control authority" not in doc