operations.py: OpenBao KV v2 CAS, LLDAP self-rotation (forward and revert), ExternalSecret force-sync and status, rollout restart (RolloutFailed is a definite failure), pilot checks. synthetic_pilot.py on the T08 stack plus OpenBao 2.5.4 with CCR-2026-0058's policy: rotation completed; a one-off wrong delivery reverted in declared order with the earlier value restored. Runner: revert steps run in declared order (BEA-10), definite failures revert, unknown outcomes stop, receipts carry error types. Found and corrected (in railiance-platform) CCR-2026-0058's required_parameters refusing reads. Packaging moved to new T13. 29 executor tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 994874@bnt-lap001 Assistant-Session: 6017c416-d619-47eb-bd1a-f670a02d7d87
2.9 KiB
2.9 KiB
NK-WP-0056-T12: the executor rotates a bind on the synthetic stack (2026-10-31)
Agent-run, local Docker, generated values, everything removed afterwards: uv run bounded-executor/synthetic_pilot.py.
Setup:
- The T08 stack: LLDAP, privacyIDEA, Authelia and KeyCape on the pinned images.
- An OpenBao dev server on the platform's pinned 2.5.4 image, with KV v2 at
platformandcas_requiredon thesvc-autheliabind. - The executor gets its own token with CCR-2026-0058's policy file plus a journey-read policy.
- Stand-ins:
- approval-engine: an in-process carrier with its consume semantics;
- audit-core: an in-memory sink;
- the ExternalSecret: re-projects the KV value into Authelia's configuration;
- the rollout: restarts the Authelia container.
- The Kubernetes adapters are unit-tested against a fake API server (
bounded-executor/tests/test_operations.py).
Report: pilot-report.json. It is value-free: scanned, and the harness asserts that no generated
value is present.
| Run | Outcome | Evidence |
|---|---|---|
| BEA-2026-9001 rotation | completed |
KV v1→v2; LLDAP refuses the old value and accepts the new; delivery, restart and synthetic journey pass; started event and receipt emitted |
| BEA-2026-9002 one-off wrong delivery | reverted |
Authelia never becomes ready after the restart (RolloutFailed, a definite failure). Revert in declared order, each step passing its own check: restore-kv → restore-directory → redeliver → restart-again. The value from before the run is current again (KV v4); the journey passes |
Findings that changed the design
- CCR-2026-0058's policy refused reads. OpenBao 2.5.4 applies
required_parameters = ["options"]to GET as well, so the executor could not read the version it must name for CAS. The executor token got 403 on every read.- Without that line, read and CAS write work.
- A stale CAS and a write without
optionsare refused, bycas_requiredon the key. - Metadata, delete, sibling reads and new paths are still denied.
- The fix is in railiance-platform's renderer and policy file. CCR-2026-0058 needs re-approval.
- Revert order. Undoing in strict reverse order would restart Authelia before its password was restored. Revert steps now run in the order the admission declares (data, then delivery, then restart), limited to steps that ran. The standard's BEA-10 says so.
- Definite failures revert. A rollout that never becomes ready was first handled like an unknown outcome
(stop, no revert). Operations can now signal a definite failure (
definite_failure,executor.StepFailed), which the runner reverts like a failed check. Truly ambiguous errors still stop. - Error types in receipts. Receipts now carry the error type of a failed or unknown step, never its message.
- Stand-in artifact: a restarted container gets a new host port. Fixed in the harness; not relevant to Kubernetes.