railiance-platform/workplans/RAILIANCE-WP-0014-credential-change-suite-stabilization.md
codex b876a9b5ba
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Open RAILIANCE-WP-0015: platform rapp consistency
Survey of the four-axis repo family model against the live cluster and all six
family repos found the concepts sound but unenforced: rapp.yaml has no schema
and has drifted three ways across the three existing rapps, the reef binding
registry lists 1 of 3 live rapps, the rapp population diverged from the
first-wave plan of record, and the model is not in custodian canon so
fix-consistency cannot check it.

Operator decisions recorded in the workplan: grouped-by-bounded-context rapp
granularity, S3 owns only its own rapps and routes schema/canon changes to the
repos that own them, canonize the model now, and build the missing wave-1
user-facing exemplar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:08:44 +02:00

137 lines
5 KiB
Markdown

---
id: RAILIANCE-WP-0014
type: workplan
title: "Credential-change test suite stabilization"
domain: financials
repo: railiance-platform
status: finished
owner: codex
topic_slug: railiance
created: "2026-08-11"
updated: "2026-08-11"
related_repos:
- rapp-postgres
- ops-warden
state_hub_workstream_id: "4dea40b7-43f5-499a-8919-79221623aa79"
---
# RAILIANCE-WP-0014 - Credential-change test suite stabilization
## Goal
Make `python3 -m unittest discover -s tests -p 'test_credential*.py'` pass
non-interactively again, without weakening any approval or front-door gate.
Origin: the `rapp-postgres` coordination message of 2026-08-11, a residual from
`RAPP-POSTGRES-WP-0002-T04`. The focused credential broker suite was green
(9/9) at commit `9f6bdff`, but full discovery reported five failures unrelated
to the broker work.
## Diagnosis
None of the five failures were broker regressions. Two were missing or invalid
artifacts in `CCR-2026-0009`; three were test fixtures that had silently
decayed as real CCR lanes advanced through their lifecycle.
The decay is the important finding. Three refusal tests used the live
`CCR-2026-0002` file as their "unapproved CCR" fixture. That lane has since
been approved, applied and activated, so the refusal those tests assert stopped
being the correct behaviour for that input — the gate did exactly the right
thing and the tests failed anyway. `applier-apply` then walked past its
(correctly ordered) blocker check into the interactive confirmation prompt and
raised `EOFError` under a non-interactive runner. A refusal test that reads its
approval state off a mutable production artifact will keep breaking every time
a lane advances.
## Boundaries
This workplan may:
- repair credential-change test fixtures and add missing CCR source artifacts
- correct schema-invalid field values in credential change requests
It must not:
- relax `applier_readiness_blockers`, `runbook_readiness_blockers`, or the
front-door `resolvable`/`status` coupling in `scripts/credential-change.py`
- change grant delivery or revocation semantics in `credential-grants/catalog.yaml`
- write or move any secret value
## Tasks
```task
id: RAILIANCE-WP-0014-T01
status: done
priority: high
state_hub_task_id: "18d3358b-2cd6-4fe0-aab6-602f85d8cccd"
```
Repair `CCR-2026-0009` (qonto-assistant workload KV read lane) so it validates:
- add the missing `openbao/policies/workload-kv-read-qonto-assistant.hcl`,
scoped read-only to `tenants/{data,metadata}/binky/qonto-api` and mirroring
the `workload-kv-read-binky-qonto-api.hcl` shape
- replace the schema-invalid `access_frontdoor.readiness: proposed` with
`pending-review`, which is the correct state for a CCR still in review
The CCR stays `status: proposed` with `resolvable: false` — this task adds the
missing source artifact, it does not advance the lane.
```task
id: RAILIANCE-WP-0014-T02
status: done
priority: high
state_hub_task_id: "4705a142-4168-41a8-aba0-691d8fc3c6bd"
```
Stop the refusal tests depending on live CCR lifecycle state. Add a
`unapproved_ccr()` helper to `tests/test_credential_change.py` that materializes
a temp copy normalized to `status: proposed`, no review comments,
`readiness: pending-review`, `resolvable: false`, and point
`test_applier_dry_run_refuses_unapproved_ccr`,
`test_applier_apply_refuses_unapproved_ccr`,
`test_runbook_refuses_unapproved_ccr` and
`test_operator_commands_refuse_unapproved_ccr` at it.
This also removes the `EOFError`: with a genuinely unapproved CCR,
`command_applier_apply` returns 1 at its blocker check and never reaches the
confirmation prompt. The gate ordering in `scripts/credential-change.py` was
already correct and was left untouched.
```task
id: RAILIANCE-WP-0014-T03
status: done
priority: medium
state_hub_task_id: "dd34d578-97e5-4c26-aef8-faafc994c387"
```
Fix `test_approve_records_comment_but_unconfirmed_claim_still_blocks_apply`,
which demoted an active CCR to `approved` while leaving
`access_frontdoor.resolvable: true`, tripping the
`resolvable=true requires status active` rule. Build the fixture from
`unapproved_ccr()` so the front-door state is consistent with the status the
test actually wants. The validation rule is correct and unchanged.
```task
id: RAILIANCE-WP-0014-T04
status: done
priority: high
state_hub_task_id: "457053f2-261f-4c80-92d4-c084e6236e88"
```
Confirm acceptance against the requested criteria:
- `python3 -m unittest discover -s tests -p 'test_credential*.py' < /dev/null`
— 52 tests, OK
- full repo discovery `-p 'test_*.py'` — 61 tests, OK
- `make credential-change-validate` — all nine CCRs OK
- `python3 scripts/credential-grants-validate.py` — catalog valid, 3 grants
- both `rapp-postgres/audit-core-*` `openbao-database-credential` grants still
carry `delivery.allowed: [exec-env]` with `child_only`/`redact_logs`, and
`revocation.required: true` with `on_exec_exit: true`
## Outcome
Suite green non-interactively; no gate, blocker, validation rule or grant
semantic was modified. The one behavioural change outside tests is the addition
of a previously missing least-privilege policy artifact.