emergent-security/tests/test_tenant_governance.py

78 lines
3.2 KiB
Python

"""Tenant governance only narrows the platform tenant envelope (canon C14, G7)."""
from __future__ import annotations
import pytest
from fixture_loading import ENVELOPES, FIXTURES, deep_merge, load_yaml
from emergent_security.tenant import PlatformTenantEnvelope, effective_ceilings, validate_tenant_governance
SPEC = load_yaml(FIXTURES / "tenants" / "governance-validation.yaml")
@pytest.fixture(scope="module")
def platform() -> PlatformTenantEnvelope:
return PlatformTenantEnvelope.from_dict(load_yaml(ENVELOPES / SPEC["platform_envelope"]))
@pytest.fixture(scope="module")
def base_governance() -> dict:
return load_yaml(ENVELOPES / SPEC["base"])
@pytest.mark.parametrize("case", SPEC["cases"], ids=[c["name"] for c in SPEC["cases"]])
def test_governance_validation(case, platform, base_governance, scales):
errors = validate_tenant_governance(deep_merge(base_governance, case["patch"]), platform, scales)
if case["error"] is None:
assert errors == []
else:
assert any(case["error"] in error for error in errors), errors
def test_platform_example_is_valid(platform, scales):
assert platform.validate(scales) == []
def test_platform_delegations_must_be_capabilities(scales):
broken = PlatformTenantEnvelope.from_dict(
{"id": "envelope://x", "tenant": "tenant://x", "capabilities": ["code.edit"],
"delegated": {"iam.change": {"mode": "autonomous"}}, "ceilings": {}, "prohibitions": []}
)
assert any("delegated class outside capabilities: iam.change" in e for e in broken.validate(scales))
def test_platform_cannot_both_delegate_and_prohibit(scales):
broken = PlatformTenantEnvelope.from_dict(
{"id": "envelope://x", "tenant": "tenant://x", "capabilities": ["code.edit"],
"delegated": {"code.edit": {"mode": "autonomous"}}, "ceilings": {}, "prohibitions": ["code.edit"]}
)
assert any("both delegated and prohibited: code.edit" in e for e in broken.validate(scales))
def test_effective_ceiling_is_the_narrower_value(platform, base_governance, scales):
from emergent_security.tenant import TenantGovernance
effective = effective_ceilings(platform, TenantGovernance.from_dict(base_governance), scales)
assert effective["blast_radius"] == "repository" # tenant narrowed
assert effective["data_sensitivity"] == "personal" # platform value kept
def test_platform_widening_does_not_erase_tenant_restrictions(platform, base_governance, scales):
from dataclasses import replace
from emergent_security.tenant import TenantGovernance
wider = replace(platform, ceilings={**platform.ceilings, "blast_radius": "platform"})
effective = effective_ceilings(wider, TenantGovernance.from_dict(base_governance), scales)
assert effective["blast_radius"] == "repository"
def test_platform_narrowing_propagates_immediately(platform, base_governance, scales):
from dataclasses import replace
from emergent_security.tenant import TenantGovernance
narrower = replace(platform, ceilings={**platform.ceilings, "blast_radius": "task"})
effective = effective_ceilings(narrower, TenantGovernance.from_dict(base_governance), scales)
assert effective["blast_radius"] == "task"