scripts/check_layer_conformance.py now prints, on every run (success and failure), the standard text it checks against (VALIDATED_AGAINST: security-layer-model_v0.8.md @ net-kingdom f9e1611 with gate-house A9, A11, A12 r2 @ 104f3fc) and its scope. A12 detection widens from the key name standard_version to any *_version key (companion_version included), a versioned standard/companion path, or a bare vN.N token in any key or value of INTENT.md frontmatter or layer.yaml. schema_version and comments are not reached; pep-stance.yaml and pip-claims.yaml are not read for A12 and keep their version fields (GH-DEC-2026-020 §3). The widened check found one value the key-name check could not: the state-hub-work-records note in layer.yaml cited "the v0.7 scope rule". It is reworded to "the standard's scope rule"; no layer or role value changes. Tests fail if a versioned standard: path, a companion_version or a bare version token returns, and if a run stops stating its version and scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 63291@bnt-lap001 Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
178 lines
6.9 KiB
Python
178 lines
6.9 KiB
Python
"""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, "notes": [{"note": "Outside §5 by the v0.7 scope rule."}]},
|
|
]
|
|
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"
|
|
"ref: net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md\n")
|
|
assert checker.version_findings(data, "x") == []
|
|
|
|
|
|
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 "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"}
|