2026-08-18 12:15:41 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import importlib.util
|
2026-08-22 14:53:31 +02:00
|
|
|
import json
|
2026-08-18 12:15:41 +02:00
|
|
|
import pathlib
|
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_PATH = pathlib.Path(__file__).with_name("validate.py")
|
|
|
|
|
SPEC = importlib.util.spec_from_file_location("tenancy_posture_validate", MODULE_PATH)
|
|
|
|
|
assert SPEC and SPEC.loader
|
|
|
|
|
VALIDATE = importlib.util.module_from_spec(SPEC)
|
|
|
|
|
SPEC.loader.exec_module(VALIDATE)
|
2026-08-22 14:53:31 +02:00
|
|
|
SCHEMA = json.loads(VALIDATE.SCHEMA.read_text(encoding="utf-8"))
|
2026-08-18 12:15:41 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def declaration() -> dict:
|
|
|
|
|
reasons = {axis: "floor explained" for axis in VALIDATE.AXES}
|
|
|
|
|
return {
|
|
|
|
|
"schema_version": "0.1",
|
|
|
|
|
"framework": "netkingdom-tenancy-posture",
|
|
|
|
|
"service": "example",
|
|
|
|
|
"role": "test",
|
|
|
|
|
"tenancy": {
|
|
|
|
|
"current": {"I": 1, "A": 1, "E": 0, "P": 0, "R": 1, "V": 0},
|
|
|
|
|
"target": {"I": 1, "A": 1, "E": 0, "P": 0, "R": 1, "V": 0},
|
|
|
|
|
"reviewed": "2026-08-17",
|
|
|
|
|
"review_due": "2027-02-17",
|
|
|
|
|
"service_class": "interactive",
|
|
|
|
|
"reason": reasons,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2026-08-22 14:53:31 +02:00
|
|
|
def zone_declaration() -> dict:
|
|
|
|
|
return {
|
|
|
|
|
"standard": "security-zones_v0.1",
|
|
|
|
|
"membership": "z2-continuity",
|
|
|
|
|
"responsible_party": "ops-warden",
|
|
|
|
|
"justification": "foundational access path",
|
|
|
|
|
"context": {
|
|
|
|
|
"maturity": "M2",
|
|
|
|
|
"criticality": "high",
|
|
|
|
|
"data_classification": "confidential",
|
|
|
|
|
},
|
|
|
|
|
"evidence": [
|
|
|
|
|
{
|
|
|
|
|
"ref": "docs/evidence/example-zone.md",
|
|
|
|
|
"supports": ["M2", "continuity-dependency"],
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"reviewed": "2026-08-22",
|
|
|
|
|
"review_due": "2026-11-22",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2026-08-18 12:15:41 +02:00
|
|
|
class SemanticValidationTests(unittest.TestCase):
|
|
|
|
|
def validate(self, document: dict) -> list[str]:
|
|
|
|
|
return VALIDATE.validate_semantics(document, pathlib.Path("tenancy.yaml"))
|
|
|
|
|
|
2026-08-22 14:53:31 +02:00
|
|
|
def validate_full(self, document: dict, tmp_path: pathlib.Path) -> list[str]:
|
|
|
|
|
import yaml
|
|
|
|
|
|
|
|
|
|
tmp_path.write_text(yaml.safe_dump(document), encoding="utf-8")
|
|
|
|
|
return VALIDATE.validate(tmp_path, SCHEMA)
|
|
|
|
|
|
2026-08-18 12:15:41 +02:00
|
|
|
def test_floor_vector_with_reasons_is_valid(self) -> None:
|
|
|
|
|
self.assertEqual([], self.validate(declaration()))
|
|
|
|
|
|
|
|
|
|
def test_level_above_floor_requires_exact_evidence_key(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["tenancy"]["current"]["A"] = 2
|
|
|
|
|
self.assertIn("current A2 has no evidence entry", self.validate(document)[0])
|
|
|
|
|
document["evidence"] = {"A2": "docs/evidence/authorization.md"}
|
|
|
|
|
self.assertEqual([], self.validate(document))
|
|
|
|
|
|
|
|
|
|
def test_implemented_level_must_be_above_current(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["tenancy"]["implemented"] = {"E": 0}
|
|
|
|
|
self.assertIn("implemented E0 must be above current E0", self.validate(document)[0])
|
|
|
|
|
|
|
|
|
|
def test_provider_available_cannot_exceed_maximum(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["provider"] = {"axes": {"V": {"available": 2, "maximum": 1}}}
|
|
|
|
|
self.assertIn("provider V available 2 exceeds maximum 1", self.validate(document)[0])
|
|
|
|
|
|
|
|
|
|
def test_review_due_cannot_precede_review(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["tenancy"]["review_due"] = "2026-08-16"
|
|
|
|
|
self.assertIn("review_due precedes reviewed", self.validate(document)[0])
|
|
|
|
|
|
2026-08-23 13:16:34 +02:00
|
|
|
def test_evidence_freshness_must_reference_evidence_key(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["evidence_freshness"] = {
|
|
|
|
|
"E2": {
|
|
|
|
|
"kind": "adversarial",
|
|
|
|
|
"observed_at": "2026-08-22T22:10:25Z",
|
|
|
|
|
"valid_until": "2026-08-23T22:10:25Z",
|
|
|
|
|
"responsible_repo": "example",
|
|
|
|
|
"scope": "bounded tenant probes",
|
|
|
|
|
"remediation": "repeat the bounded run",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self.assertIn(
|
|
|
|
|
"evidence_freshness E2 has no evidence entry",
|
|
|
|
|
self.validate(document)[0],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_evidence_freshness_expiry_must_follow_observation(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["evidence"] = {"E2": "docs/evidence/e2.md"}
|
|
|
|
|
document["evidence_freshness"] = {
|
|
|
|
|
"E2": {
|
|
|
|
|
"kind": "adversarial",
|
|
|
|
|
"observed_at": "2026-08-22T22:10:25Z",
|
|
|
|
|
"valid_until": "2026-08-22T22:10:25Z",
|
|
|
|
|
"responsible_repo": "example",
|
|
|
|
|
"scope": "bounded tenant probes",
|
|
|
|
|
"remediation": "repeat the bounded run",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self.assertIn(
|
|
|
|
|
"valid_until must be after observed_at",
|
|
|
|
|
self.validate(document)[0],
|
|
|
|
|
)
|
|
|
|
|
|
2026-08-18 12:15:41 +02:00
|
|
|
def test_service_names_are_unique(self) -> None:
|
|
|
|
|
entry = declaration()
|
|
|
|
|
document = {
|
|
|
|
|
"schema_version": "0.1",
|
|
|
|
|
"framework": "netkingdom-tenancy-posture",
|
|
|
|
|
"services": [entry, entry],
|
|
|
|
|
}
|
|
|
|
|
self.assertIn("service names must be unique", self.validate(document)[0])
|
|
|
|
|
|
2026-08-22 14:53:31 +02:00
|
|
|
def test_workload_identity_name_must_match_service(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["workload_identity"] = {
|
|
|
|
|
"name": "different",
|
|
|
|
|
"kind": "operational-control-plane",
|
|
|
|
|
"responsible_repo": "example",
|
|
|
|
|
"identity_bindings": [
|
|
|
|
|
{
|
|
|
|
|
"scheme": "iam-profile",
|
|
|
|
|
"authority": "key-cape",
|
|
|
|
|
"subject": "example-prod",
|
|
|
|
|
"principal_type": "service",
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
self.assertIn(
|
|
|
|
|
"workload_identity.name must equal service", self.validate(document)[0]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_workload_identity_bindings_are_unique(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
binding = {
|
|
|
|
|
"scheme": "iam-profile",
|
|
|
|
|
"authority": "key-cape",
|
|
|
|
|
"subject": "example-prod",
|
|
|
|
|
"principal_type": "service",
|
|
|
|
|
}
|
|
|
|
|
document["workload_identity"] = {
|
|
|
|
|
"name": "example",
|
|
|
|
|
"kind": "platform-service",
|
|
|
|
|
"responsible_repo": "example",
|
|
|
|
|
"identity_bindings": [binding, binding],
|
|
|
|
|
}
|
|
|
|
|
self.assertIn(
|
|
|
|
|
"workload identity bindings must be unique", self.validate(document)[0]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_zones_require_authoritative_workload_identity(self) -> None:
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["zones"] = zone_declaration()
|
|
|
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
|
|
|
path = pathlib.Path(directory) / "tenancy.yaml"
|
|
|
|
|
errors = self.validate_full(document, path)
|
|
|
|
|
self.assertTrue(any("workload_identity" in error for error in errors))
|
|
|
|
|
|
|
|
|
|
def test_operational_workload_may_declare_zones(self) -> None:
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["workload_identity"] = {
|
|
|
|
|
"name": "example",
|
|
|
|
|
"kind": "operational-control-plane",
|
|
|
|
|
"responsible_repo": "ops-warden",
|
|
|
|
|
"identity_bindings": [
|
|
|
|
|
{
|
|
|
|
|
"scheme": "ssh-certificate",
|
|
|
|
|
"authority": "ops-warden",
|
|
|
|
|
"subject": "agt-example",
|
|
|
|
|
"principal_type": "agent",
|
|
|
|
|
"environment": "prod",
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
document["zones"] = zone_declaration()
|
|
|
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
|
|
|
path = pathlib.Path(directory) / "tenancy.yaml"
|
|
|
|
|
self.assertEqual([], self.validate_full(document, path))
|
|
|
|
|
|
|
|
|
|
def test_zone_membership_uses_canonical_catalog(self) -> None:
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["workload_identity"] = {
|
|
|
|
|
"name": "example",
|
|
|
|
|
"kind": "application",
|
|
|
|
|
"responsible_repo": "example",
|
|
|
|
|
"declaration_ref": "rapp-example/declarations/rapp.yaml",
|
|
|
|
|
"identity_bindings": [
|
|
|
|
|
{
|
|
|
|
|
"scheme": "iam-profile",
|
|
|
|
|
"authority": "key-cape",
|
|
|
|
|
"subject": "example-prod",
|
|
|
|
|
"principal_type": "service",
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
document["zones"] = zone_declaration()
|
|
|
|
|
document["zones"]["membership"] = "permissive-default"
|
|
|
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
|
|
|
path = pathlib.Path(directory) / "tenancy.yaml"
|
|
|
|
|
errors = self.validate_full(document, path)
|
|
|
|
|
self.assertTrue(any("membership" in error for error in errors))
|
|
|
|
|
|
|
|
|
|
def test_zone_review_due_must_be_after_reviewed(self) -> None:
|
|
|
|
|
document = declaration()
|
|
|
|
|
document["zones"] = zone_declaration()
|
|
|
|
|
document["zones"]["review_due"] = document["zones"]["reviewed"]
|
|
|
|
|
self.assertIn(
|
|
|
|
|
"zones.review_due must be after zones.reviewed",
|
|
|
|
|
self.validate(document)[0],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_multi_service_zones_must_not_be_top_level(self) -> None:
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
entry = declaration()
|
|
|
|
|
document = {
|
|
|
|
|
"schema_version": "0.1",
|
|
|
|
|
"framework": "netkingdom-tenancy-posture",
|
|
|
|
|
"services": [entry],
|
|
|
|
|
"zones": zone_declaration(),
|
|
|
|
|
}
|
|
|
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
|
|
|
path = pathlib.Path(directory) / "tenancy.yaml"
|
|
|
|
|
errors = self.validate_full(document, path)
|
|
|
|
|
self.assertTrue(errors)
|
|
|
|
|
|
|
|
|
|
def test_multi_service_zone_requires_identity_on_same_entry(self) -> None:
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
entry = declaration()
|
|
|
|
|
entry["zones"] = zone_declaration()
|
|
|
|
|
document = {
|
|
|
|
|
"schema_version": "0.1",
|
|
|
|
|
"framework": "netkingdom-tenancy-posture",
|
|
|
|
|
"services": [entry],
|
|
|
|
|
}
|
|
|
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
|
|
|
path = pathlib.Path(directory) / "tenancy.yaml"
|
|
|
|
|
errors = self.validate_full(document, path)
|
|
|
|
|
self.assertTrue(any("workload_identity" in error for error in errors))
|
|
|
|
|
|
2026-08-18 12:15:41 +02:00
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
unittest.main()
|