Converge layer checker on GH-DEC-2026-021.
VALIDATED_AGAINST names v0.7 at net-kingdom@66dc491 as amended by GH-DEC-2026-017/020/021 (gate-house@39d9287). The version detector adopts ops-warden's estate reference: identity-bearing standard:/companion: values carrying a version token are pins; keys naming neither are not reached. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 58902@bnt-lap001 Assistant-Session: 7ac7f865-2dc5-4aa7-8eb7-27a342109c2f
This commit is contained in:
parent
a7312baafc
commit
abd4bf1fd8
2 changed files with 33 additions and 10 deletions
|
|
@ -30,10 +30,14 @@ sys.path.insert(0, str(ROOT / "src"))
|
||||||
|
|
||||||
from user_engine.layer_yaml import load_mapping, load_mapping_text # noqa: E402
|
from user_engine.layer_yaml import load_mapping, load_mapping_text # noqa: E402
|
||||||
|
|
||||||
# The standard text this checker was built and validated against. The version
|
# What every run checks against, printed on every run (GH-DEC-2026-020 §4,
|
||||||
# belongs to the run, not to the declaration (GH-DEC-2026-020 §4, A12 r2); it is
|
# GH-DEC-2026-021 §2). The accepted text is v0.7 at net-kingdom@66dc491; the
|
||||||
# printed on every run. Bump it when the checker is re-validated.
|
# 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"
|
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. Stance, claims and classification maps
|
# What every run ranges over. Stance, claims and classification maps
|
||||||
# (pep-stance.yaml) are not declarations and are not checked for versions
|
# (pep-stance.yaml) are not declarations and are not checked for versions
|
||||||
|
|
@ -45,9 +49,15 @@ SCOPE = (
|
||||||
|
|
||||||
# A12 r2: no standard or companion version in any key or value of the
|
# A12 r2: no standard or companion version in any key or value of the
|
||||||
# declaration. Comments are not parsed; schema_version is not reached.
|
# declaration. Comments are not parsed; schema_version is not reached.
|
||||||
VERSION_KEY = re.compile(r"(?:^|_)version$", re.IGNORECASE)
|
# Detector converged on the estate reference, ops-warden's (GH-DEC-2026-021 §3):
|
||||||
VERSION_VALUE = re.compile(r"(?:^|[_\-/\s])v?\d+\.\d+(?:\.\d+)*(?:\.md)?(?=$|[\s/])|_v\d+", re.IGNORECASE)
|
# a version token (`v?N.N`) in an identity-bearing value (`standard:`,
|
||||||
|
# `companion:`) is a pin (A12 r3); keys naming neither, e.g. `intent_version`,
|
||||||
|
# are not reached.
|
||||||
|
VERSION_KEY = re.compile(r"(standard|companion).*version|version.*(standard|companion)", re.I)
|
||||||
|
VERSION_VALUE = re.compile(r"[_\-.]v\d+(\.\d+)*(\.md)?\b|@v?\d+\.\d+", re.I)
|
||||||
UNREACHED_KEYS = {"schema_version"}
|
UNREACHED_KEYS = {"schema_version"}
|
||||||
|
IDENTITY_KEYS = {"standard", "companion"}
|
||||||
|
IDENTITY_VERSION = re.compile(r"\bv?\d+\.\d+", re.I)
|
||||||
|
|
||||||
TOOLING_IMPORTS = {
|
TOOLING_IMPORTS = {
|
||||||
"hvac": "OpenBao / Vault client",
|
"hvac": "OpenBao / Vault client",
|
||||||
|
|
@ -81,7 +91,9 @@ def fold(value: object) -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def find_versions(node: object, where: str, path: str = "") -> list[str]:
|
def find_versions(
|
||||||
|
node: object, where: str, path: str = "", identity: bool = False
|
||||||
|
) -> list[str]:
|
||||||
"""Every key or value in a declaration that carries a version (A12 r2)."""
|
"""Every key or value in a declaration that carries a version (A12 r2)."""
|
||||||
found: list[str] = []
|
found: list[str] = []
|
||||||
if isinstance(node, dict):
|
if isinstance(node, dict):
|
||||||
|
|
@ -92,12 +104,14 @@ def find_versions(node: object, where: str, path: str = "") -> list[str]:
|
||||||
if VERSION_KEY.search(str(key)):
|
if VERSION_KEY.search(str(key)):
|
||||||
found.append(f"{where}: key '{here}'")
|
found.append(f"{where}: key '{here}'")
|
||||||
continue
|
continue
|
||||||
found.extend(find_versions(value, where, here))
|
found.extend(find_versions(value, where, here, str(key).lower() in IDENTITY_KEYS))
|
||||||
elif isinstance(node, list):
|
elif isinstance(node, list):
|
||||||
for index, item in enumerate(node):
|
for index, item in enumerate(node):
|
||||||
found.extend(find_versions(item, where, f"{path}[{index}]"))
|
found.extend(find_versions(item, where, f"{path}[{index}]", identity))
|
||||||
elif isinstance(node, str) and VERSION_VALUE.search(node):
|
elif isinstance(node, str) and VERSION_VALUE.search(node):
|
||||||
found.append(f"{where}: value of '{path}' = {node!r}")
|
found.append(f"{where}: value of '{path}' = {node!r}")
|
||||||
|
elif isinstance(node, str) and identity and IDENTITY_VERSION.search(node):
|
||||||
|
found.append(f"{where}: identity-bearing value of '{path}' = {node!r}")
|
||||||
return found
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -106,7 +120,7 @@ def reject_versions(data: dict, where: str) -> None:
|
||||||
if found:
|
if found:
|
||||||
print(
|
print(
|
||||||
"FAIL: a layer declaration MUST NOT carry a standard or companion "
|
"FAIL: a layer declaration MUST NOT carry a standard or companion "
|
||||||
"version in any key or value (GH-DEC-2026-017 §5, GH-DEC-2026-020, A12 r2)",
|
"version in any key or value (GH-DEC-2026-017 §5, GH-DEC-2026-020, GH-DEC-2026-021, A12 r3)",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
for item in found:
|
for item in found:
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,15 @@ class LayerDeclarationTests(unittest.TestCase):
|
||||||
# pep-stance.yaml keeps its version fields (GH-DEC-2026-020 §3).
|
# pep-stance.yaml keeps its version fields (GH-DEC-2026-020 §3).
|
||||||
self.assertTrue(module.find_versions(load_mapping(STANCE_FILE), "stance"))
|
self.assertTrue(module.find_versions(load_mapping(STANCE_FILE), "stance"))
|
||||||
|
|
||||||
|
def test_version_scan_matches_estate_reference_detector(self):
|
||||||
|
# GH-DEC-2026-021 §3 (A12 r3): a version token in an identity-bearing
|
||||||
|
# value is a pin; a key naming neither standard nor companion is not.
|
||||||
|
module = _checker()
|
||||||
|
self.assertTrue(module.find_versions({"standard": "security-layer-model 0.7"}, "x"))
|
||||||
|
self.assertTrue(module.find_versions({"companion": ["SECURITY-COMPANION v0.2"]}, "x"))
|
||||||
|
self.assertEqual(module.find_versions({"intent_version": "0.3"}, "x"), [])
|
||||||
|
self.assertEqual(module.find_versions({"note": "revised 0.7 wording"}, "x"), [])
|
||||||
|
|
||||||
def test_every_run_prints_version_and_scope(self):
|
def test_every_run_prints_version_and_scope(self):
|
||||||
module = _checker()
|
module = _checker()
|
||||||
for argv in ([], ["--report"]):
|
for argv in ([], ["--report"]):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue