feat: add auth-capability lanes and pilot closeout

Add the warden-sign auth-capability lane, AppRole handoff, verification guards, docs, and tests.

Point the whynot-design pilot at the canonical decision and add the real publish closeout preflight/runbook.
This commit is contained in:
tegwick 2026-06-29 16:58:16 +02:00
parent a621fbaffd
commit 6382139890
27 changed files with 1455 additions and 107 deletions

View file

@ -19,6 +19,7 @@ from secrets_engine.openbao import OpenBaoClient
@dataclass
class RouteResult:
catalog_id: str
kind: str
owner: str
stage: str
decision_status: str
@ -59,13 +60,20 @@ def route_lane(
metadata_applied = False
value_present = False
if client is not None and client.is_reachable():
metadata_applied = client.read_policy(entry.policy_name) is not None
# Presence check uses the engine's own token; reports boolean only.
field = entry.fields[0] if entry.fields else ""
if field:
value_present = client.kv_field_present(entry.mount, entry.path, field)
policy_applied = client.read_policy(entry.policy_name) is not None
role_applied = client.approle_exists(entry.role_name)
metadata_applied = policy_applied and role_applied
if entry.stores_kv_value():
# Presence check uses the engine's own token; reports boolean only.
field = entry.fields[0] if entry.fields else ""
if field:
value_present = client.kv_field_present(entry.mount, entry.path, field)
else:
# Auth-capability lanes have no stored value; a fresh secret_id is minted
# on demand through the handoff command once metadata exists.
value_present = metadata_applied
approved = decision is None or decision.is_approved()
approved = not entry.approval_required() or (decision is not None and decision.is_approved())
ready = approved and metadata_applied and value_present
if not approved:
@ -74,6 +82,12 @@ def route_lane(
elif not metadata_applied:
missing = "OpenBao policy/role apply"
next_command = f"secrets-engine apply {decision_ref or entry.id} --stage {entry.stage}"
elif entry.kind == "auth-capability":
missing = ""
next_command = (
f"secrets-engine handoff {entry.id} --stage {entry.stage} "
"--role-id-file <path> --secret-id-file <path>"
)
elif not value_present:
missing = "provisioned secret value"
next_command = (
@ -86,6 +100,7 @@ def route_lane(
return RouteResult(
catalog_id=entry.id,
kind=entry.kind,
owner=entry.owner,
stage=entry.stage,
decision_status=decision_status,