railiance-platform/workplans/RPF-WP-0016-versioned-ephemeral-custody-lifecycle.md
codex e4af2a1d10
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(workplans): migrate active workplans off the retired RAILIANCE-WP prefix
RAILIANCE-WP is a family name, not a repository (ADR-007, and the prefix
registry already lists it retired). Three repositories independently used one
number space for unrelated work — RAILIANCE-WP-0012 was openbao extraction here,
a cnpg backup in railiance-apps and a deploy-verify in railiance-cluster. This
repository also carried two files both numbered 0016.

Active workplans move to the successor prefix and are renumbered from 0001 in
historical order. Archived workplans keep their historical identifiers.

Projection UUIDs are re-derived from the new canonical ids. Records already
registered under the old identifiers leave orphaned hub rows behind; that debt
is recorded in CUST-WP-0068 and clears when ADR-012's reset-from-forge lands.

Refs CUST-WP-0068-T03

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-25 22:58:35 +02:00

7.5 KiB

id type title domain repo status owner topic_slug created updated related origin origin_ref state_hub_workstream_id
RPF-WP-0016 workplan Version ephemeral custody projection and broker handoff financials railiance-platform finished codex railiance 2026-08-22 2026-08-22
RAILIANCE-WP-0024
WHITEHAT-WP-0001
AUDIT-WP-0008
run-review WH-ENG-20260822-AUDIT-E2-02 terminal clean admission abort 26165dd5-dca5-5261-b4bf-183d186aad27

RPF-WP-0016 — Version ephemeral custody projection and broker handoff

Goal

Replace engagement-specific credential scripts and prose handoffs with one versioned, value-safe, fail-closed lifecycle. A consumer must prove it can consume the projection receipt before platform custody mints anything. The platform then exposes direct preflight, project, status, cleanup, and expired-lease cleanup interfaces without transferring bearer values or collapsing owner approvals.

The implementation is repository code and contracts only. It does not authorize or schedule a live credential projection, workload, probe, or unattended cleanup controller.

T01 — Define projection, broker-readiness, and cleanup receipts

id: RPF-WP-0016-T01
status: done
priority: high
state_hub_task_id: "3d95a854-1c54-58c9-90d2-971b9a9ec5c6"

Publish versioned JSON Schemas and canonical validation for the projection contract, broker-readiness receipt, active projection receipt, and cleanup receipt. Bind every receipt to the exact engagement, target revision and image, runner and target contract digests, mounted identity handles, expiry, opaque lease id, and cleanup authority. Values and value-derived fingerprints are forbidden.

Done when malformed, stale, mismatched, expired, and value-bearing documents fail closed and consumers can implement without interpreting prose.

Implemented in four JSON Schemas plus scripts/custody_contract.py. Canonical projection ids cover all receipt content; validators bind target, contract, roles, mount paths, resource names and UIDs, and reject value-bearing fields. Broker approvals also pin the current hashes of all four interface schemas.

T02 — Implement a data-driven custody lifecycle

id: RPF-WP-0016-T02
status: done
priority: high
state_hub_task_id: "783f74b8-d4a6-5ac5-9300-62acfedc53c6"

Replace copied per-engagement code and static manifests with one lifecycle that derives exact OpenBao and ESO resources from a validated engagement contract. Expose value-safe preflight, project, status, and idempotent cleanup commands. Preserve the existing two-identity sender overlay, application-level expiry, exact-key mount, readiness reload, and exact-scope rollback behavior.

Done when a new engagement requires data only, not copied Python, HCL, or YAML, and an old engagement identifier cannot leak into generated resources.

Implemented by scripts/custody-projection.py and the intentionally invalid placeholder template docs/custody-projection-contract.example.json. Policy, role, store, KV paths, ExternalSecret data mappings, sender overlays, expiry, and cleanup scope derive from one validated contract. Resource names use an engagement-id digest rather than a copied run suffix.

T03 — Gate projection on a direct broker capability receipt

id: RPF-WP-0016-T03
status: done
priority: high
state_hub_task_id: "e2cced83-5beb-5fb1-919a-72bd6cb49dcf"

Provide a direct owner interface for whitehat-security to inspect, verify, approve, or request changes to the contract. Approval must identify the tested adapter revision and artifact digest and be posted directly to State Hub. The platform lifecycle must find a current matching approval before generating a credential.

Done when an unconnected, stale, wrong-engagement, or wrong-contract broker is rejected before the first OpenBao or sender-registry mutation.

Implemented by scripts/wp0025-broker-readiness.py. Its closed verification surface pins Whitehat's adapter and focused test paths, computes their commit and digest, runs only the named focused test, and posts the canonical receipt directly as whitehat-security. project checks State Hub before reading the platform-admin token file, generating bearer values, or touching live state. No adapter approval is fabricated by this implementation; a future Whitehat adapter must pass the interface itself.

T04 — Harden execution and transactional cleanup

id: RPF-WP-0016-T04
status: done
priority: high
state_hub_task_id: "a14cb95b-6ef4-5872-a4ec-c7b51577cef1"

Centralize remote argv quoting, test shell-hostile arguments, and inject failures at each mutation boundary. Prove that partial projection invokes exact cleanup and that status never infers absence after a connectivity failure. Retire the copied -01/-02 procedure from future-run instructions.

Done when the SSH expansion defect from the -02 run and every modeled partial failure have regression coverage.

Implemented by scripts/remote_exec.py and focused tests covering $, shell substitution, semicolons, quotes, NUL refusal, and value-safe failure messages. The lifecycle uses a transaction whose rollback is exercised after every modeled mutation boundary. Connectivity failure cannot be interpreted as absence, and cleanup refuses a recreated same-name Kubernetes resource whose UID differs from the receipt.

T05 — Add an approval-ready expired-lease cleanup entry point

id: RPF-WP-0016-T05
status: done
priority: medium
state_hub_task_id: "8e2840d1-b8e3-5f0f-8c94-f5019fff4e72"

Add a fail-closed cleanup-expired interface that accepts only a valid projection receipt after its expiry, removes only the receipt-bound resources, and emits the normal cleanup receipt. Do not install a scheduler or controller; deployment of unattended cleanup remains a separate owner decision.

Done when an approved future reaper can call a deterministic command without receiving projected bearer values or reconstructing cleanup scope from chat.

Implemented as cleanup-expired. It refuses before expiry, requires the exact canonical projection receipt and engagement confirmation, verifies live UIDs, uses the ordinary exact cleanup transaction, and emits the versioned cleanup receipt. No scheduler, controller, runtime identity, or unattended authority was deployed; those remain a separate owner decision.

Acceptance

  • No projection can begin without a current consumer broker receipt.
  • A new engagement is configuration, not copied executable code.
  • Projection and cleanup receipts are versioned, canonical, and value-safe.
  • Remote command arguments survive shell-hostile templates unchanged.
  • Every modeled partial mutation cleans only its receipt-bound scope.
  • Expired cleanup is executable but no unattended scheduler is deployed.

T06 — Export the broker receipt consumed by admission

id: RPF-WP-0016-T06
status: done
priority: high
state_hub_task_id: "d815e1b9-73fe-527c-85c9-c20e37cf510f"

The first fresh-run setup review found that approve posted the canonical broker-readiness receipt to State Hub but exposed no safe way to persist the raw receipt document required by Whitehat's --broker-receipt input. Redirecting the command output would save a CLI wrapper rather than the canonical document.

approve and a ready status now accept --receipt-out, create parent directories, write only the canonical value-safe receipt, and force mode 0600. Other commands fail closed when that option is supplied. Regression coverage proves the wrapper is excluded and the file mode is private.