These workplans exist only in the retired local hub. Their random pre-ADR-007 identifiers are refused by C-06 as stale references, so they cannot be registered. Deriving from the canonical record id takes no identity from anything: central does not hold them and the old ids die with the cache. Records central already holds were deliberately left untouched. Refs CUST-WP-0068-T06 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
162 lines
7 KiB
Markdown
162 lines
7 KiB
Markdown
---
|
|
id: RPF-WP-0020
|
|
type: workplan
|
|
title: "Close CCR schema drift: one active lane unmigrated, one draft the suite cannot express"
|
|
domain: financials
|
|
repo: railiance-platform
|
|
status: finished
|
|
owner: codex
|
|
topic_slug: railiance
|
|
created: "2026-08-18"
|
|
updated: "2026-08-21"
|
|
related:
|
|
- RPF-WP-0014
|
|
origin: residual
|
|
origin_ref: RPF-WP-0019
|
|
state_hub_workstream_id: "99bdb617-b577-5de3-a9d8-4990ac676e28"
|
|
---
|
|
|
|
# RPF-WP-0020 — CCR schema drift
|
|
|
|
## Goal
|
|
|
|
Make `tests/test_credential_change.py::test_all_repo_ccrs_validate` pass for
|
|
the right reason: because every credential-change request in the repo is
|
|
either valid or explicitly declared in-flight — not because the assertion was
|
|
loosened until it stopped complaining.
|
|
|
|
## Why this is its own workplan
|
|
|
|
The test has been failing on `main`. It was found while closing
|
|
`RPF-WP-0019` and confirmed to predate that work (it fails at `HEAD` with the
|
|
apps-pg changes stashed), so it is neither a regression from that workplan nor
|
|
something to fix inside it.
|
|
|
|
A single red test is hiding **two unrelated problems with opposite remedies**.
|
|
That is the reason to split them out and name them, rather than fix whichever
|
|
one makes the suite green first.
|
|
|
|
## The two problems
|
|
|
|
**P1 — an active credential lane uses an unrepresented auth mode.**
|
|
`credential-change-requests/CCR-2026-0010-email-connect-transactional.yaml`
|
|
carries `status: active` and `readiness: ready`. It has always declared the
|
|
live transitional ESO token Secret, bootstrap script, policy and TTL, but the
|
|
validator understood only OIDC and Kubernetes auth and consequently reported
|
|
the role/bound-claim fields for those modes as missing.
|
|
|
|
This is the one that matters. A live lane whose declaration does not describe
|
|
how the workload authenticates is a governance gap, not a lint failure — the
|
|
document that is supposed to be the authority on the lane cannot answer the
|
|
first question anyone would ask of it. The live lane is working, which is
|
|
exactly what made this representation gap easy to leave.
|
|
|
|
**P2 — a genuine in-flight request the suite could not express.**
|
|
`CCR-2026-0011-scaleway-object-storage-bootstrap.yaml` carries
|
|
`status: apply_pending` and an out-of-enum placeholder readiness string.
|
|
It is a founder-bootstrap credential still holding placeholder values, and
|
|
`ops-warden` already tracks it as a draft lane. Its errors include a
|
|
`readiness` value outside the permitted enum, which is the file honestly
|
|
reporting that it is not finished.
|
|
|
|
This one is not a defect. The defect is that a suite asserting *all* CCRs
|
|
validate has no way to say "this one is deliberately incomplete", so an honest
|
|
draft and a real gap produce identical output.
|
|
|
|
## Boundaries
|
|
|
|
- **No secret values are read, written or rotated.** This is declaration
|
|
hygiene. Anything requiring a mint, a rotation or an apply belongs to the
|
|
credential-change approval flow in `docs/credential-change-approval.md`.
|
|
- P2 is not closed by filling in placeholders. The Scaleway bootstrap key is
|
|
a live commercial credential with an owner outside this repo.
|
|
- The validator's rules are not relaxed to accommodate either file.
|
|
|
|
## Tasks
|
|
|
|
```task
|
|
id: RPF-WP-0020-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "4763622c-78aa-556a-ba8e-9b556a2e78fc"
|
|
```
|
|
**Migrate CCR-2026-0010 to the current schema.** Determine the actual
|
|
authentication path for the `email-connect` transactional lane — Kubernetes
|
|
auth mount, role, bound claims, and the policy name that must match
|
|
`openbao.policy_name` — from the live OpenBao configuration and the existing
|
|
policy file, not by inventing plausible values. If the live configuration and
|
|
the declaration disagree, the live configuration is the fact and the
|
|
disagreement is the finding.
|
|
|
|
Completed 2026-08-21. Live read-only Kubernetes metadata showed
|
|
`ClusterSecretStore/openbao-email-connect` using
|
|
`external-secrets/openbao-email-connect-eso-token`, limited to namespace
|
|
`email-connect`, and reporting Valid; its ExternalSecret reported
|
|
SecretSynced. The schema now represents this transitional token mode directly,
|
|
requires the ESO policy artifact, Secret reference, bootstrap script, bounded
|
|
TTL and explicit Kubernetes-auth follow-up, and keeps delegated token creation
|
|
out of scope. No Secret value was read.
|
|
|
|
```task
|
|
id: RPF-WP-0020-T02
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "a897b2f5-b7ae-5dbf-9f51-54b2db5ca6fc"
|
|
```
|
|
**Give the suite a way to express a draft.** Add an explicit in-flight state
|
|
so `CCR-2026-0011` is skipped *by declaration* rather than by exception list —
|
|
a `status` the validator recognises as not-yet-complete, with the test
|
|
asserting that such files are still well-formed in every other respect. An
|
|
allowlist of filenames would work today and rot on the next draft.
|
|
|
|
Completed 2026-08-21. Added the non-applyable `in_flight` status. It requires a
|
|
named owner, blocking reason and exact `missing_fields`; only
|
|
`openbao.policy_file` and `openbao.auth` may be declared incomplete, while all
|
|
other CCR structure remains validated. CCR-2026-0011 now uses this state and a
|
|
valid non-resolvable front-door readiness without inventing policy/auth
|
|
metadata or filling credential placeholders.
|
|
|
|
```task
|
|
id: RPF-WP-0020-T03
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "44959415-a917-5dfb-a5ab-80ab166b9096"
|
|
```
|
|
**Report the drift rather than only fixing it.** If the `openbao.auth`
|
|
requirement was added without migrating existing active CCRs, other repos
|
|
carrying CCRs may have the same gap and no failing test to reveal it. Confirm
|
|
whether the requirement originated here or upstream, and notify accordingly.
|
|
|
|
Completed 2026-08-21. Git history traces the validator requirement to local
|
|
commit `815b124`; a filesystem-wide declaration search found CCR files and the
|
|
validator/schema implementation only in `railiance-platform`. There is no
|
|
upstream CCR implementation to migrate or notify. The migration obligation is
|
|
now documented locally.
|
|
|
|
```task
|
|
id: RPF-WP-0020-T04
|
|
status: done
|
|
priority: low
|
|
state_hub_task_id: "d85eeb8a-3147-59e1-bc2a-e84244dde93d"
|
|
```
|
|
**Make the suite green and keep it that way.** With T01 and T02 done, the full
|
|
suite passes. Record in `docs/credential-change-approval.md` that a new
|
|
required field obliges a migration pass over existing active CCRs — the
|
|
omission that produced P1.
|
|
|
|
Completed 2026-08-21. Regression coverage proves the live token-auth shape,
|
|
explicit in-flight omissions, rejection of undeclared omissions, and safe
|
|
status/summary rendering. The approval guide now requires a migration pass over
|
|
all existing CCRs whenever required fields are added or strengthened. The full
|
|
repository test suite passes.
|
|
|
|
## Risks
|
|
|
|
**T01 invents values to make the test pass.** The likeliest failure and the
|
|
worst one: a declaration that is well-formed and wrong is more dangerous than
|
|
one that is visibly incomplete, because it stops anyone looking. Mitigation is
|
|
that T01 reads live configuration and treats disagreement as a finding.
|
|
|
|
**T02 becomes a way to silence future failures.** Mitigation is that the
|
|
in-flight state still requires the file to be well-formed in every other
|
|
respect, so it suppresses the completeness assertion and nothing else.
|