kings-guard/scripts/check_layer_conformance.py
tegwick 5120adf55a Apply GH-DEC-2026-017 to the layer declaration; close KG-IN-0007.
INTENT.md frontmatter governs and layer.yaml is marked derived from it.
standard_version is removed from both forms (A12). The checker and its
tests change in the same commit: they no longer require the field, they
reject it, they fold case against the four-token vocabulary (A9) instead
of comparing with plain equality, and they still fail a layer disagreement
that survives the fold (A11). Neither layer value is re-spelled.

The ruling answers kings-guard's "validated-against" reading of the field
(§5: version-scoped state belongs in the derived conformance record), so
that version now lives in the checker as VALIDATED_AGAINST and is printed
in every run's output. The standard: path in INTENT.md is unversioned to
match the reference form.

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
2026-09-21 07:35:40 +02:00

312 lines
13 KiB
Python

#!/usr/bin/env python3
"""Check kings-guard against the NetKingdom security layer model (§5, §11).
Read-only. kings-guard's whole position under the standard rests on one claim:
it holds no direct client for any Tooling-layer system, and the
capabilities that would need one sit at zero instead (§11 blocked-clean)
That claim has been asserted in prose since KG-DEC-2026-001. §11 (v0.7) requires
a machine-readable declaration because prose cannot distinguish a declaration
from a transcribed review. This script is what makes the claim checkable: it
fails if a Tooling client appears in src/ without a matching layer.yaml entry.
The failure it exists to catch is a *convenience* — someone reaching for an
OpenBao or cluster client during an incident because the engine surface still
does not exist (§9.2). That is precisely the "small convenience" §6 warns about,
and it would arrive as a one-line import.
Declaration form (GH-DEC-2026-017, amendments A9, A11, A12): INTENT.md's
frontmatter `layer:` key governs; layer.yaml is a derived artifact that must be
marked derived, name INTENT.md, and agree with it. Layer comparison ASCII-folds
case against §3's closed four-token vocabulary, so `Staff` and `staff` agree and
neither file is re-spelled. A disagreement that survives the fold is reported as
a finding, not resolved by precedence. Neither form may carry a
`standard_version`; the version this check was built and validated against is
the checker's own, VALIDATED_AGAINST below, and is printed in every run's output
— this script's output is the derived conformance record A12 points to.
Review dates are reported, never enforced: a date-triggered failure breaks the
build on a calendar day with no code change.
Exit 0 clean, 1 undeclared contact found or the two declaration forms disagree,
2 declaration malformed.
"""
from __future__ import annotations
import argparse
import ast
import re
import sys
from datetime import date
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src" / "kings_guard"
DECL = ROOT / "layer.yaml"
INTENT = ROOT / "INTENT.md"
# The standard text this checker was built and validated against. This is the
# derived conformance record's version (GH-DEC-2026-017 §5 / A12), moved here
# from layer.yaml's former `standard_version: "0.7"`, which recorded the same
# fact in a place the ruling says a declaration must not carry it. Bump it when
# the checker is re-validated against a newer accepted text.
VALIDATED_AGAINST = "net-kingdom/canon/standards/security-layer-model_v0.7.md"
# §3's closed layer vocabulary (A9): four tokens, compared ASCII case-insensitively.
LAYER_VOCABULARY = {"taxonomy", "tooling", "engine", "staff"}
EXPECTED_LAYER = "staff" # kings-guard's own §4 row, folded
# Import roots that would constitute a direct Tooling-layer client under §4.
# Matched against the top-level module of every import in src/.
TOOLING_IMPORTS = {
"hvac": "OpenBao / Vault client",
"bao": "OpenBao client",
"kubernetes": "cluster client",
"kubernetes_asyncio": "cluster client",
"psycopg": "direct database connection",
"psycopg2": "direct database connection",
"asyncpg": "direct database connection",
"sqlalchemy": "direct database connection",
"pymysql": "direct database connection",
"redis": "direct datastore connection",
"ldap3": "direct LDAP client (key-cape tooling)",
"python_ldap": "direct LDAP client (key-cape tooling)",
"docker": "container runtime client",
}
# §3.4 rule 1 — no standing credential held in the repository or its
# configuration. Filenames that would be a standing secret, and assignments
# of well-known secret env vars to string literals in src/.
CREDENTIAL_FILENAMES = {
".env",
".env.local",
".env.production",
"credentials.json",
"secrets.yaml",
"secrets.yml",
"id_rsa",
"id_ed25519",
"id_ecdsa",
}
CREDENTIAL_LITERAL = re.compile(
r"""(?x)
\b(?:VAULT_TOKEN|OPENBAO_TOKEN|BAO_TOKEN|AWS_SECRET_ACCESS_KEY|
PRIVATE_KEY|BEGIN\ (?:RSA\ )?PRIVATE\ KEY)
"""
)
SKIP_CREDENTIAL_SCAN_DIRS = {".git", ".venv", "__pycache__", ".pytest_cache", ".ruff_cache"}
def fold(value: object) -> str:
"""ASCII case-fold, per §3 as amended (A9): two spellings are one token."""
return str(value).encode("ascii", "replace").decode("ascii").lower()
def _malformed(message: str) -> None:
print(f"FAIL: {message}", file=sys.stderr)
raise SystemExit(2)
def load_governing_layer() -> str:
"""The declaration: INTENT.md frontmatter `layer:` (§11, GH-DEC-2026-017 §1)."""
if not INTENT.exists():
_malformed(f"no {INTENT.name} — §11's governing declaration form")
lines = INTENT.read_text().splitlines()
if not lines or lines[0].strip() != "---":
_malformed(f"{INTENT.name} has no frontmatter to carry the declaration (§11)")
try:
end = lines[1:].index("---") + 1
except ValueError:
_malformed(f"{INTENT.name} frontmatter is not terminated")
try:
front = yaml.safe_load("\n".join(lines[1:end])) or {}
except yaml.YAMLError as exc:
_malformed(f"{INTENT.name} frontmatter is not parseable: {exc}")
if "layer" not in front:
_malformed(f"{INTENT.name} frontmatter has no 'layer' key — §11's declaration")
if "standard_version" in front:
_malformed(
f"{INTENT.name} frontmatter carries 'standard_version' — a layer "
"declaration MUST NOT carry a standard version (§11 as amended by A12)"
)
layer = front["layer"]
if fold(layer) not in LAYER_VOCABULARY:
_malformed(
f"{INTENT.name} declares layer {layer!r}, outside §3's closed vocabulary "
f"{sorted(LAYER_VOCABULARY)} (case-insensitive)"
)
if fold(layer) != EXPECTED_LAYER:
_malformed(f"{INTENT.name} declares layer {layer!r}, expected Staff (§4 row)")
return str(layer)
def load_declaration() -> dict:
"""The derived form, layer.yaml (§11 derived-artifact rule)."""
if not DECL.exists():
_malformed(f"no declaration at {DECL.relative_to(ROOT)} (§11)")
try:
data = yaml.safe_load(DECL.read_text())
except yaml.YAMLError as exc:
print(f"FAIL: {DECL.name} is not parseable: {exc}", file=sys.stderr)
raise SystemExit(2) from exc
for key in ("layer", "repository", "tooling_contacts", "derived", "derived_from"):
if key not in data:
_malformed(f"{DECL.name} missing required key '{key}' (§11)")
if data["derived"] is not True:
_malformed(f"{DECL.name} must be marked 'derived: true' (§11, GH-DEC-2026-017 §1)")
if data["derived_from"] != "INTENT.md":
_malformed(
f"{DECL.name} derives from {data['derived_from']!r}; §11 names INTENT.md "
"as the governing declaration"
)
if "standard_version" in data:
_malformed(
f"{DECL.name} carries 'standard_version' — a layer declaration MUST NOT "
"carry a standard version (§11 as amended by A12)"
)
if fold(data["layer"]) not in LAYER_VOCABULARY:
_malformed(
f"{DECL.name} declares layer {data['layer']!r}, outside §3's closed "
f"vocabulary {sorted(LAYER_VOCABULARY)} (case-insensitive)"
)
return data
def forms_disagree(governing: object, derived: object) -> bool:
"""A11: the derived form must agree with INTENT.md, after the A9 case fold."""
return fold(governing) != fold(derived)
def imported_modules(path: Path) -> set[str]:
"""Top-level module name of every import in one file."""
try:
tree = ast.parse(path.read_text())
except SyntaxError:
return set()
found: set[str] = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
found.update(alias.name.split(".")[0] for alias in node.names)
elif isinstance(node, ast.ImportFrom):
if node.level == 0 and node.module:
found.add(node.module.split(".")[0])
return found
def scan() -> list[tuple[Path, str, str]]:
hits: list[tuple[Path, str, str]] = []
for path in sorted(SRC.rglob("*.py")):
for module in sorted(imported_modules(path)):
if module in TOOLING_IMPORTS:
hits.append((path, module, TOOLING_IMPORTS[module]))
return hits
def scan_standing_credentials() -> list[tuple[Path, str]]:
"""§3.4 rule 1: no standing credential in the repository or its config."""
hits: list[tuple[Path, str]] = []
for path in ROOT.rglob("*"):
if not path.is_file():
continue
if any(part in SKIP_CREDENTIAL_SCAN_DIRS for part in path.parts):
continue
if path.name in CREDENTIAL_FILENAMES:
hits.append((path, f"credential-shaped file {path.name}"))
continue
if path.suffix in {".pem", ".key"} and "test" not in path.parts:
hits.append((path, f"key material file {path.name}"))
if SRC.is_dir():
for path in sorted(SRC.rglob("*.py")):
text = path.read_text(encoding="utf-8")
if CREDENTIAL_LITERAL.search(text):
hits.append((path, "standing-credential literal or private-key block"))
return hits
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--report", action="store_true", help="print the declaration summary")
args = parser.parse_args()
governing = load_governing_layer()
decl = load_declaration()
declared = {c.get("id") for c in decl.get("tooling_contacts") or []}
hits = scan()
credential_hits = scan_standing_credentials()
undeclared = [h for h in hits if h[1] not in declared]
rules = decl.get("agent_principal_rules") or {}
checks = decl.get("agent_principal_rule_checks") or {}
if args.report:
print(f"kings-guard — layer: {governing} (declared in INTENT.md; §11 governing form)")
print(f" layer.yaml: derived from {decl['derived_from']}, layer: {decl['layer']}")
print(f" checker validated against: {VALIDATED_AGAINST}")
print(f" tooling contacts declared: {len(declared)}")
print(f" unowned capabilities (§11 blocked-clean): "
f"{len(decl.get('unowned_capabilities') or [])}")
today = date.today()
for cap in decl.get("unowned_capabilities") or []:
review = cap.get("review")
stale = ""
if review and date.fromisoformat(str(review)) < today:
stale = " [REVIEW OVERDUE]"
print(f" - {cap['id']}: {cap.get('owner_status', '?')}{stale}")
print(" agent-principal rule checks (§3.4):")
for name, meta in checks.items():
form = meta.get("form", "unspecified") if isinstance(meta, dict) else "unspecified"
print(f" - {name}: {form} (claimed={rules.get(name)})")
if forms_disagree(governing, decl["layer"]):
print("", file=sys.stderr)
print("FAIL: the two declaration forms disagree (§11, A11)", file=sys.stderr)
print(f" INTENT.md (governs): layer: {governing}", file=sys.stderr)
print(f" layer.yaml (derived): layer: {decl['layer']}", file=sys.stderr)
print(" Case is already folded, so this is a real layer disagreement.", file=sys.stderr)
print(" It is a finding in its own right; precedence does not erase it.", file=sys.stderr)
return 1
if undeclared:
print("", file=sys.stderr)
print("FAIL: undeclared Tooling-layer client (§11 undeclared violation)", file=sys.stderr)
for path, module, what in undeclared:
rel = path.relative_to(ROOT)
print(f" {rel}: imports '{module}'{what}", file=sys.stderr)
print("", file=sys.stderr)
print(" A Staff repository may not hold a direct Tooling client (§5).", file=sys.stderr)
print(" Route it through the owning engine, or if none exists, raise an", file=sys.stderr)
print(" engine gap — do not declare this to make the check pass.", file=sys.stderr)
return 1
if credential_hits:
print("", file=sys.stderr)
print("FAIL: standing credential material (§3.4 rule 1)", file=sys.stderr)
for path, what in credential_hits:
try:
rel = path.relative_to(ROOT)
except ValueError:
rel = path
print(f" {rel}: {what}", file=sys.stderr)
print("", file=sys.stderr)
print(" Authority is per task, time-bounded, and attributable to the", file=sys.stderr)
print(" principal acted for. Do not hold a standing secret here.", file=sys.stderr)
return 1
if rules.get("no_standing_credential") is not True:
print("FAIL: layer.yaml does not claim no_standing_credential (§3.4 rule 1)", file=sys.stderr)
return 2
if not args.report:
print(
f"OK: no direct Tooling client in {SRC.relative_to(ROOT)}; "
"no standing credential (§5, §11, §3.4 rule 1); "
f"declaration forms agree; validated against {VALIDATED_AGAINST}"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())