Declare Engine/Lifecycle against security layer model v0.7
Replace the gate-house review note with this repository's own declaration: INTENT.md frontmatter, layer.yaml, and a published PEP stance map. SCOPE.md and agent boundary docs now match that layer. The review under history/ identifies the implementation remainder; SECRETS-WP-0008 is the follow-on workplan. SECRETS-IN-0001 is closed. The layer is not contested. Catalog "custody" is a finding: OpenBao owns custody, this engine owns the lifecycle API over it. SSH-CA signing is accepted as a proposed engine API and declined as a Staff lane. Assistant: grok Assistant-Session: 01a04cea-cb33-7c63-bad7-c1b0f9f0076b
This commit is contained in:
parent
b1f0f7b666
commit
1945e16685
14 changed files with 1177 additions and 108 deletions
178
scripts/check_layer_conformance.py
Normal file
178
scripts/check_layer_conformance.py
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Check secrets-engine against the NetKingdom security layer model (§3.3, §6, §11).
|
||||
|
||||
Read-only. This is the Engine/Lifecycle adaptation of the ops-warden reference
|
||||
checker. §5 Staff shapes do not apply to the owned OpenBao contact.
|
||||
|
||||
Mechanical checks:
|
||||
|
||||
- a machine-readable declaration exists and says Engine / Lifecycle
|
||||
- INTENT.md frontmatter matches that declaration
|
||||
- no authorization decision surface is exposed
|
||||
- the PEP stance map is published at the path named in the declaration
|
||||
- every OpenBao subprocess adapter lives in a module listed as owned tooling
|
||||
|
||||
Exit 0 clean, 1 finding, 2 declaration malformed.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SRC = ROOT / "src" / "secrets_engine"
|
||||
DECL = ROOT / "layer.yaml"
|
||||
INTENT = ROOT / "INTENT.md"
|
||||
|
||||
BAO_ARGV = re.compile(
|
||||
r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b|self\.bao_bin)\s*,"""
|
||||
)
|
||||
DECISION_SURFACE = re.compile(
|
||||
r"""\b(evaluate_policy|check_permission|render_decision|pdp_decide)\b"""
|
||||
)
|
||||
|
||||
|
||||
def load_declaration() -> dict:
|
||||
if not DECL.exists():
|
||||
print(f"MISSING: {DECL} — secrets-engine must declare in its own voice (§11)")
|
||||
raise SystemExit(2)
|
||||
decl = yaml.safe_load(DECL.read_text())
|
||||
for key in (
|
||||
"layer",
|
||||
"role",
|
||||
"repository",
|
||||
"standard_version",
|
||||
"owned_tooling",
|
||||
"decision_surfaces_exposed",
|
||||
"pep_shaped",
|
||||
"pep_stance",
|
||||
):
|
||||
if key not in decl:
|
||||
print(f"MALFORMED: layer.yaml has no {key!r}")
|
||||
raise SystemExit(2)
|
||||
if decl["layer"] != "engine":
|
||||
print(f"MALFORMED: declared layer is {decl['layer']!r}, expected 'engine'")
|
||||
raise SystemExit(2)
|
||||
if decl["role"] != "lifecycle":
|
||||
print(f"MALFORMED: declared role is {decl['role']!r}, expected 'lifecycle'")
|
||||
raise SystemExit(2)
|
||||
if decl["repository"] != "secrets-engine":
|
||||
print(f"MALFORMED: repository is {decl['repository']!r}")
|
||||
raise SystemExit(2)
|
||||
return decl
|
||||
|
||||
|
||||
def intent_frontmatter() -> dict:
|
||||
text = INTENT.read_text(encoding="utf-8")
|
||||
if not text.startswith("---"):
|
||||
print("MALFORMED: INTENT.md has no YAML frontmatter (§11 / companion §2)")
|
||||
raise SystemExit(2)
|
||||
end = text.find("\n---", 3)
|
||||
if end < 0:
|
||||
print("MALFORMED: INTENT.md frontmatter is unclosed")
|
||||
raise SystemExit(2)
|
||||
return yaml.safe_load(text[3:end]) or {}
|
||||
|
||||
|
||||
def owned_modules(decl: dict) -> set[str]:
|
||||
names: set[str] = set()
|
||||
for entry in decl.get("owned_tooling", []):
|
||||
for module in entry.get("modules", []):
|
||||
names.add(Path(module).name)
|
||||
return names
|
||||
|
||||
|
||||
def scan_bao_modules() -> dict[str, list[int]]:
|
||||
found: dict[str, list[int]] = {}
|
||||
for path in sorted(SRC.rglob("*.py")):
|
||||
hits: list[int] = []
|
||||
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("#"):
|
||||
continue
|
||||
if BAO_ARGV.search(line):
|
||||
hits.append(n)
|
||||
if hits:
|
||||
found[path.name] = hits
|
||||
return found
|
||||
|
||||
|
||||
def scan_decision_surfaces() -> dict[str, list[int]]:
|
||||
found: dict[str, list[int]] = {}
|
||||
for path in sorted(SRC.rglob("*.py")):
|
||||
hits: list[int] = []
|
||||
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
||||
if DECISION_SURFACE.search(line):
|
||||
hits.append(n)
|
||||
if hits:
|
||||
found[path.name] = hits
|
||||
return found
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--report", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
decl = load_declaration()
|
||||
front = intent_frontmatter()
|
||||
ok = True
|
||||
|
||||
if str(front.get("layer", "")).lower() != "engine":
|
||||
ok = False
|
||||
print("FINDING: INTENT.md frontmatter layer is not Engine")
|
||||
if str(front.get("role", "")).lower() != "lifecycle":
|
||||
ok = False
|
||||
print("FINDING: INTENT.md frontmatter role is not Lifecycle")
|
||||
|
||||
if decl["decision_surfaces_exposed"] not in {None, "none"}:
|
||||
ok = False
|
||||
print("FINDING: decision_surfaces_exposed is not none — §6 forbids a second PDP")
|
||||
|
||||
surfaces = scan_decision_surfaces()
|
||||
if surfaces:
|
||||
ok = False
|
||||
print("FINDING: possible authorization decision surface in source:")
|
||||
for name, lines in sorted(surfaces.items()):
|
||||
print(f" src/secrets_engine/{name}: line(s) {', '.join(map(str, lines[:6]))}")
|
||||
|
||||
stance = ROOT / str(decl["pep_stance"])
|
||||
if decl.get("pep_shaped") and not stance.is_file():
|
||||
ok = False
|
||||
print(f"FINDING: pep_shaped but {decl['pep_stance']} is missing (§6.4 / §13.1)")
|
||||
|
||||
found = scan_bao_modules()
|
||||
owned = owned_modules(decl)
|
||||
undeclared = {name: lines for name, lines in found.items() if name not in owned}
|
||||
if undeclared:
|
||||
ok = False
|
||||
print("FINDING: OpenBao adapter outside owned_tooling modules:")
|
||||
for name, lines in sorted(undeclared.items()):
|
||||
print(f" src/secrets_engine/{name}: line(s) {', '.join(map(str, lines[:6]))}")
|
||||
|
||||
if args.report:
|
||||
print(
|
||||
f"{decl['repository']} — layer: {decl['layer']} "
|
||||
f"role: {decl['role']} (model v{decl['standard_version']})"
|
||||
)
|
||||
print(f"declared by {decl['declared_by']}")
|
||||
print(f"pep stance: {decl['pep_stance']}")
|
||||
print(f"owned OpenBao modules: {sorted(owned)}")
|
||||
print(f"OpenBao argv adapters found: {sorted(found)}")
|
||||
|
||||
if ok and not args.report:
|
||||
print(
|
||||
"PASS — Engine/Lifecycle declaration present, no decision surface, "
|
||||
f"{len(found)} OpenBao adapter module(s) owned."
|
||||
)
|
||||
elif ok:
|
||||
print("\nPASS — declaration, owned tooling, and PEP stance path hold.")
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue