net-kingdom/docs/evidence/2026-10-31-nk56-t12-synthetic-pilot/README.md
tegwick db56d8468e
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
NK-WP-0056-T12 done: pilot operations; synthetic rotation and revert pass
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
2026-10-31 16:24:17 +01:00

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 platform and cas_required on the svc-authelia bind.
  • 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

  1. 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 options are refused, by cas_required on 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.
  2. 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.
  3. 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.
  4. Error types in receipts. Receipts now carry the error type of a failed or unknown step, never its message.
  5. Stand-in artifact: a restarted container gets a new host port. Fixed in the harness; not relevant to Kubernetes.