OSVauco/opax-mcp/test_capability_registry.py

141 lines
5.3 KiB
Python

import ast
import sys
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "opax-mcp"))
from capability_registry import (
CAPABILITIES,
Availability,
RiskLevel,
get_capability,
list_active_capabilities,
list_capabilities,
)
class TestCapabilityRegistry(unittest.TestCase):
def setUp(self):
self.capabilities = list_capabilities()
def test_registry_contains_exactly_nineteen_capabilities(self):
self.assertEqual(len(self.capabilities), 19)
self.assertEqual(len(CAPABILITIES), 19)
def test_identifiers_are_unique(self):
identifiers = [capability.id for capability in self.capabilities]
self.assertEqual(len(identifiers), len(set(identifiers)))
def test_order_is_deterministic_and_starts_with_active_capabilities(self):
self.assertEqual(
[capability.id for capability in self.capabilities[:2]],
["emma.chat", "emma.analyze_user_text"],
)
self.assertEqual(
[capability.id for capability in self.capabilities],
list(CAPABILITIES.keys()),
)
def test_active_capabilities_are_exactly_the_two_permitted_capabilities(self):
active = list_active_capabilities()
self.assertEqual(
[capability.id for capability in active],
["emma.chat", "emma.analyze_user_text"],
)
for capability in active:
self.assertEqual(capability.risk_level, RiskLevel.READ)
self.assertFalse(capability.approval_required)
self.assertFalse(capability.self_approval_forbidden)
def test_write_and_high_impact_capabilities_are_planned_and_gated(self):
gated = [
capability
for capability in self.capabilities
if capability.risk_level in {RiskLevel.WRITE, RiskLevel.HIGH_IMPACT}
]
self.assertTrue(gated)
for capability in gated:
self.assertEqual(capability.availability, Availability.PLANNED)
self.assertTrue(capability.approval_required)
self.assertTrue(capability.audit_required)
self.assertTrue(capability.self_approval_forbidden)
def test_forbidden_shell_capability_has_no_execution_target(self):
capability = get_capability("terminal.arbitrary_shell")
self.assertIsNotNone(capability)
self.assertEqual(capability.risk_level, RiskLevel.FORBIDDEN)
self.assertEqual(capability.availability, Availability.FORBIDDEN)
self.assertIsNone(capability.backend_tool)
self.assertFalse(capability.approval_required)
self.assertTrue(capability.self_approval_forbidden)
self.assertEqual(capability.allowed_targets, ())
def test_unknown_capability_returns_none(self):
self.assertIsNone(get_capability("unknown"))
def test_public_registry_mapping_is_immutable(self):
with self.assertRaises(TypeError):
CAPABILITIES["new.capability"] = get_capability("emma.chat")
def test_schema_mappings_are_immutable(self):
for capability in self.capabilities:
with self.assertRaises(TypeError):
capability.input_schema["unexpected"] = "value"
with self.assertRaises(TypeError):
capability.output_schema["unexpected"] = "value"
def test_registry_module_has_no_external_execution_imports(self):
module_path = REPO_ROOT / "opax-mcp" / "capability_registry.py"
tree = ast.parse(module_path.read_text(encoding="utf-8"))
forbidden_roots = {
"os",
"subprocess",
"requests",
"httpx",
"google",
"gitea",
"firebase",
"firestore",
}
imported_roots = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
imported_roots.update(alias.name.split(".")[0] for alias in node.names)
if isinstance(node, ast.ImportFrom) and node.module:
imported_roots.add(node.module.split(".")[0])
self.assertFalse(imported_roots & forbidden_roots)
def test_active_and_planned_capabilities_have_required_metadata(self):
for capability in self.capabilities:
if capability.availability == Availability.FORBIDDEN:
continue
self.assertTrue(capability.id)
self.assertTrue(capability.display_name)
self.assertTrue(capability.description)
self.assertTrue(capability.category)
self.assertTrue(capability.execution_owner)
self.assertTrue(capability.allowed_targets)
def test_planned_write_and_high_impact_bindings_and_rollbacks(self):
rollback_required_ids = {
"gitea.push_change",
"cloudrun.deploy_digest",
"emma.update_ui",
"emma.update_backend",
"emma.update_model_config",
}
for capability in self.capabilities:
if capability.risk_level not in {RiskLevel.WRITE, RiskLevel.HIGH_IMPACT}:
continue
self.assertTrue(capability.approval_binding)
self.assertEqual(
capability.rollback_required,
capability.id in rollback_required_ids,
)
if __name__ == "__main__":
unittest.main()