ops-warden/scripts/check_layer_conformance.py
tegwick 39791526a0
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Apply GH-DEC-2026-021: identity-value pins, prose citations not reached.
The playbook detector is the estate reference (021 §3). Add its one
addition to the reference and the checker: any v?N.N in a standard: or
companion: value is a pin. The prose-citation note moves from pending to
not reached (021 §1, A12 r3), and intent_version is noted as a key that
must not be flagged. VALIDATED_AGAINST keeps accepted v0.7 and adds
GH-DEC-2026-021 at gate-house@39d9287.

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 13:05:24 +02:00

343 lines
16 KiB
Python

#!/usr/bin/env python3
"""Check ops-warden against the NetKingdom security layer model (§5, §11).
Read-only. Two declaration forms are read, and the precedence between them is
`GH-DEC-2026-017` §1 (amendment A11): **INTENT.md's frontmatter governs** and
`layer.yaml` is a derived artifact that must be marked derived, must name
INTENT.md as its source, and must agree with it. The sidecar is read anyway,
because a disagreement between the two is itself a finding and is reported
rather than resolved away by precedence.
Comparison against §3's closed four-token vocabulary ASCII-folds case before
comparing (`GH-DEC-2026-017` §2, amendment A9): two spellings of a token do not
describe two boundaries, and a check that reports findings about capital letters
buries the one real disagreement it exists to find.
Neither form carries a version of the standard or of its companion, in any key
or value (`GH-DEC-2026-017` §5, amendment A12 as refined by A12 r2 /
`GH-DEC-2026-020` §1-§2). The rule reaches content, not a key name: a
`standard_version` key, a `companion_version` key, and a version-bearing path
such as `standard: .../security-layer-model_v0.7.md` are the same pin. Comments
and a file's own `schema_version` are not reached. Stance, claims and
evidence-classification maps (`pep-stance.yaml`) are NOT declarations and this
check does not read them (`GH-DEC-2026-020` §3).
The version belongs to the run (`GH-DEC-2026-020` §4): every run prints
VALIDATED_AGAINST and SCOPE below, including the PASS line, following
kings-guard's pattern. A retained copy of this output is a derived artifact
whose version is owed by whoever retains it.
Makes §11's second mechanical check real:
every direct Tooling client in a Staff repository maps to a declared
§5.1, §5.2, or §5.3 entry
The failure this catches is a *new* direct OpenBao contact appearing in
src/warden/ without an entry in layer.yaml — an undeclared violation (§11),
which is a finding rather than a tracked gap. It deliberately does NOT check
the review dates: a date-triggered failure breaks the build on a calendar day
with no code change (the reasoning recorded in WARDEN-WP-0033-T05), so
staleness is reported and left to `--report`, never to CI.
Exit 0 clean, 1 undeclared contact found, 2 declaration malformed.
"""
from __future__ import annotations
import argparse
import re
import sys
from datetime import date
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src" / "warden"
INTENT = ROOT / "INTENT.md"
DECL = ROOT / "layer.yaml"
VALID_SHAPES = {"5.1", "5.2", "5.3"}
# What every run checks against, printed on every run (GH-DEC-2026-020 §4,
# GH-DEC-2026-021 §2). The accepted text is v0.7 at net-kingdom@66dc491; the
# decision records whose rulings this checker enforces beyond v0.7 are named with it.
VALIDATED_AGAINST = (
"net-kingdom/canon/standards/security-layer-model_v0.7.md (net-kingdom@66dc491) "
"as amended by GH-DEC-2026-017, GH-DEC-2026-020 and GH-DEC-2026-021 "
"(A9-A13, A12 r3; gate-house@39d9287)"
)
# What every run ranges over. pep-stance.yaml is deliberately outside it.
SCOPE = "INTENT.md frontmatter, layer.yaml, src/warden/**/*.py"
# A12 r2: a version of the standard or companion in any key or value of the
# declaration. Keys: anything naming a standard/companion version. Values: a
# versioned file name or path (`_v0.7`, `-v0.8.md`) or a bare version string on a
# version-named key. `schema_version` is the file's own schema, not reached.
# GH-DEC-2026-021 §1/§3 (A12 r3): a version is reached only as a pin. Any version
# token (`v?N.N`) in the value of an identity-bearing key (`standard:`,
# `companion:`) is a pin; a revision cited in other prose is provenance and is not
# reached. Keys such as `intent_version` name neither and are not flagged.
VERSION_KEY = re.compile(r"(standard|companion).*version|version.*(standard|companion)", re.I)
VERSION_IN_VALUE = re.compile(r"[_\-.]v\d+(\.\d+)*(\.md)?\b|@v?\d+\.\d+", re.I)
NOT_REACHED_KEYS = {"schema_version"}
IDENTITY_KEYS = {"standard", "companion"}
IDENTITY_VERSION = re.compile(r"\bv?\d+\.\d+", re.I)
def find_version_pins(node, where: str = "", identity: bool = False) -> list[str]:
"""Every place in a parsed declaration that carries a standard/companion version.
Walks every key and value (comments are gone after parsing, which is the
A12 r2 exclusion). Returns human-readable locations; empty means clean.
"""
pins: list[str] = []
if isinstance(node, dict):
for k, v in node.items():
here = f"{where}.{k}" if where else str(k)
if str(k) in NOT_REACHED_KEYS:
continue
if VERSION_KEY.search(str(k)):
pins.append(f"{here} (key names a standard/companion version)")
continue
pins.extend(find_version_pins(v, here, str(k).lower() in IDENTITY_KEYS))
elif isinstance(node, list):
for i, v in enumerate(node):
pins.extend(find_version_pins(v, f"{where}[{i}]", identity))
elif isinstance(node, str) and VERSION_IN_VALUE.search(node):
pins.append(f"{where} = {node!r} (value carries a version)")
elif isinstance(node, str) and identity and IDENTITY_VERSION.search(node):
pins.append(f"{where} = {node!r} (identity-bearing value carries a version)")
return pins
def _reject_version_pins(label: str, node) -> None:
pins = find_version_pins(node)
if pins:
print(
f"MALFORMED: {label} carries a standard/companion version — a layer "
"declaration MUST NOT, in any key or value (§11 as amended by A12 r2, "
"GH-DEC-2026-020 §1-§2):"
)
for p in pins:
print(f" {p}")
raise SystemExit(2)
# §3's vocabulary, closed, four tokens (GH-DEC-2026-017 §3, amendment A9). The
# canonical spellings are §4's catalog-column forms; comparison is ASCII
# case-insensitive, so the fold is what is stored and `Taxonomy` is in the set —
# omitting it is the defect A9 records against the estate's other validator.
LAYER_VOCABULARY = {"taxonomy", "tooling", "engine", "staff"}
def _fold(value: str) -> str:
"""ASCII case-fold, per §3 as amended: two spellings of a token are one token."""
return str(value).strip().encode("ascii", "ignore").decode().lower()
def load_governing_layer() -> str:
"""The declaration is INTENT.md's frontmatter `layer:` key (§11, GH-DEC-2026-017 §1).
layer.yaml is derived and does not govern. Read without a YAML frontmatter
dependency: the file is read by humans first and a parser second.
"""
if not INTENT.exists():
print(f"MISSING: {INTENT} — §11's governing declaration form")
raise SystemExit(2)
lines = INTENT.read_text().splitlines()
if not lines or lines[0].strip() != "---":
print("MALFORMED: INTENT.md has no frontmatter to carry the declaration (§11)")
raise SystemExit(2)
end = next((i for i, ln in enumerate(lines[1:], 1) if ln.strip() == "---"), None)
if end is None:
print("MALFORMED: INTENT.md frontmatter is not terminated")
raise SystemExit(2)
front = yaml.safe_load("\n".join(lines[1:end])) or {}
if "layer" not in front:
print("MALFORMED: INTENT.md frontmatter has no 'layer' key — §11's declaration")
raise SystemExit(2)
_reject_version_pins("INTENT.md frontmatter", front)
layer = front["layer"]
if _fold(layer) not in LAYER_VOCABULARY:
print(
f"MALFORMED: INTENT.md declares layer {layer!r}, outside §3's closed "
f"vocabulary {sorted(LAYER_VOCABULARY)} (case-insensitive)"
)
raise SystemExit(2)
return layer
# A direct Tooling contact is an *invocation*, not a mention. Matching the word
# "bao" caught help text, a docstring, and the dev-tier doubles library that
# simulates bao rather than calling it — three false positives on first run.
# So match the two shapes that actually execute:
# 1. an HTTP request built against the OpenBao address
# 2. an argv list whose first element is the bao binary
TOOLING_PATTERNS = (
# httpx call whose URL is built from the configured OpenBao/Vault address
re.compile(r"""\bhttpx\.\w+\(|url\s*=\s*f?["'].*\{self\._cfg\.addr\}"""),
# argv construction: [bao_bin, ...] / ["bao", ...] / [bao_binary, ...]
re.compile(r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b)\s*,"""),
)
# httpx alone is not a Tooling contact — policy.py calls an Engine and worker.py
# calls the State Hub. A module matching only the httpx pattern counts as a
# contact only if it also references the OpenBao address configuration.
ADDR_HINT = re.compile(r"""_cfg\.addr|VAULT_ADDR|BAO_ADDR""")
# Modules that talk to an Engine or to something outside the §4 catalog. Listed
# in layer.yaml under non_tooling_clients and excluded from the scan with it.
def _excluded(decl: dict) -> set[str]:
return {e["module"].split("/")[-1] for e in decl.get("non_tooling_clients", [])}
def load_declaration() -> dict:
if not DECL.exists():
print(f"MISSING: {DECL} — ops-warden must declare in its own voice (§11)")
raise SystemExit(2)
decl = yaml.safe_load(DECL.read_text())
for key in ("layer", "repository", "derived", "derived_from", "tooling_contacts"):
if key not in decl:
print(f"MALFORMED: layer.yaml has no {key!r}")
raise SystemExit(2)
# §11's derived-artifact rule: marked as derived, naming what it derives from.
if decl["derived"] is not True:
print("MALFORMED: layer.yaml must be marked 'derived: true' (§11, GH-DEC-2026-017 §1)")
raise SystemExit(2)
if decl["derived_from"] != "INTENT.md":
print(
f"MALFORMED: layer.yaml derives from {decl['derived_from']!r}; §11 names "
"INTENT.md as the governing declaration"
)
raise SystemExit(2)
# A12: the version has no home in a declaration, governing or derived.
_reject_version_pins("layer.yaml", decl)
if _fold(decl["layer"]) not in LAYER_VOCABULARY:
print(
f"MALFORMED: layer.yaml declares layer {decl['layer']!r}, outside §3's "
f"closed vocabulary {sorted(LAYER_VOCABULARY)} (case-insensitive)"
)
raise SystemExit(2)
for c in decl["tooling_contacts"]:
if c.get("shape") not in VALID_SHAPES:
print(f"MALFORMED: {c.get('id')} has shape {c.get('shape')!r}, not one of {sorted(VALID_SHAPES)}")
raise SystemExit(2)
# §5.3 carries four fields, machine-readably. That is the whole point of
# the shape; a gap missing them is prose wearing a schema.
if c["shape"] == "5.3":
for field in ("capability", "intended_owner", "blocked_on", "review"):
if not c.get(field):
print(f"MALFORMED: §5.3 entry {c['id']!r} is missing {field!r}")
raise SystemExit(2)
# §5.2's test is the supplied-authority property.
if c["shape"] == "5.2" and c.get("supplied_authority") != "none":
print(f"MALFORMED: §5.2 conduit {c['id']!r} must declare supplied_authority: none")
raise SystemExit(2)
return decl
def scan_modules() -> dict[str, list[int]]:
"""Return {module_name: [line numbers]} for direct Tooling contacts."""
found: dict[str, list[int]] = {}
for path in sorted(SRC.rglob("*.py")):
if path.name.startswith("test_"):
continue
text = path.read_text()
hits: list[int] = []
for n, line in enumerate(text.splitlines(), 1):
stripped = line.strip()
if stripped.startswith("#") or stripped.startswith('"'):
continue
if any(p.search(line) for p in TOOLING_PATTERNS):
hits.append(n)
if hits:
# An httpx-only match needs the OpenBao address to be a Tooling
# contact; otherwise it is an Engine or non-catalogued call.
argv_shape = any(TOOLING_PATTERNS[1].search(ln) for ln in text.splitlines())
if argv_shape or ADDR_HINT.search(text):
found[path.name] = hits
return found
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--report", action="store_true", help="also print the declaration and gap review dates")
args = ap.parse_args()
# Printed before anything can fail, so even a MALFORMED run states what it
# checked against and over what (GH-DEC-2026-020 §4).
print(f"validated against: {VALIDATED_AGAINST}")
print(f"scope: {SCOPE}")
governing = load_governing_layer()
decl = load_declaration()
declared = {c["module"].split("/")[-1] for c in decl["tooling_contacts"]}
excluded = _excluded(decl)
found = scan_modules()
undeclared = {m: lines for m, lines in found.items() if m not in declared and m not in excluded}
# A voluntary declaration has no fixed argv shape to detect (an
# operator-configured command). Over-declaring is safe; not reporting it as
# stale keeps the signal meaningful.
voluntary = {
c["module"].split("/")[-1]
for c in decl["tooling_contacts"]
if c.get("detection") == "voluntary"
}
stale_decls = declared - set(found) - voluntary
if args.report:
print(f"{decl['repository']} — layer: {governing} (declared in INTENT.md; §11 governing form)")
print(f" layer.yaml: derived from {decl['derived_from']}, layer: {decl['layer']}")
print(f"declared by {decl['declared_by']}\n")
for c in decl["tooling_contacts"]:
line = f" §{c['shape']} {c['id']:<28} {c['module']}"
if c["shape"] == "5.3":
overdue = str(c["review"]) < date.today().isoformat()
line += f" -> {c['intended_owner']} review {c['review']}"
if overdue:
line += " [REVIEW OVERDUE]"
print(line)
gaps = [c for c in decl["tooling_contacts"] if c["shape"] == "5.3"]
print(f"\n{len(gaps)} declared gap(s) — tracked non-conformance, not conformance (§11).")
ok = True
# §11 as amended (A11): the derived form MUST agree with the governing one,
# and a disagreement is a finding in its own right — reported, not resolved
# away by precedence. Comparison folds case (A9): `Staff` and `staff` agree.
if _fold(decl["layer"]) != _fold(governing):
ok = False
print(
"\nDECLARATION DISAGREEMENT — a finding under §11, not a precedence question:\n"
f" INTENT.md (governs): layer: {governing}\n"
f" layer.yaml (derived): layer: {decl['layer']}\n"
"Precedence says which value is ops-warden's answer. It does not say the\n"
"disagreement did not happen. Case is already folded, so this is a real\n"
"disagreement about a layer, not about orthography."
)
if undeclared:
ok = False
print("\nUNDECLARED TOOLING CONTACT — a finding under §11, not a tracked gap:")
for m, lines in sorted(undeclared.items()):
print(f" src/warden/{m}: line(s) {', '.join(map(str, lines[:6]))}")
print("\nAdd a §5.1/§5.2/§5.3 entry to layer.yaml, or route it through an engine.")
if stale_decls:
print("\nNote: declared but no contact found (module removed or refactored?):")
for m in sorted(stale_decls):
print(f" {m}")
if ok and not args.report:
print(
f"PASS — {len(found)} module(s) with Tooling contact, all declared; "
f"validated against {VALIDATED_AGAINST}"
)
elif ok:
print(
"\nPASS — every direct Tooling contact maps to a declared shape; "
f"validated against {VALIDATED_AGAINST}"
)
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())