The standard moved v0.4 -> v0.6. All four findings from our v0.4 review were adopted in v0.5, and v0.6 went further on two of them. §11 now requires a machine-readable declaration — prose cannot distinguish a declaration from a transcribed review. We had none. Added layer.yaml (form adapted from ops-warden's reference implementation), scripts/check_layer_conformance.py, and tests/test_layer_conformance.py. The check makes our central claim mechanical rather than asserted: no direct Tooling client in src/. The test exercises the negative case on a synthetic tree, so it fails if the checker goes blind. pyyaml is added as a DEV dependency only — `dependencies = []` is load-bearing for the §5 claim and stays empty. Adopted from v0.6: - containment is no longer ours (§9.2). Actuation is an Engine concept, unowned and held at zero; kings-guard proposes containment and never performs it. The register row is now a dependency, not our gap. - observation is scoped to Staff-reachable sources, with identity and secret observation pending — our finding 1, adopted near-verbatim. - access-engine DECLINED the authentication-evidence gap; owner is now the identity layer plus audit-core, reproposed and unassented. - §11 blocked-clean recorded, with the rule that it must not rank below conforming — our finding 2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEtvmYUBP2fDtirJGWn5MW Assistant: claude-code Assistant-Model: opus Assistant-Process: 4014379@bnt-lap001 Assistant-Session: 4af9e20f-1768-4afc-951b-b507784e382b
88 lines
3.2 KiB
Python
88 lines
3.2 KiB
Python
"""kings-guard's layer declaration is checkable, not merely asserted (§11).
|
|
|
|
The claim under test is the one our whole position rests on: no direct
|
|
Tooling-layer client. A test that only ran the checker against a clean tree
|
|
would prove nothing — it would pass just as happily if the checker were broken.
|
|
So the negative case is exercised too, on a synthetic tree.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
yaml = pytest.importorskip("yaml")
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SCRIPT = ROOT / "scripts" / "check_layer_conformance.py"
|
|
DECL = ROOT / "layer.yaml"
|
|
|
|
|
|
def _run(*args: str) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.run(
|
|
[sys.executable, str(SCRIPT), *args],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
|
|
def test_declaration_exists_and_declares_staff():
|
|
"""§11: an estate-authored repository declares its layer machine-readably."""
|
|
assert DECL.exists(), "no layer.yaml — §11 requires a machine-readable declaration"
|
|
data = yaml.safe_load(DECL.read_text())
|
|
assert data["repository"] == "kings-guard"
|
|
assert data["layer"] == "staff"
|
|
assert data["framework"] == "netkingdom-security-layer-model"
|
|
|
|
|
|
def test_no_tooling_contacts_declared():
|
|
"""The blocked-clean position: nothing to declare, because nothing is touched."""
|
|
data = yaml.safe_load(DECL.read_text())
|
|
assert data["tooling_contacts"] == [], (
|
|
"a Tooling contact appeared in the declaration; kings-guard's blocked-clean "
|
|
"position under §11 no longer holds and KG-DEC-2026-001 needs revisiting"
|
|
)
|
|
for shape, entries in data["declared_shapes"].items():
|
|
assert entries == [], f"§5.{shape} shape declared; see comment above"
|
|
|
|
|
|
def test_unowned_capabilities_carry_the_gap_record_fields():
|
|
"""§5.3 field shape, reused for §13 unowned-capability rows (§17 gap-record)."""
|
|
data = yaml.safe_load(DECL.read_text())
|
|
caps = data["unowned_capabilities"]
|
|
assert caps, "the three known gaps should be declared"
|
|
for cap in caps:
|
|
for field in ("capability", "intended_owner", "blocked_on", "review", "state"):
|
|
assert cap.get(field), f"{cap.get('id')} missing '{field}'"
|
|
assert cap["state"] == "unowned-capability"
|
|
|
|
|
|
def test_checker_passes_on_the_real_tree():
|
|
result = _run()
|
|
assert result.returncode == 0, result.stderr
|
|
|
|
|
|
def test_checker_catches_an_undeclared_tooling_client(tmp_path, monkeypatch):
|
|
"""The negative case: a direct OpenBao client must fail the check.
|
|
|
|
This is the convenience §6 warns about — it would arrive as one import.
|
|
"""
|
|
import importlib.util
|
|
|
|
spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
fake_src = tmp_path / "src" / "kings_guard"
|
|
fake_src.mkdir(parents=True)
|
|
(fake_src / "effector.py").write_text(
|
|
"import hvac\n\n\ndef contain(actor):\n hvac.Client().revoke(actor)\n"
|
|
)
|
|
monkeypatch.setattr(module, "SRC", fake_src)
|
|
monkeypatch.setattr(module, "ROOT", tmp_path)
|
|
|
|
hits = module.scan()
|
|
assert hits, "a direct OpenBao client was not detected — the checker is blind"
|
|
assert hits[0][1] == "hvac"
|