railiance-platform/tests/test_auth_role_watch_lane.py
codex 69530053ab
All checks were successful
CCR intake gate / gate (push) Successful in 2m13s
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
auth-role-presence-watch: dry-run policy_write carries source and body; approve state-hub summary tolerates non-KV CCRs
The founder's applier-dry-run of CCR-2026-0064 crashed (KeyError 'source') in render_applier_dry_run.
New test renders the dry run and the apply plan through the CLI. The --record-state-hub summary of
approve no longer assumes openbao.fields, which lane CCRs without a KV path do not have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
2026-11-06 10:20:04 +01:00

156 lines
7.1 KiB
Python

"""auth-role-presence-watch lane (CCR-2026-0064, net-kingdom NK-WP-0058-T06)."""
from __future__ import annotations
import copy
import importlib.util
import json
import os
import stat
import sys
import tempfile
import unittest
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
CCR_PATH = ROOT / "credential-change-requests/CCR-2026-0064-nk-bounded-executor-window-watch.yaml"
WATCHED = "auth/kubernetes/role/net-kingdom-bind-executor-svc-authelia-write"
def load(name: str, rel: str):
spec = importlib.util.spec_from_file_location(name, ROOT / rel)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
lane = load("auth_role_watch_lane", "scripts/auth_role_watch_lane.py")
cc = load("credential_change_cli_watch", "scripts/credential-change.py")
def ccr() -> dict:
return yaml.safe_load(CCR_PATH.read_text())
FAKE_BAO = r'''#!/usr/bin/env python3
import json, os, sys
path = os.environ["FAKE_BAO_STATE"]
state = json.load(open(path))
args = [a for a in sys.argv[1:] if a != "-format=json"]
state.setdefault("calls", []).append(args)
if args[:2] == ["auth", "list"]:
print(json.dumps({k: {"type": v} for k, v in state["mounts"].items()}))
elif args[:2] == ["policy", "write"]:
state["policies"][args[2]] = open(args[3]).read()
elif args[:2] == ["policy", "read"]:
if args[2] not in state["policies"]:
json.dump(state, open(path, "w")); sys.exit(2)
print(state["policies"][args[2]])
elif args[0] == "write":
role = json.load(open(args[2][1:]))
state["roles"][args[1]] = {k: (900 if v == "15m" else v) for k, v in role.items()}
elif args[0] == "read":
print(json.dumps({"data": state["roles"][args[1]]}))
json.dump(state, open(path, "w"))
'''
class AuthRoleWatchLaneTests(unittest.TestCase):
def test_ccr_validates_and_blocks_until_approved_and_bound(self):
_ccr, errors, _w = cc.validate_ccr(CCR_PATH)
self.assertEqual(errors, [])
draft = copy.deepcopy(_ccr) # independent of the file's live review state
draft.update(status="proposed")
draft["openbao"]["auth"]["bound_claims_confirmed"] = False
blockers = cc.applier_readiness_blockers(draft)
self.assertIn("applier requires confirmed OpenBao auth binding", blockers)
ready = copy.deepcopy(_ccr)
ready["status"] = "approved"
ready["openbao"]["auth"]["bound_claims_confirmed"] = True
self.assertEqual(cc.applier_readiness_blockers(ready), [])
def test_dry_run_and_apply_plan_render_through_the_cli(self):
"""2026-11-06: the founder's dry run crashed on a policy_write without source and body."""
ready = copy.deepcopy(ccr())
ready.update(status="approved")
ready["openbao"]["auth"]["bound_claims_confirmed"] = True
dry = cc.render_applier_dry_run(cc.applier_dry_run_payload(ready, []))
self.assertIn("policy_write: sys/policies/acl/net-kingdom-bounded-executor-window-watch", dry)
self.assertIn('path "%s" {' % WATCHED, dry)
self.assertIn("auth_role_write: auth/kubernetes/role/net-kingdom-bounded-executor-window-watch", dry)
self.assertIn("CCR-2026-0064", cc.render_applier_apply_plan(ready, []))
def test_flag_policy_is_one_read_and_self_lifecycle(self):
text = (ROOT / ccr()["openbao"]["policy_file"]).read_text()
paths = [line.split('"')[1] for line in text.splitlines() if line.startswith("path ")]
self.assertEqual(paths, [WATCHED, "auth/token/lookup-self", "auth/token/revoke-self"])
self.assertIn('path "%s" {\n capabilities = ["read"]\n}' % WATCHED, text)
self.assertNotIn("delete", text)
def test_close_mode_adds_only_delete_on_the_same_path(self):
c = ccr()
c["openbao"]["watch"]["mode"] = "close"
self.assertIn('path "%s" {\n capabilities = ["read", "delete"]\n}' % WATCHED, lane.generated_policy_hcl(c))
self.assertIn("openbao.policy_file differs from the policy generated from the CCR", lane.validate(c, ROOT))
def test_validator_rejects_widening(self):
cases = [
("unknown mode", lambda c: c["openbao"]["watch"].update(mode="admin")),
("other mount", lambda c: c["openbao"]["watch"].update(mount="netkingdom")),
("watch itself", lambda c: c["openbao"]["auth"].update(role=c["openbao"]["watch"]["role"])),
("long ttl", lambda c: c["openbao"]["auth"].update(ttl="1h")),
("default policy", lambda c: c["openbao"]["auth"].update(token_no_default_policy=False)),
("extra policy", lambda c: c["openbao"]["auth"]["policies"].append("platform-admin")),
("two accounts", lambda c: c["openbao"]["auth"]["bound_claims"]["service_account_names"].append("x")),
("extra claim", lambda c: c["openbao"]["auth"]["bound_claims"].update(other=["x"])),
("other audience", lambda c: c["openbao"]["auth"].update(audience="kubernetes")),
("staging", lambda c: c["target"].update(environment="staging")),
]
for label, mutate in cases:
with self.subTest(label):
c = ccr()
mutate(c)
self.assertNotEqual(lane.validate(c, ROOT), [], label)
def test_edited_policy_file_is_refused(self):
c = ccr()
with tempfile.TemporaryDirectory(dir=ROOT / "openbao/policies") as tmp:
edited = Path(tmp) / "p.hcl"
edited.write_text(lane.generated_policy_hcl(c) + 'path "platform/*" {\n capabilities = ["read"]\n}\n')
c["openbao"]["policy_name"] = "p"
c["openbao"]["policy_file"] = str(edited.relative_to(ROOT))
self.assertNotEqual(lane.validate(c, ROOT), [])
def _apply(self, mounts):
tmp = Path(tempfile.mkdtemp())
(tmp / "state.json").write_text(json.dumps({"mounts": mounts, "policies": {}, "roles": {}}))
bao = tmp / "bao"
bao.write_text(FAKE_BAO)
bao.chmod(bao.stat().st_mode | stat.S_IEXEC)
os.environ["FAKE_BAO_STATE"] = str(tmp / "state.json")
error = None
try:
lane.run_apply(ccr(), ROOT, str(bao), quiet=True)
except lane.BaoError as exc:
error = exc
return error, json.loads((tmp / "state.json").read_text())
def test_apply_writes_policy_and_role_and_reads_back(self):
error, state = self._apply({"kubernetes/": "kubernetes"})
self.assertIsNone(error)
role = state["roles"]["auth/kubernetes/role/net-kingdom-bounded-executor-window-watch"]
self.assertEqual(role["bound_service_account_names"], ["nk-window-watch"])
self.assertEqual(role["token_policies"], ["net-kingdom-bounded-executor-window-watch"])
self.assertEqual(set(state["policies"]), {"net-kingdom-bounded-executor-window-watch"})
self.assertNotIn(WATCHED, state["roles"]) # the watched role is never written here
def test_apply_refuses_without_the_kubernetes_mount(self):
error, state = self._apply({})
self.assertIsNotNone(error)
self.assertEqual(state["policies"], {})
if __name__ == "__main__":
unittest.main()