tenant-engine/tests/test_layer_conformance.py

220 lines
8.8 KiB
Python
Raw Normal View History

"""TEN-WP-0011-T01/T02: layer declaration and published PEP stance."""
from __future__ import annotations
import importlib.util
import subprocess
import sys
from pathlib import Path
import yaml
from tenant_engine.stance import published_stance, shipped_stance
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "scripts" / "check_layer_conformance.py"
def _run(*args: str) -> subprocess.CompletedProcess[str]:
return subprocess.run([sys.executable, str(SCRIPT), *args], capture_output=True, text=True)
def test_layer_yaml_declares_engine_pip():
data = yaml.safe_load((ROOT / "layer.yaml").read_text())
assert data["repository"] == "tenant-engine"
assert data["layer"] == "engine"
assert data["role"] == "pip"
assert data["derived"] is True
assert data["derived_from"] == "INTENT.md"
assert data["tooling_contacts"] == []
assert data["pep_stance"] == "pep-stance.yaml"
assert data["pip_claims"] == "pip-claims.yaml"
ids = {c["id"] for c in data["non_tooling_clients"]}
assert "postgres-own-store" in ids
assert "sqlite-dev-store" in ids
assert "access-engine-check" in ids
assert "state-hub-work-records" in ids
def _intent() -> dict:
return yaml.safe_load((ROOT / "INTENT.md").read_text().split("---", 2)[1])
def _fold(value: object) -> str:
return str(value).translate(str.maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"abcdefghijklmnopqrstuvwxyz"))
def test_intent_frontmatter_agrees_with_layer_yaml():
"""A11/A9: the derived form agrees with the governing one after a case-fold.
A fold, not an equality: INTENT.md says Engine and layer.yaml says engine,
and neither is re-spelled. A real divergence still fails.
"""
intent = _intent()
decl = yaml.safe_load((ROOT / "layer.yaml").read_text())
assert _fold(intent["layer"]) == _fold(decl["layer"])
assert _fold(intent["role"]) == _fold(decl["role"])
assert _fold(intent["layer"]) in {"taxonomy", "tooling", "engine", "staff"}
def _checker():
spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return module
def test_no_declaration_carries_a_standard_version():
"""A12 r2 / GH-DEC-2026-020: no version in any key or value of either form."""
checker = _checker()
assert "standard_version" not in yaml.safe_load((ROOT / "layer.yaml").read_text())
assert "standard_version" not in _intent()
assert checker.version_findings(yaml.safe_load((ROOT / "layer.yaml").read_text()),
"layer.yaml") == []
assert checker.version_findings(_intent(), "INTENT.md") == []
def test_versioned_standard_path_or_companion_version_fails():
"""GH-DEC-2026-020 §1-§2: the pin is caught under any name, not only standard_version."""
checker = _checker()
base = {"layer": "Engine", "role": "PIP"}
bad = [
{**base, "standard": "net-kingdom/canon/standards/security-layer-model_v0.7.md"},
{**base, "companion_version": "0.2"},
{**base, "companion": "net-kingdom/SECURITY-COMPANION.md v0.2"},
{**base, "standard_version": "0.8"},
{**base, "standard": "security-layer-model v0.7"}, # 021 §3 addition
{**base, "ref": "net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md"},
]
for data in bad:
assert checker.version_findings(data, "x"), data
def test_schema_version_comments_and_section_numbers_are_not_reached():
checker = _checker()
data = yaml.safe_load(
"# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md\n"
"schema_version: '0.1'\nstandard: netkingdom-security-layer-model\n"
"declared_shapes: {'5.1': [], '5.2': []}\ndeclared_at: '2026-08-29'\n"
"notes: [{note: 'Outside §5 by the v0.7 scope rule.'}]\n")
assert checker.version_findings(data, "x") == []
def test_prose_citation_is_not_a_pin():
"""GH-DEC-2026-021 §1: a revision cited in prose is provenance, not reached."""
checker = _checker()
for data in ({"notes": [{"note": "Outside §5 by the v0.7 scope rule."}]},
{"role_note": "Per Security Layer Model v0.8 §11 and companion v0.2."}):
assert checker.version_findings(data, "x") == [], data
def test_checker_does_not_apply_a12_to_stance_or_claims_maps():
"""A12 r2 / GH-DEC-2026-020 §3: those files keep their version and are not read for it."""
for name in ("pep-stance.yaml", "pip-claims.yaml"):
assert "standard_version" in yaml.safe_load((ROOT / name).read_text())
assert _run().returncode == 0
def test_every_run_states_version_and_scope(tmp_path):
"""GH-DEC-2026-020 §4: the version lives in the run, on success and on failure."""
checker = _checker()
ok = _run()
assert ok.stdout.count(checker.VALIDATED_AGAINST) >= 2 # header and OK line
assert "scope:" in ok.stdout
report = _run("--report")
assert checker.VALIDATED_AGAINST in report.stdout and "scope:" in report.stdout
def test_a_failing_run_still_states_version_and_scope(tmp_path, monkeypatch, capsys):
checker = _checker()
fake = tmp_path / "INTENT.md"
fake.write_text("---\nlayer: Engine\nrole: PIP\n"
"standard: net-kingdom/canon/standards/security-layer-model_v0.7.md\n---\n")
monkeypatch.setattr(checker, "INTENT", fake)
monkeypatch.setattr(sys, "argv", ["check_layer_conformance.py"])
try:
checker.main()
except SystemExit as exc:
assert exc.code == 2
else: # pragma: no cover
raise AssertionError("a versioned standard: path must fail")
out = capsys.readouterr()
assert checker.VALIDATED_AGAINST in out.out and "scope:" in out.out
assert "value carries a version" in out.err
def test_checker_rejects_a_divergence_that_survives_the_fold(tmp_path, monkeypatch):
spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
fake = tmp_path / "INTENT.md"
fake.write_text("---\nlayer: Staff\nrole: PIP\n---\n")
monkeypatch.setattr(module, "INTENT", fake)
try:
module.intent_frontmatter()
except SystemExit as exc:
assert exc.code == 2
else: # pragma: no cover
raise AssertionError("a Staff INTENT.md must not pass as Engine")
def test_checker_passes_on_the_real_tree():
result = _run()
assert result.returncode == 0, result.stderr + result.stdout
def test_checker_catches_an_undeclared_openbao_client(tmp_path, monkeypatch):
spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
fake_src = tmp_path / "src" / "tenant_engine"
fake_src.mkdir(parents=True)
(fake_src / "vault.py").write_text("import hvac\n")
monkeypatch.setattr(module, "SRC", fake_src)
hits = module.scan()
assert hits
assert any(h[1] == "hvac" for h in hits)
def test_published_stance_equals_shipped_behaviour():
assert published_stance() == shipped_stance()
assert set(shipped_stance()) == {"unset", "unreachable", "non_allow", "unknown"}
assert set(shipped_stance().values()) == {"fail_closed"}
def test_accepted_v08_run_provenance_and_catalog_scope():
checker = _checker()
assert "security-layer-model_v0.8.md" in checker.VALIDATED_AGAINST
assert "sha256:3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b" in checker.VALIDATED_AGAINST
assert "single repository tenant-engine (catalogued in §4)" in checker.SCOPE
def test_reference_semantics_propagate_identity_through_nested_sequences():
checker = _checker()
for data in (
{"nested": {"standard": ["Security Layer Model v0.8"]}},
{"companion": [["Security Companion 0.3"]]},
{"standard": {"alternate": ["Security Layer Model v0.7"]}},
):
# A dictionary begins a fresh identity key; only sequence descendants
# inherit the immediate standard:/companion: identity in the reference.
if isinstance(data.get("standard"), dict):
assert checker.find_version_pins(data) == []
else:
assert checker.find_version_pins(data), data
assert checker.find_version_pins({"rationale": "Assented at v0.7; migrated at v0.8."}) == []
assert checker.find_version_pins({"intent_version": "0.2.0", "schema_version": "0.1"}) == []
def test_ascii_folding_never_discards_non_ascii_letters():
checker = _checker()
assert checker._fold("Staff") == "staff"
assert checker._fold("Engine") == "engine"
# Deleting non-ASCII bytes would turn this fifth token into Staff.
assert checker._fold("Stαaff") not in checker.LAYER_VOCABULARY