railiance-platform/workplans/RPF-WP-0008-credential-change-suite-stabilization.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

137 lines
5 KiB
Markdown

---
id: RPF-WP-0008
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: "ec6b9fe2-5aae-5eb0-ba05-c1be241eda6b"
---
# RPF-WP-0008 - 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: RPF-WP-0008-T01
status: done
priority: high
state_hub_task_id: "300632b3-f89c-523e-a31f-b9bc98c8df30"
```
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: RPF-WP-0008-T02
status: done
priority: high
state_hub_task_id: "9533e97b-06dc-58d5-8249-fe299bad438d"
```
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: RPF-WP-0008-T03
status: done
priority: medium
state_hub_task_id: "1b417fe7-6703-5663-9f3c-3a040ce1fe6f"
```
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: RPF-WP-0008-T04
status: done
priority: high
state_hub_task_id: "83a4e8da-5ebb-5006-8aa8-2fe02169f9ba"
```
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.