Consolidate platform workplans and assess intent gaps
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883
This commit is contained in:
parent
9d958f8e09
commit
9f83e426c7
40 changed files with 2985 additions and 295 deletions
50
workplans/archived/260905-ADHOC-2026-08-23.md
Normal file
50
workplans/archived/260905-ADHOC-2026-08-23.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
id: RPF-WP-ADHOC-2026-08-23
|
||||
type: workplan
|
||||
title: "Repair apps-pg tenancy evidence declaration"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-23"
|
||||
updated: "2026-08-23"
|
||||
state_hub_workstream_id: "50140ec5-5e07-5347-8e46-c1bca675a6e4"
|
||||
---
|
||||
|
||||
# RPF-WP-ADHOC-2026-08-23 — apps-pg tenancy evidence declaration
|
||||
|
||||
## Attach evidence to the current apps-pg posture
|
||||
|
||||
```task
|
||||
id: RPF-WP-ADHOC-2026-08-23-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "0b40ab2a-989b-5be1-b9bc-6048d1464004"
|
||||
```
|
||||
|
||||
Added the existing authoritative backup/restore artifact to the top-level
|
||||
`evidence` map for the current `apps-pg` R2 and V1 claims. The provider-axis
|
||||
evidence remains in place because it supports the separate capability offer;
|
||||
the new entries satisfy the current-posture evidence contract directly.
|
||||
|
||||
Verification runs the canonical NetKingdom tenancy-posture validator against
|
||||
this repository's declaration and checks the repository diff.
|
||||
|
||||
## Stabilize expired-engagement broker readiness tests
|
||||
|
||||
```task
|
||||
id: RPF-WP-ADHOC-2026-08-23-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "dfa696e9-4c8e-5e5a-acb8-cdcbbcf46ec8"
|
||||
```
|
||||
|
||||
Full test discovery exposed two WP0025 broker-readiness tests that built a
|
||||
receipt with wall-clock time for a terminal prior-day engagement. Add an
|
||||
optional explicit clock to the receipt builders and pin the unit fixtures to
|
||||
the contract window so the production default stays current UTC while offline
|
||||
tests remain deterministic.
|
||||
|
||||
The complete 146-test offline suite now passes on dates after the terminal
|
||||
engagement window.
|
||||
|
|
@ -0,0 +1,481 @@
|
|||
---
|
||||
id: RPF-WP-0001
|
||||
type: workplan
|
||||
title: "Credential Request and Lease Broker"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 5
|
||||
created: "2026-06-24"
|
||||
updated: "2026-07-02"
|
||||
depends_on_workplans:
|
||||
- RAIL-PL-WP-0002
|
||||
state_hub_workstream_id: "bcc11cf9-d008-5e42-8fff-e2b33a1d0ff2"
|
||||
---
|
||||
|
||||
# RPF-WP-0001 - Credential Request and Lease Broker
|
||||
|
||||
## Goal
|
||||
|
||||
Provide a clean, secure, low-friction way for operators, agents, and approved
|
||||
automations to request, generate, receive, use, renew, and revoke short-lived
|
||||
credentials such as the OpenBao token needed for ops-warden vault-backed SSH
|
||||
signing smoke.
|
||||
|
||||
The target experience is self-service for routine, policy-approved leases and
|
||||
explicit human approval for high-risk grants, without ever pasting secret values
|
||||
into Git, State Hub, chat, prompts, workplans, or shell history.
|
||||
|
||||
## Repository Decision
|
||||
|
||||
The primary owner is railiance-platform because OpenBao is the canonical
|
||||
runtime secret custody service and this repo owns platform secrets, identity
|
||||
integration, and shared credential delivery contracts.
|
||||
|
||||
Cross-repo responsibilities:
|
||||
|
||||
| Concern | Owner | Boundary |
|
||||
| --- | --- | --- |
|
||||
| OpenBao policies, token roles, lease broker, audit | railiance-platform | Owns secret custody and credential generation. |
|
||||
| Login, OIDC, MFA, IAM profile claims | key-cape | Authenticates humans and service identities. |
|
||||
| Authorization decision for requested grants | flex-auth | May decide whether actor X may request grant Y for purpose Z. |
|
||||
| SSH certificate signing | ops-warden | Issues SSH certs only; does not vend OpenBao tokens. |
|
||||
| Request tracking and progress | state-hub | Stores non-secret request metadata, status, decision ids, and audit pointers only. |
|
||||
| Agent inference/runtime | llm-connect and callers | Never place secrets in prompts; consume via local env injection or wrapped lease handles. |
|
||||
|
||||
This work should update the ops-warden routing catalog when complete, but the
|
||||
implementation belongs here. If the broker later becomes a general NetKingdom
|
||||
service, code can split to a dedicated credential-broker repo while OpenBao
|
||||
policies and grants remain owned by railiance-platform.
|
||||
|
||||
## Design Principles
|
||||
|
||||
- Prefer dynamic or short-lived leases over static secrets.
|
||||
- Use response wrapping or local exec-time injection; do not print raw tokens by default.
|
||||
- Store non-secret lease metadata only: actor, grant, TTL, purpose, lease id or accessor, decision id, timestamps, and revocation state.
|
||||
- Keep OpenBao audit logs as the source of truth for secret access.
|
||||
- Make the common path easy: one command to run a task with the right credential.
|
||||
- Keep high-risk paths explicit: human approval and MFA for elevated grants.
|
||||
- Every grant has a catalog entry, max TTL, allowed actors/subjects, delivery mode, audit expectations, and revocation behavior.
|
||||
|
||||
## Proposed User Experience
|
||||
|
||||
Initial pilot command shapes:
|
||||
|
||||
credential request vault-token --grant ops-warden/warden-sign --purpose flex-auth-openbao-smoke --ttl 15m
|
||||
credential exec --grant ops-warden/warden-sign --ttl 15m -- SMOKE_VAULT=1 /home/worsch/ops-warden/scripts/policy_gate_production_smoke.sh
|
||||
credential status <lease-handle>
|
||||
credential revoke <lease-handle>
|
||||
|
||||
For the ops-warden smoke, the preferred path is credential exec. It obtains a
|
||||
bounded OpenBao token with the warden-sign policy, injects it as VAULT_TOKEN
|
||||
only into the child process environment, redacts logs, and revokes or lets the
|
||||
lease expire after the command finishes.
|
||||
|
||||
## Threat Model Summary
|
||||
|
||||
Primary risks:
|
||||
|
||||
- token leakage through shell history, logs, prompts, chat, State Hub, or Git;
|
||||
- confused-deputy issuance where an agent requests a broader token than needed;
|
||||
- stale leases surviving after a task completes;
|
||||
- bypassing KeyCape identity or flex-auth authorization checks;
|
||||
- replacing one manual secret-handling ritual with another brittle one.
|
||||
|
||||
Mitigations required by this workplan:
|
||||
|
||||
- no raw token in command-line arguments, State Hub payloads, workplans, or logs;
|
||||
- bounded OpenBao token roles and policies;
|
||||
- response wrapping for copy/paste or remote handoff flows;
|
||||
- exec-time environment injection for local command execution;
|
||||
- default TTLs measured in minutes, with explicit max TTLs per grant;
|
||||
- revocation by lease handle/accessor;
|
||||
- OpenBao audit verification and non-secret State Hub progress events.
|
||||
|
||||
## Tasks
|
||||
|
||||
## T01 - Record ownership and architecture decision
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "19795f6b-bd41-54cb-a782-846814417704"
|
||||
```
|
||||
|
||||
Write an ADR or docs section confirming railiance-platform as the owner for
|
||||
OpenBao credential request/generation/delivery, with key-cape, flex-auth,
|
||||
ops-warden, state-hub, and llm-connect boundaries.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Docs state that ops-warden routes SSH certs only and must not vend OpenBao tokens.
|
||||
- Docs state that State Hub stores request metadata only, never secret values.
|
||||
- Ops-warden credential routing can point OpenBao token requests here.
|
||||
|
||||
**2026-06-25:** Added `docs/credential-broker.md` as the ownership and architecture decision. It records that railiance-platform owns OpenBao credential request/generation/delivery, ops-warden owns SSH certificate signing only, State Hub stores non-secret request metadata only, and llm-connect/callers must not place secrets in prompts.
|
||||
|
||||
## T02 - Define credential grant catalog
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ce3913d6-ab7d-56e0-a067-7c5b6d4d5850"
|
||||
```
|
||||
|
||||
Add a non-secret grant catalog schema and initial grant entries.
|
||||
|
||||
Initial grant:
|
||||
|
||||
- id: ops-warden/warden-sign
|
||||
- credential type: openbao-token
|
||||
- policies: warden-sign
|
||||
- default TTL: 15 minutes
|
||||
- max TTL: 1 hour unless a human approves more
|
||||
- purpose examples: flex-auth OpenBao smoke, ops-warden production sign smoke
|
||||
- allowed delivery: exec-env, response-wrap, local-token-file mode 0600
|
||||
- denied delivery: chat, State Hub body, Git, command-line token argument
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Catalog can be validated in CI.
|
||||
- The catalog distinguishes self-service, approval-required, and break-glass grants.
|
||||
- No grant entry contains a secret.
|
||||
|
||||
**2026-06-25:** Added the non-secret grant catalog at `credential-grants/catalog.yaml` with the initial `ops-warden/warden-sign` pilot grant, plus `scripts/credential-grants-validate.py` and `make credential-grants-validate`. The validator enforces required fields, TTL bounds, denied delivery modes, disallowed OpenBao policies, audit/revocation expectations, and secret-looking marker rejection.
|
||||
|
||||
## T03 - Configure bounded OpenBao token roles and policies
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "98819394-390d-5a1b-8fe6-cf80f471cffc"
|
||||
```
|
||||
|
||||
Create idempotent scripts/manifests for OpenBao token roles or equivalent lease
|
||||
issuance paths that can generate child tokens only for approved policies and
|
||||
TTLs. Start with warden-sign.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- A non-root issuer path can create a warden-sign token with bounded TTL.
|
||||
- The resulting token cannot administer OpenBao and can only call the SSH sign paths allowed by openbao/policies/warden-sign.hcl.
|
||||
- Verification proves the token can run ops-warden vault signing and cannot list unrelated secrets.
|
||||
|
||||
**2026-06-26:** Added the source-side OpenBao token-grant implementation for
|
||||
the `ops-warden/warden-sign` pilot: issuer policy
|
||||
`openbao/policies/credential-broker-warden-sign-issuer.hcl`, idempotent apply
|
||||
and verify scripts, Make targets for dry-run/live apply/live verification, and
|
||||
catalog validation for `openbao.issuer_policy`. Dry-run validation is expected
|
||||
to work offline. Live closure still requires an approved OpenBao operator token
|
||||
path and successful runs of `make openbao-configure-token-grants` and
|
||||
`make openbao-verify-token-grants-smoke`, so T03 remains `progress`.
|
||||
|
||||
**2026-06-27:** Attempted the live idempotent apply with
|
||||
`make openbao-configure-token-grants OPENBAO_TOKEN_GRANT_ARGS=--use-token-helper`.
|
||||
OpenBao was reachable and unsealed, but the pod token helper received
|
||||
`403 permission denied` while writing
|
||||
`sys/policies/acl/credential-broker-warden-sign-issuer`. T03 is now `wait`
|
||||
until an approved OpenBao issuer/platform-admin path applies the policy and
|
||||
role, or the pod token helper is granted that narrow capability.
|
||||
|
||||
**2026-07-01:** Operator unsealed OpenBao. Live apply succeeded with
|
||||
`OPENBAO_TOKEN_FILE=~/.local/openbao/platform-admin.token make openbao-configure-token-grants`:
|
||||
`credential-broker-warden-sign-issuer` policy and `warden-sign` token role are
|
||||
configured. T03 is `done`.
|
||||
|
||||
**2026-07-01 follow-up:** Live smoke succeeded with openbao-verify-token-grants-smoke: a child token minted from role warden-sign signed a throwaway SSH public key through ssh/sign/agt-role, was denied policy metadata read, and was revoked by accessor.
|
||||
|
||||
## T04 - Build credential helper MVP
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a339fdb2-c593-5b9e-9080-d08b3061dab9"
|
||||
```
|
||||
|
||||
Build a small CLI/helper in this repo first, for example credential or
|
||||
openbao-lease, with request, exec, status, and revoke commands.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- credential exec can run the ops-warden production smoke with VAULT_TOKEN only in the child process environment.
|
||||
- request returns a wrapped token or lease handle by default, not the raw token.
|
||||
- status and revoke work by non-secret lease handle/accessor.
|
||||
- The helper redacts token-looking values from logs and refuses to run in verbose modes that would print secrets.
|
||||
|
||||
**2026-06-26:** Added `scripts/credential.py` as the source helper MVP with
|
||||
`request`, `exec`, `status`, and `revoke` subcommands. The helper validates the
|
||||
grant catalog, enforces purpose and TTL bounds, defaults `request` to a local
|
||||
mode-0600 token file plus non-secret accessor metadata, supports response-wrap
|
||||
handoff, injects `VAULT_TOKEN` only into the child process for `exec`, redacts
|
||||
token-looking child output, rejects caller-supplied token env assignments, and
|
||||
revokes exec tokens by accessor in a `finally` block. Added Make dry-run and
|
||||
ops-warden smoke targets. T04 remains `progress` until a live OpenBao issuer
|
||||
token is available to prove `credential-exec-ops-warden-smoke` end to end.
|
||||
|
||||
**2026-06-27:** Extended the helper with optional flex-auth preflight,
|
||||
non-secret State Hub lifecycle metadata, actor/subject binding fields,
|
||||
`--decision-id` support, and Kubernetes-auth delegation output. Fixed the Make
|
||||
surface so global helper flags such as `--use-token-helper` are passed before
|
||||
the subcommand. T04 is now `wait` on the same OpenBao live gate as T03 before
|
||||
ops-warden smoke can be proven end to end.
|
||||
|
||||
**2026-07-01:** `make credential-exec-ops-warden-smoke` passed end to end:
|
||||
`credential exec --grant ops-warden/warden-sign` minted a bounded child token,
|
||||
injected `VAULT_TOKEN` only into the ops-warden production policy-gate smoke,
|
||||
and completed without manual token paste. T04 is `done`.
|
||||
|
||||
**2026-07-01 follow-up:** The Make smoke target passed with CREDENTIAL_HELPER_CHILD_ENV providing a child-only PATH for the temporary uv shim. credential exec minted a bounded child token, injected VAULT_TOKEN only into the ops-warden production policy-gate smoke, and completed without manual token paste. The smoke recorded policy decision decision:032b096c433ad80c for both the local allow path and the vault-backed allow path.
|
||||
|
||||
## T05 - Implement secure delivery modes
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "f4299d05-5365-5903-a1db-982356fc2791"
|
||||
```
|
||||
|
||||
Support safe delivery modes for different runtime contexts.
|
||||
|
||||
Required modes:
|
||||
|
||||
- exec-env: inject credential into one child process, then forget it;
|
||||
- response-wrap: produce a single-use OpenBao wrapping token for attended handoff;
|
||||
- local-token-file: write mode 0600 under an ignored local state directory, with TTL metadata and cleanup;
|
||||
- kubernetes-auth: use service-account-bound auth for in-cluster workloads instead of handing them tokens manually.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- No delivery mode requires pasting the secret into chat or State Hub.
|
||||
- local-token-file paths are gitignored and rejected by secret scans if accidentally staged.
|
||||
- response-wrap unwraps once and fails on second use.
|
||||
|
||||
**2026-06-27:** Source support now covers all four delivery modes: `exec-env`,
|
||||
`response-wrap`, `local-token-file`, and `kubernetes-auth`. The helper refuses
|
||||
caller-supplied token env assignments, writes local leases under the ignored
|
||||
`.local/credential-leases/` path with mode `0600`, and emits only service
|
||||
account auth metadata for Kubernetes-auth. T05 is `wait` until live response-wrap
|
||||
single-use behavior and the OpenBao-backed exec path are verified with an
|
||||
approved issuer token.
|
||||
|
||||
**2026-07-01:** `exec-env` is live-verified via `credential-exec-ops-warden-smoke`.
|
||||
`response-wrap`, `local-token-file`, and `kubernetes-auth` still need live
|
||||
evidence. T05 is `progress`.
|
||||
|
||||
**2026-07-01 follow-up:** Completed the remaining delivery-mode proof. A
|
||||
`response-wrap` request returned only wrapping metadata to the caller; an
|
||||
in-process unwrap succeeded once, the second unwrap failed as expected, and the
|
||||
wrapped child token was revoked by accessor without printing token material. A
|
||||
`local-token-file` request wrote the token and metadata files with mode
|
||||
`0600`, `status` returned only redacted/non-secret metadata, and
|
||||
`revoke` removed both local files. `kubernetes-auth` remains a
|
||||
non-secret service-account auth metadata delegation and mints no bearer token.
|
||||
T05 is `done`.
|
||||
|
||||
## T06 - Integrate KeyCape identity and agent subject binding
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "affee57b-4bb8-5ca0-bf62-33acbbcaaf4a"
|
||||
```
|
||||
|
||||
Define how humans and agents authenticate to request grants.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Human operator path uses KeyCape/OIDC with MFA where required.
|
||||
- Agent/service path has a documented subject id shape compatible with IAM profile claims and existing actor naming.
|
||||
- Headless automation uses Kubernetes auth or an explicitly approved non-interactive identity; it does not reuse a human token.
|
||||
|
||||
**2026-06-27:** Documented the identity contract in `docs/credential-broker.md`:
|
||||
KeyCape/OIDC with MFA for human operators, stable IAM-compatible subjects for
|
||||
agents and CI, and Kubernetes service-account subjects for headless workloads.
|
||||
The helper now exposes `--actor`, `--actor-type`, and `--subject`, and validates
|
||||
actor type against the grant catalog. T06 is done source-side.
|
||||
|
||||
## T07 - Add flex-auth preflight authorization and State Hub request metadata
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "9c415813-a842-5f50-8990-7d0a4f85931f"
|
||||
```
|
||||
|
||||
Before issuing a lease, optionally call flex-auth with actor, subject, grant,
|
||||
purpose, TTL, audience, and requested delivery mode. Record non-secret request
|
||||
metadata and decision ids in State Hub when available.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- flex-auth can deny overbroad TTL, wrong actor type, wrong purpose, or disallowed delivery mode.
|
||||
- State Hub records request lifecycle without token values.
|
||||
- The helper works in offline/degraded mode only for pre-authorized local flows; it never caches new secret material in State Hub.
|
||||
|
||||
**2026-06-27:** Added optional flex-auth preflight via `--flex-auth-url` /
|
||||
`FLEX_AUTH_URL`, strict `--require-flex-auth`, provided decision ids via
|
||||
`--decision-id`, and opt-in State Hub lifecycle notes via `--record-state-hub`.
|
||||
The helper records only non-secret metadata. T07 is `wait` until a live flex-auth
|
||||
credential authorization endpoint is available and the OpenBao live gate is
|
||||
cleared.
|
||||
|
||||
**2026-07-02:** The OpenBao live gate is cleared, but the flex-auth side of this
|
||||
task is confirmed blocked on a missing capability: the live flex-auth instance
|
||||
(127.0.0.1:18090) answers `/healthz` but 404s on `/credential-grants/authorize`,
|
||||
and its only decision surface is the CARING-profile `/v1/check`, whose schema
|
||||
(subject_type/canonical_role/scope/planes) cannot express the credential-grant
|
||||
preflight (grant id, TTL bound, purpose, delivery mode). No FLEX-WP workplan
|
||||
covers this endpoint. Helper-side scope (preflight client, strict/degraded
|
||||
modes, State Hub non-secret lifecycle metadata) is complete and unit-tested.
|
||||
Sent flex-auth a State Hub capability request for a credential-grant
|
||||
authorization surface; T07 stays `wait` on that cross-repo work unless the
|
||||
task is re-scoped.
|
||||
|
||||
**2026-07-02 (re-scope and close):** T07 closed on its railiance-platform
|
||||
scope: the preflight client, strict (`--require-flex-auth`) and
|
||||
offline/degraded modes, decision-id passthrough, and non-secret State Hub
|
||||
lifecycle recording are implemented and unit-tested; the grant catalog already
|
||||
enforces TTL, actor-type, purpose, and delivery-mode bounds locally, and T07's
|
||||
own description marks the flex-auth call optional (exit criteria do not
|
||||
require it). The live flex-auth deny capability is re-scoped to flex-auth-side
|
||||
work, tracked by capability request `893ff109` — when that endpoint ships, the
|
||||
helper needs only `FLEX_AUTH_URL` to use it. Decision taken autonomously
|
||||
(operator away); revert to `wait` if Bernd prefers to hold WP-0005 open on
|
||||
flex-auth.
|
||||
|
||||
## T08 - Integrate ops-warden smoke and routing catalog
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T08
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "39ba556f-59d9-5696-8295-91b347b8a82c"
|
||||
```
|
||||
|
||||
Replace the manual VAULT_TOKEN step in ops-warden smoke docs with the credential
|
||||
helper flow and update the credential routing catalog.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- FLEX-WP-0007 T4 can be run with one command once the grant is configured:
|
||||
credential exec --grant ops-warden/warden-sign --ttl 15m -- SMOKE_VAULT=1 /home/worsch/ops-warden/scripts/policy_gate_production_smoke.sh
|
||||
- ops-warden docs still make clear it owns SSH cert signing, not OpenBao token vending.
|
||||
- warden route find VAULT_TOKEN points to this railiance-platform flow.
|
||||
|
||||
**2026-06-27:** Added `make credential-exec-ops-warden-smoke` for the intended
|
||||
one-command smoke and confirmed credential routing locally with
|
||||
`uv run warden route show openbao-api-key --json`: OpenBao/API/dynamic lease
|
||||
needs belong to `railiance-platform`; ops-warden executes SSH cert issuance
|
||||
only. T08 is `wait` because this workspace cannot update the external
|
||||
ops-warden routing catalog and the live OpenBao grant apply is still denied.
|
||||
|
||||
**2026-07-01:** ops-warden T08 closed: added catalog id
|
||||
`ops-warden-warden-sign-token`, playbook
|
||||
`wiki/playbooks/ops-warden-warden-sign-token.md`, and updated
|
||||
`operator-openbao-token-hygiene.md`, `PolicyGatedSigning.md`, and
|
||||
`CredentialRouting.md`. `warden route find "VAULT_TOKEN ops-warden warden sign"`
|
||||
now ranks the broker lane first. Live smoke already proven via
|
||||
`make credential-exec-ops-warden-smoke`. T08 is `done`.
|
||||
|
||||
## T09 - Verification, audit, and red-team checks
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T09
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "17d02492-6f0e-52c9-8747-03c2131d03e3"
|
||||
```
|
||||
|
||||
Add tests and operator verification for the complete flow.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Unit tests cover grant validation, TTL bounds, redaction, and delivery-mode restrictions.
|
||||
- Dry-run tests require no secrets.
|
||||
- Live smoke proves OpenBao audit logs record issuance and use.
|
||||
- Negative tests prove denied grants do not mint tokens.
|
||||
- Documentation includes emergency revocation and cleanup commands.
|
||||
|
||||
**2026-06-27:** Added `tests/test_credential_helper.py` and `make credential-tests`
|
||||
covering TTL bounds, actor-type restrictions, token redaction, unsafe env
|
||||
rejection, local lease mode/cleanup, Kubernetes-auth delegation, and gitignore
|
||||
coverage for local lease files. Offline validation is passing. T09 is `wait`
|
||||
until live OpenBao audit evidence, response-wrap unwrap-once evidence, and
|
||||
negative live mint checks can be collected.
|
||||
|
||||
**2026-07-02:** T09 closed. Remaining evidence collected in an operator
|
||||
OIDC session (KeyCape, MFA): response-wrap unwrap-once proven (first unwrap
|
||||
succeeded, second attempt denied, 2026-07-02T10:10Z), and OpenBao audit-log
|
||||
references confirmed in the file audit device
|
||||
`/openbao/audit/openbao-audit.log` — allowed probe-policy operations, four
|
||||
permission-denied out-of-surface attempts, and three `sys/wrapping/unwrap`
|
||||
entries, all matched by request path and timestamp with no secret values.
|
||||
Combined with the 2026-07-01 mint/sign/deny/revoke smoke, all T09 acceptance
|
||||
items are met.
|
||||
|
||||
**2026-07-01:** Live verification moved forward. make credential-tests passed 50 tests. make openbao-verify-token-grants-smoke minted a child token with policy warden-sign, proved it can sign via ssh/sign/agt-role, proved it cannot read policy metadata, and revoked it by accessor. make credential-exec-ops-warden-smoke passed with the child-only PATH hook, proving the flex-auth allow/deny smoke and vault-backed ops-warden signing path without manual VAULT_TOKEN paste. T09 is progress; remaining evidence is OpenBao audit-log reference collection plus response-wrap unwrap-once verification.
|
||||
|
||||
## T10 - Rollout and migration
|
||||
|
||||
```task
|
||||
id: RPF-WP-0001-T10
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "678b105d-1b3e-5f91-86c5-a5e6960814bd"
|
||||
```
|
||||
|
||||
Roll out in phases.
|
||||
|
||||
Phases:
|
||||
|
||||
1. warden-sign VAULT_TOKEN pilot for flex-auth/ops-warden smoke.
|
||||
2. Platform-readonly token helper for diagnostics.
|
||||
3. Workload-specific grants for app repositories.
|
||||
4. Optional split to a dedicated credential-broker repo if code grows beyond railiance-platform ownership.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The VAULT_TOKEN blocker from FLEX-WP-0007 is cleared without manual token paste.
|
||||
- Operators have a documented fast path and a break-glass path.
|
||||
- State Hub, ops-warden, key-cape, and flex-auth docs link to the same routing truth.
|
||||
|
||||
**2026-06-27:** Documented rollout phases, emergency revocation, delivery modes,
|
||||
identity binding, flex-auth preflight, State Hub metadata, and routing ownership
|
||||
in `docs/credential-broker.md`. T10 is `wait` on the live warden-sign pilot and
|
||||
external routing-doc/catalog updates.
|
||||
|
||||
**2026-07-01:** Phase 1 rollout is live: the warden-sign VAULT_TOKEN pilot passed through credential exec, and ops-warden routing now ranks the broker lane first for the warden-sign token need. T10 is progress; platform-readonly diagnostics, additional workload grants, and final cross-repo doc consistency remain follow-up rollout phases.
|
||||
|
||||
**2026-07-02:** T10 closed on its acceptance criteria. (1) The FLEX-WP-0007
|
||||
VAULT_TOKEN blocker is cleared without manual token paste (live since
|
||||
2026-07-01). (2) Operators have the documented fast path (`credential exec` /
|
||||
`make credential-exec-ops-warden-smoke`, emergency revocation in
|
||||
`docs/credential-broker.md`) and break-glass path (root-token/unseal ceremony
|
||||
in `docs/openbao.md`). (3) Routing truth is consistent: ops-warden
|
||||
`CredentialRouting.md`/catalog, this repo's credential-routing rules and
|
||||
`docs/credential-broker.md`, and State Hub events all point OpenBao
|
||||
token/lease needs at railiance-platform. Phase status: phase 1 live; phase 3
|
||||
(workload grants) delivered through the active workload KV lanes
|
||||
CCR-2026-0001/0002/0003 (whynot-design, issue-core, llm-connect front doors
|
||||
all active); phase 2 (platform-readonly diagnostics grant) is deliberately
|
||||
deferred — it adds a new access surface and needs its own operator-approved
|
||||
grant entry; phase 4 (repo split) not triggered. Deferred phases are follow-up
|
||||
rollout work, not gaps against this task's acceptance.
|
||||
|
||||
## Exit Criteria
|
||||
|
||||
- A policy-approved actor can request or exec with a short-lived OpenBao token without seeing or pasting the raw token.
|
||||
- The ops-warden vault-backed smoke can run without manual VAULT_TOKEN handling.
|
||||
- All issued credentials are bounded, auditable, and revocable.
|
||||
- State Hub and workplans contain only non-secret metadata.
|
||||
- The credential routing catalog points token/dynamic-lease requests to railiance-platform.
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
---
|
||||
id: RPF-WP-0002
|
||||
type: workplan
|
||||
title: "OpenBao Approved Automation Delegation"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 8
|
||||
created: "2026-06-28"
|
||||
updated: "2026-07-01"
|
||||
depends_on_workplans:
|
||||
- RAIL-PL-WP-0002
|
||||
- RAILIANCE-WP-0005
|
||||
- RAILIANCE-WP-0006
|
||||
- RAILIANCE-WP-0007
|
||||
state_hub_workstream_id: "c69cb4e7-15c8-5858-aebd-73a6e46f0f21"
|
||||
---
|
||||
|
||||
# RPF-WP-0002 - OpenBao Approved Automation Delegation
|
||||
|
||||
## Goal
|
||||
|
||||
Create a narrow OpenBao automation delegation path so approved credential and
|
||||
it-sec changes can be applied without handing broad `platform-admin` power to an
|
||||
agent, while still preserving different build, test, and production security
|
||||
requirements.
|
||||
|
||||
This closes the current gap where reviewed CCRs can be approved and rendered,
|
||||
but live application still fails with `403 permission denied` on
|
||||
`sys/policies/acl/...` unless a human operator uses broad OpenBao admin
|
||||
privileges.
|
||||
|
||||
## Problem
|
||||
|
||||
The current model has two bad modes:
|
||||
|
||||
- fully manual OpenBao UI work, which can unblock one credential but is slow,
|
||||
hard to review, and easy to drift from the CCR;
|
||||
- broad `platform-admin`, which is too powerful for routine automation and too
|
||||
risky to hand to agents.
|
||||
|
||||
The issue appears in multiple workstreams:
|
||||
|
||||
- `RAILIANCE-WP-0005` token-grant apply failed on
|
||||
`sys/policies/acl/credential-broker-warden-sign-issuer`;
|
||||
- `RAILIANCE-WP-0007` whynot-design CCR apply failed on
|
||||
`sys/policies/acl/workload-kv-read-whynot-design-npm-publish`.
|
||||
|
||||
Both are approved non-secret metadata changes. They should not require a human
|
||||
to hand-type OpenBao policy and auth-role writes once review is complete.
|
||||
|
||||
## Direction
|
||||
|
||||
Add one or more constrained OpenBao applier identities that can apply only
|
||||
reviewed, generated metadata for approved change classes.
|
||||
|
||||
The applier must not be a general `platform-admin` replacement. It should:
|
||||
|
||||
- verify a resolved State Hub decision or CCR status before live mutation;
|
||||
- write only allowed policy names and auth role prefixes;
|
||||
- never read or print secret values;
|
||||
- record non-secret apply evidence;
|
||||
- keep production secret value provisioning under approved operator custody
|
||||
until a separate wrapped or dual-control flow is approved.
|
||||
|
||||
## Environment Model
|
||||
|
||||
Build and development:
|
||||
|
||||
- automation may apply approved sandbox metadata;
|
||||
- generated test secrets may be allowed only in non-production mounts;
|
||||
- approvals can be lightweight but still recorded.
|
||||
|
||||
Test and staging:
|
||||
|
||||
- automation may apply approved metadata after validation and owner review;
|
||||
- verification must include positive and negative access checks;
|
||||
- secret values should use wrapped delivery or operator custody depending on
|
||||
risk classification.
|
||||
|
||||
Production:
|
||||
|
||||
- automation may apply only approved non-secret metadata such as narrow ACL
|
||||
policies and auth roles;
|
||||
- production secret values remain out-of-band operator custody unless a later
|
||||
workplan creates a stronger wrapped or dual-control provisioning path;
|
||||
- activation requires verification evidence before ops-warden or another front
|
||||
door becomes resolvable.
|
||||
|
||||
## Proposed Policy Shape
|
||||
|
||||
Start with one production candidate policy, for example
|
||||
`credential-change-prod-applier`, and keep it intentionally narrow:
|
||||
|
||||
- allow `create`, `update`, and `read` on `sys/policies/acl/workload-kv-read-*`;
|
||||
- allow `create`, `update`, and `read` on approved credential-broker issuer
|
||||
policy names such as `credential-broker-*-issuer`;
|
||||
- allow `create`, `update`, and `read` on selected auth role prefixes such as
|
||||
`auth/netkingdom/role/*` with local dry-run role-name constraints,
|
||||
`auth/kubernetes/role/*`, and `auth/token/roles/credential-broker-*`;
|
||||
- allow read/list only where needed for idempotent verification;
|
||||
- deny broad `sys/*`, `auth/*`, `platform/*`, `identity/*`, `root`, and
|
||||
`platform-admin` semantics.
|
||||
|
||||
Policy-name and role-name restrictions should be enforced in both OpenBao ACLs
|
||||
and the local applier script.
|
||||
|
||||
## Tasks
|
||||
|
||||
## T01 - Specify delegated applier policy boundaries
|
||||
|
||||
```task
|
||||
id: RPF-WP-0002-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "914a31ae-9fbf-5c8d-a5df-cc5a3c4633e3"
|
||||
```
|
||||
|
||||
Define build, test, and production applier capabilities, including exact
|
||||
OpenBao paths, allowed name prefixes, denied paths, and required audit evidence.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- A human reviewer can see which OpenBao paths each environment can mutate.
|
||||
- Production applier policy excludes secret value reads and broad admin paths.
|
||||
- The proposal covers both workload KV read lanes and credential broker issuer
|
||||
policies.
|
||||
|
||||
**2026-06-29:** Added `docs/openbao-approved-automation-delegation.md` and
|
||||
`openbao/policies/credential-change-prod-applier.hcl`. The document defines
|
||||
build/development, test/staging, and production boundaries, the allowed
|
||||
production metadata mutation surface, denied secret/admin paths, and required
|
||||
non-secret evidence. The production policy candidate allows only reviewed
|
||||
metadata writes for workload KV read policies, credential-broker issuer
|
||||
policies, approved auth-role prefixes, and self capability checks; it does not
|
||||
grant secret value reads or writes.
|
||||
|
||||
## T02 - Implement a CCR-aware applier dry-run
|
||||
|
||||
```task
|
||||
id: RPF-WP-0002-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d02dd668-e75d-59b3-a1db-5c0e5b8ce301"
|
||||
```
|
||||
|
||||
Extend the credential-change tooling so a proposed applier can validate a CCR,
|
||||
check approval state, render the exact mutations, and refuse any out-of-policy
|
||||
policy name, auth role, mount, path, or environment.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Dry-run succeeds for `CCR-2026-0001`.
|
||||
- Dry-run refuses unapproved CCRs.
|
||||
- Dry-run refuses attempts to create `root`, `platform-admin`, wildcard, or
|
||||
unrelated policy names.
|
||||
|
||||
**2026-06-29:** Added `scripts/credential-change.py applier-dry-run <CCR>` and
|
||||
Make target `credential-change-applier-dry-run`. The dry-run validates the CCR,
|
||||
requires approved/applied/verified/active status, requires confirmed auth
|
||||
bindings, verifies the OpenBao mount/path/policy/role stay inside the delegated
|
||||
metadata surface, compares the policy artifact to the generated CCR policy body,
|
||||
and renders only policy/auth-role mutations. It explicitly leaves secret value
|
||||
writes, secret reads, and front-door activation out of scope. Unit tests cover
|
||||
the active whynot-design CCR success path, unapproved CCR refusal, and rejection
|
||||
of `platform-admin`/out-of-scope mount and path attempts. `make
|
||||
credential-tests` passed with 28 tests.
|
||||
|
||||
## T03 - Add non-production applier role first
|
||||
|
||||
```task
|
||||
id: RPF-WP-0002-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "945a2847-ceaa-5bba-ab2b-29b4d90abac7"
|
||||
```
|
||||
|
||||
Create a build/test applier identity and prove it can apply approved metadata in
|
||||
a non-production lane without gaining unrelated OpenBao permissions.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Apply succeeds in a non-production mount or namespace.
|
||||
- Negative checks prove unrelated policy/auth/secret paths are denied.
|
||||
- Evidence is recorded without secret values.
|
||||
|
||||
**2026-06-30:** Added the non-production metadata-only policy candidate
|
||||
`openbao/policies/credential-change-nonprod-applier.hcl` and documented that
|
||||
generated test-secret paths require separate CCR-backed approval. Live non-prod
|
||||
identity creation and positive/negative OpenBao evidence remain to close this
|
||||
task.
|
||||
|
||||
**2026-06-30:** Added the guarded `applier-apply` execution path that reuses the
|
||||
CCR dry-run guardrails, requires exact `DELEGATED APPLY <CCR-ID>` confirmation,
|
||||
uses the local `bao` CLI with ambient delegated applier authority, writes only
|
||||
policy/auth-role metadata, and records non-secret `delegated_metadata_apply`
|
||||
evidence. Non-production task closure still needs a live build/test applier
|
||||
identity plus positive and negative capability evidence.
|
||||
|
||||
**2026-06-30:** Added `scripts/openbao-apply-credential-change-appliers.py` and
|
||||
Make target `openbao-credential-change-appliers-dry-run` to install/dry-run the
|
||||
non-production applier policy plus bounded `auth/token/roles/credential-change-
|
||||
nonprod-applier` role. The token role allows only the matching applier policy,
|
||||
disallows `root` and `platform-admin`, disables the default policy, and does not
|
||||
issue tokens by itself. Live non-production apply and denial evidence remains
|
||||
the closeout gate.
|
||||
|
||||
**2026-07-01:** Applied the updated non-production metadata-only policy
|
||||
and bounded `auth/token/roles/credential-change-nonprod-applier` role to live
|
||||
OpenBao. The role attaches only `credential-change-nonprod-applier`, disables
|
||||
the default policy, and disallows `root` / `platform-admin`; T03 remains open
|
||||
until a non-production lane apply and denial probe are recorded.
|
||||
|
||||
## T04 - Add production metadata applier with human approval gate
|
||||
|
||||
```task
|
||||
id: RPF-WP-0002-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "493744db-445d-546f-82ea-2dee4bc72214"
|
||||
```
|
||||
|
||||
Create the production metadata applier path and require a resolved CCR/State Hub
|
||||
approval before mutation.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Approved `CCR-2026-0001` metadata can be applied without `platform-admin`.
|
||||
- Unapproved CCRs fail closed.
|
||||
- Secret value provisioning is still not automated in production.
|
||||
|
||||
**2026-06-30:** Strengthened the production gate by adding source-artifact
|
||||
checks to the CCR applier dry-run and documenting that unapproved CCRs fail
|
||||
closed before OpenBao mutation rendering. The production policy candidate exists
|
||||
and remains metadata-only; live delegated identity creation/application evidence
|
||||
still needs an operator-held OpenBao step.
|
||||
|
||||
**2026-06-30:** Added `applier-apply` and Make targets
|
||||
`credential-change-applier-apply-plan` / `credential-change-applier-apply`. The
|
||||
command fails closed for unapproved CCRs, renders the dry-run payload before
|
||||
mutation, requires exact confirmation, does not accept tokens in argv, leaves
|
||||
secret values out of scope, and appends State Hub/file-backed non-secret apply
|
||||
evidence when requested. Production closure still requires live execution using
|
||||
the constrained applier identity rather than broad `platform-admin`.
|
||||
|
||||
**2026-06-30:** Added `scripts/openbao-apply-credential-change-appliers.py` and
|
||||
Make targets `openbao-credential-change-appliers-dry-run` /
|
||||
`openbao-configure-credential-change-appliers` to configure the production
|
||||
`credential-change-prod-applier` policy and bounded token role. The role allows
|
||||
only `credential-change-prod-applier`, disallows `root` and `platform-admin`,
|
||||
uses service tokens, disables default policy attachment, and keeps token issuance
|
||||
outside the setup script. Production closure still needs a live run and
|
||||
capability evidence using this constrained identity.
|
||||
|
||||
**2026-07-01:** Updated the delegated applier ACLs to use the OpenBao-matchable
|
||||
`auth/netkingdom/role/*` path while keeping role-name and bound-claim
|
||||
constraints in the local CCR dry-run. Applied the live prod/nonprod applier
|
||||
policies and token roles, then issued a 15-minute
|
||||
`credential-change-prod-applier` child token and used it to run
|
||||
`scripts/credential-change.py applier-apply CCR-2026-0001`. The delegated
|
||||
run wrote the workload KV policy and OIDC role metadata without
|
||||
`platform-admin`. A `sys/capabilities-self` probe on
|
||||
`platform/data/workloads/coulomb/whynot-design/npm-publish` returned
|
||||
`deny`, and the matching short-lived child token accessor was revoked.
|
||||
|
||||
## T05 - Close the whynot-design pilot
|
||||
|
||||
```task
|
||||
id: RPF-WP-0002-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b5959c20-7ac7-53a8-ba0d-ee569c122a4f"
|
||||
```
|
||||
|
||||
Use the delegated production metadata applier to finish the whynot-design npm
|
||||
publish token lane after the actual token is provisioned through approved
|
||||
custody.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Policy and auth role are applied by the delegated applier.
|
||||
- `NPM_AUTH_TOKEN` is provisioned through approved custody.
|
||||
- Positive and negative verification pass without printing the token.
|
||||
- `CCR-2026-0001` can move to `active`.
|
||||
- ops-warden can mark `whynot-design-npm-publish` ready/resolvable.
|
||||
|
||||
**2026-07-01:** Closed the whynot-design pilot. `CCR-2026-0001` is
|
||||
active, the front-door metadata is ready/resolvable, prior approved-custody
|
||||
provisioning plus positive and negative verification are recorded without
|
||||
secret values, and the delegated prod applier evidence is now recorded on the
|
||||
CCR.
|
||||
|
||||
## Exit Criteria
|
||||
|
||||
- Routine approved OpenBao metadata changes no longer require broad
|
||||
`platform-admin`.
|
||||
- Production automation cannot read or exfiltrate managed secret values.
|
||||
- Build, test, and production each have distinct, documented security
|
||||
requirements.
|
||||
- CCR approval, apply, verification, and front-door activation form one
|
||||
reviewable chain.
|
||||
|
||||
|
||||
## Completion 2026-07-02 — T03 live probe and workplan finish
|
||||
|
||||
T03 closed with live positive and negative evidence from a
|
||||
`credential-change-nonprod-applier` child token (accessor
|
||||
`pCznHtid1O0vy36QHqMbzu5Y`, revoked after use):
|
||||
|
||||
- allowed: `policy_write workload-kv-read-nonprod-probe-test` (test artifact
|
||||
deleted afterwards by the operator session) and `policy_read
|
||||
workload-kv-read-issue-core-runtime`;
|
||||
- denied: `policy_read platform-admin`, out-of-pattern `policy_write
|
||||
evil-probe-test`, KV secret read on the issue-core path, and
|
||||
`auth/token/roles/credential-change-nonprod-applier` write;
|
||||
- all recorded in `/openbao/audit/openbao-audit.log` (2026-07-02T10:09Z
|
||||
window).
|
||||
|
||||
The production applier path was proven the same day: both `CCR-2026-0002`
|
||||
and `CCR-2026-0003` were applied with a `credential-change-prod-applier`
|
||||
child token holding only that policy — no `platform-admin` handoff. All
|
||||
tasks are done; the workplan is finished.
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
---
|
||||
id: RPF-WP-0003
|
||||
type: workplan
|
||||
title: "Issue-Core Runtime Ingestion Credential Lane"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 9
|
||||
created: "2026-06-29"
|
||||
updated: "2026-07-02"
|
||||
depends_on_workplans:
|
||||
- RAIL-PL-WP-0002
|
||||
- RAILIANCE-WP-0004
|
||||
- RAILIANCE-WP-0007
|
||||
- RAILIANCE-WP-0008
|
||||
related_state_hub_messages:
|
||||
- "f76d3a9e-a98f-4081-885d-b79d94312699"
|
||||
related_ccrs:
|
||||
- CCR-2026-0002
|
||||
state_hub_workstream_id: "5fb6b6a7-3a40-5658-9804-21c0928c6dd9"
|
||||
---
|
||||
|
||||
# RPF-WP-0003 - Issue-Core Runtime Ingestion Credential Lane
|
||||
|
||||
## Goal
|
||||
|
||||
Promote the draft `issue-core-ingestion-api-key` access lane from a proposed
|
||||
CCR to a reviewed, least-privilege, verified OpenBao workload KV lane that
|
||||
`issue-core` can consume through External Secrets and that `ops-warden` can
|
||||
reference without holding secret values.
|
||||
|
||||
This follows the same platform pattern proven by `RAILIANCE-WP-0006`, but keeps
|
||||
the issue-core lane independent so the field set, service-account binding,
|
||||
verification evidence, and activation decision can be reviewed on their own.
|
||||
|
||||
No task in this workplan may paste, commit, log, or send secret values through
|
||||
Git, State Hub, chat, prompts, shell history, or workplan text.
|
||||
|
||||
## Suggestion Reviewed
|
||||
|
||||
Ops-warden confirmed the whynot-design lane in State Hub message
|
||||
`f76d3a9e-a98f-4081-885d-b79d94312699` and noted that
|
||||
`issue-core-ingestion-api-key` remains draft on its side. The repo already has
|
||||
the proposed non-secret CCR:
|
||||
|
||||
- `credential-change-requests/CCR-2026-0002-issue-core-ingestion-api-key.yaml`
|
||||
|
||||
## INTENT Fit
|
||||
|
||||
This work belongs in railiance-platform because it provides shared, secure,
|
||||
operable secret custody and delivery behind stable interfaces. It does not add
|
||||
issue-core application behavior. The platform-owned output is the OpenBao path,
|
||||
read policy, Kubernetes auth role, External Secrets contract, verification
|
||||
evidence, and ops-warden handoff.
|
||||
|
||||
The plan supports these `INTENT.md` principles:
|
||||
|
||||
- secure custody: secret values stay in OpenBao/operator custody;
|
||||
- stable interfaces: issue-core consumes a documented path, fields, role, and
|
||||
External Secrets target rather than internal OpenBao topology;
|
||||
- operable and observable: activation requires positive and negative checks
|
||||
plus non-secret audit evidence;
|
||||
- independently evolvable: the credential store, auth role, and front door can
|
||||
change underneath the consumer contract.
|
||||
|
||||
## Proposed Contract
|
||||
|
||||
| Item | Proposed value |
|
||||
| --- | --- |
|
||||
| CCR | `CCR-2026-0002` |
|
||||
| ops-warden catalog id | `issue-core-ingestion-api-key` |
|
||||
| Tenant/org | `issue-core` |
|
||||
| Workload/project | `issue-core` |
|
||||
| KV mount | `platform` |
|
||||
| OpenBao CLI path | `platform/workloads/issue-core/issue-core/issue-core-runtime` |
|
||||
| Secret fields | `ISSUE_CORE_API_KEY`, pending decision on `GITEA_BACKEND_TOKEN` |
|
||||
| Read policy | `workload-kv-read-issue-core-runtime` |
|
||||
| Policy file | `openbao/policies/workload-kv-read-issue-core-runtime.hcl` |
|
||||
| Auth method | Kubernetes auth |
|
||||
| Auth role | `external-secrets-issue-core` |
|
||||
| OpenBao auth service account | `external-secrets` |
|
||||
| OpenBao auth namespace | `external-secrets` |
|
||||
| Delivery surface | `ExternalSecret issue-core/issue-core-runtime` to Secret `issue-core-runtime` |
|
||||
| ops-warden command | `warden access issue-core-ingestion-api-key --fetch ISSUE_CORE_API_KEY` |
|
||||
|
||||
The `GITEA_BACKEND_TOKEN` field remains an explicit review point. Remove it
|
||||
from the CCR before approval if issue-core no longer needs it in this lane.
|
||||
|
||||
## Tasks
|
||||
|
||||
## T01 - Review CCR scope and field set
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a4675954-898a-5b9c-b549-06c5a4bb2afe"
|
||||
```
|
||||
|
||||
Review `CCR-2026-0002` with the platform operator and issue-core owner before
|
||||
any live OpenBao apply.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The issue-core owner confirms whether `GITEA_BACKEND_TOKEN` belongs in this
|
||||
lane or should be removed before approval.
|
||||
- The approved field set is limited to runtime ingestion credentials needed by
|
||||
issue-core.
|
||||
- Review comments and approval state are recorded in the CCR without secret
|
||||
values.
|
||||
- The lane remains clearly platform-owned secret custody, not issue-core
|
||||
application logic.
|
||||
|
||||
**2026-06-30:** Live cluster metadata confirms
|
||||
`ExternalSecret issue-core/issue-core-runtime` is `Ready=True` with reason
|
||||
`SecretSynced` and maps both `ISSUE_CORE_API_KEY` and `GITEA_BACKEND_TOKEN` from
|
||||
`platform/workloads/issue-core/issue-core/issue-core-runtime`. Retain both
|
||||
fields in `CCR-2026-0002` unless the issue-core owner later removes one through
|
||||
review. The CCR remains `proposed`; this task records non-secret scope review,
|
||||
not approval to apply.
|
||||
|
||||
## T02 - Confirm Kubernetes auth and External Secrets binding
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8c938e3e-3302-5f1f-a422-03dd7eca7ed1"
|
||||
```
|
||||
|
||||
Confirm the exact Kubernetes service account, namespace, and External Secrets
|
||||
target that should consume this lane.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The service account and namespace are confirmed as `issue-core`/`issue-core`
|
||||
or the CCR is updated with the approved alternative.
|
||||
- The auth role binds only the approved service account and namespace.
|
||||
- The External Secrets target and expected field names are documented.
|
||||
- No direct human or agent read path is activated unless separately approved.
|
||||
|
||||
**2026-06-30:** Confirmed the current delivery path uses the platform External
|
||||
Secrets operator, not a workload pod service account. The `issue-core`
|
||||
Deployment uses the `default` service account, and no `issue-core` service
|
||||
account exists. `ClusterSecretStore/openbao` authenticates to OpenBao as
|
||||
`external-secrets/external-secrets` with role `external-secrets-issue-core` and
|
||||
is limited to the `issue-core` namespace. Updated `CCR-2026-0002` to this
|
||||
confirmed auth subject while keeping the exact
|
||||
`workload-kv-read-issue-core-runtime` policy. `credential-change.py
|
||||
applier-dry-run CCR-2026-0002` now blocks only because the CCR is still
|
||||
`proposed`.
|
||||
|
||||
## T03 - Apply or confirm least-privilege OpenBao metadata
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b0fd87d6-9150-5607-8102-411d0a373e1b"
|
||||
```
|
||||
|
||||
Apply the read policy and Kubernetes auth role only after review and binding
|
||||
confirmation.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- `openbao/policies/workload-kv-read-issue-core-runtime.hcl` grants only read
|
||||
access to the exact KV-v2 data and metadata paths.
|
||||
- The Kubernetes auth role attaches only
|
||||
`workload-kv-read-issue-core-runtime`.
|
||||
- Live apply uses an approved operator path or the delegated applier from
|
||||
`RAILIANCE-WP-0008`; broad `platform-admin` handoffs are avoided where
|
||||
possible.
|
||||
- Apply evidence records only policy name, role name, actor, timestamp, and
|
||||
non-secret OpenBao request ids.
|
||||
|
||||
## T04 - Provision values through approved custody
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8b2d803d-7165-58c4-b9ce-95d45273b8fb"
|
||||
```
|
||||
|
||||
Have an approved operator create or confirm the OpenBao KV entry and fields.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The path exists at
|
||||
`platform/workloads/issue-core/issue-core/issue-core-runtime`.
|
||||
- Approved fields are present with the exact reviewed names.
|
||||
- Values are entered directly through OpenBao/operator custody, never through
|
||||
Git, State Hub, chat, prompts, workplans, or shell history.
|
||||
- Non-secret evidence records only path, field names, actor, timestamp, and
|
||||
verification result.
|
||||
|
||||
## T05 - Verify positive and negative access
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "83c98191-b9eb-5189-9aa7-06cb58424f95"
|
||||
```
|
||||
|
||||
Prove that the approved issue-core identity can consume the lane and that other
|
||||
identities cannot.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Positive verification shows the approved issue-core service account can read
|
||||
the configured fields through OpenBao or External Secrets without printing
|
||||
values.
|
||||
- Negative verification shows an unapproved service account cannot read the
|
||||
path.
|
||||
- OpenBao audit evidence exists for allowed and denied attempts, recorded only
|
||||
as non-secret request ids or timestamps.
|
||||
- Verification includes the External Secrets delivery path if that is the
|
||||
production consumer interface.
|
||||
|
||||
## T06 - Activate ops-warden catalog front door
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "f8a321d1-e898-5a96-b4c5-b025739e5d9c"
|
||||
```
|
||||
|
||||
Send ops-warden the non-secret pointers needed to promote
|
||||
`issue-core-ingestion-api-key` from draft to active.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The handoff includes only catalog id, mount, path, field names, auth role,
|
||||
policy name/path, External Secrets target, optional flex-auth ref, and
|
||||
runbook/workplan links.
|
||||
- ops-warden confirms the catalog entry has no unresolved placeholders.
|
||||
- ops-warden confirms it proxies access as the caller and holds no secret
|
||||
value.
|
||||
- The CCR front-door readiness becomes active/resolvable only after positive
|
||||
and negative verification.
|
||||
|
||||
**2026-07-02:** T06 done. ops-warden promoted catalog id
|
||||
`issue-core-ingestion-api-key` from draft to active (ops-warden commit
|
||||
`364eb7d`) following its own promotion checklist: concrete zero-placeholder
|
||||
handoff (`warden route show issue-core-ingestion-api-key --json` reports
|
||||
`status: active`, `resolvable: true`), playbook gate marked met, draft tables
|
||||
updated, routing tests passing (45/45). The entry carries pointers only —
|
||||
ops-warden proxies reads as the caller and holds no secret value.
|
||||
`CCR-2026-0002` recorded the `frontdoor_activation` evidence and moved to
|
||||
`status: active` with `readiness: ready`. Promotion happened only after the
|
||||
2026-07-02 positive/negative verification.
|
||||
|
||||
## T07 - Record lifecycle operations
|
||||
|
||||
```task
|
||||
id: RPF-WP-0003-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "cac50ef4-7236-5218-8882-c9e5cc1f772f"
|
||||
```
|
||||
|
||||
Document how to deactivate, rotate, and respond to compromise for this lane.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Deactivation disables the ops-warden front door and removes or detaches the
|
||||
auth role policy without deleting required audit evidence.
|
||||
- Rotation keeps values inside OpenBao/operator custody and records only
|
||||
non-secret evidence.
|
||||
- Compromise response names the immediate front-door disable, affected field
|
||||
rotation, and follow-up incident workplan path.
|
||||
|
||||
## Exit Criteria
|
||||
|
||||
- `CCR-2026-0002` is reviewed, approved, applied, verified, and active.
|
||||
- issue-core can consume the required runtime ingestion credential through the
|
||||
approved platform interface.
|
||||
- Unauthorized access is denied and recorded.
|
||||
- ops-warden can resolve `issue-core-ingestion-api-key` without storing the
|
||||
value.
|
||||
- No secret values appear in Git, State Hub, chat, prompts, logs, or workplans.
|
||||
|
||||
|
||||
## Progress 2026-07-02 — approval, apply, verification
|
||||
|
||||
`CCR-2026-0002` approved by bernd.worsch (both required approver roles) with
|
||||
the field-set decision to keep `ISSUE_CORE_API_KEY` and `GITEA_BACKEND_TOKEN`.
|
||||
|
||||
- T03 done: policy `workload-kv-read-issue-core-runtime` and kubernetes auth
|
||||
role applied via the constrained `credential-change-prod-applier` child
|
||||
token (accessor revoked after use); State Hub apply evidence `4a66c84f`.
|
||||
- T04 done: KV entry exists at the approved path (metadata `current_version
|
||||
2`, created 2026-06-25); values were provisioned through operator custody.
|
||||
- T05 done: positive = ExternalSecret `issue-core/issue-core-runtime`
|
||||
Ready=True/SecretSynced (refresh 2026-07-02T09:42Z); negative =
|
||||
default-policy token denied on the KV data path (2026-07-02T10:08Z, probe
|
||||
accessor revoked); both recorded in the file audit device
|
||||
`/openbao/audit/openbao-audit.log`.
|
||||
- T06 progress: front-door handoff sent to ops-warden (State Hub message
|
||||
`5d47caaa-dd3f-496f-94ba-a488722f8d82`); waiting on catalog confirmation.
|
||||
|
||||
|
||||
## T07 completed 2026-07-02
|
||||
|
||||
Lifecycle operations documented in
|
||||
`docs/credential-lane-lifecycle-runbook.md`: the canonical per-action
|
||||
procedure is generated by `scripts/credential-change.py lifecycle-plan
|
||||
<CCR> --action {deactivate|rotate|compromise}`, and the runbook adds the
|
||||
lane-specific consumer facts (materialized-Secret persistence, second
|
||||
consumers, restart requirements, provider-side revocation for the OpenRouter
|
||||
key) plus the post-rotate verification contract. Front-door disable comes
|
||||
first in every action; audit evidence is never deleted; values stay in
|
||||
OpenBao/operator custody.
|
||||
|
|
@ -0,0 +1,417 @@
|
|||
---
|
||||
id: RPF-WP-0004
|
||||
type: workplan
|
||||
title: "llm-connect OpenRouter Provider Key Lane"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
planning_priority: high
|
||||
planning_order: 10
|
||||
created: "2026-06-29"
|
||||
updated: "2026-08-21"
|
||||
depends_on_workplans:
|
||||
- RAIL-PL-WP-0002
|
||||
- RAILIANCE-WP-0004
|
||||
- RAILIANCE-WP-0007
|
||||
- RAILIANCE-WP-0008
|
||||
related_state_hub_messages:
|
||||
- "f76d3a9e-a98f-4081-885d-b79d94312699"
|
||||
related_ccrs:
|
||||
- CCR-2026-0003
|
||||
state_hub_workstream_id: "afc66064-7ba4-5f11-b61f-d76890244b7e"
|
||||
---
|
||||
|
||||
# RPF-WP-0004 - llm-connect OpenRouter Provider Key Lane
|
||||
|
||||
## Goal
|
||||
|
||||
Promote the draft llm-connect OpenRouter provider-key access lane from a
|
||||
proposed CCR to a reviewed, least-privilege, verified OpenBao workload KV lane
|
||||
that the live llm-connect runtime can consume through External Secrets and that
|
||||
`ops-warden` can reference without holding the provider key.
|
||||
|
||||
This keeps provider credential custody in the shared platform layer while
|
||||
leaving llm-connect behavior, model routing, and provider-specific runtime
|
||||
logic with the owning application/service.
|
||||
|
||||
No task in this workplan may paste, commit, log, or send secret values through
|
||||
Git, State Hub, chat, prompts, shell history, or workplan text.
|
||||
|
||||
## Suggestion Reviewed
|
||||
|
||||
Ops-warden confirmed the whynot-design lane in State Hub message
|
||||
`f76d3a9e-a98f-4081-885d-b79d94312699` and noted that the OpenRouter/llm-connect
|
||||
sibling lane remains draft on its side. The repo already has the proposed
|
||||
non-secret CCR:
|
||||
|
||||
- `credential-change-requests/CCR-2026-0003-llm-connect-openrouter-api-key.yaml`
|
||||
|
||||
Ops-warden already uses `openrouter-llm-connect` as the canonical draft
|
||||
catalog id in its routing catalog and playbook. This workplan and
|
||||
`CCR-2026-0003` now align to that selector so automated callers have
|
||||
one stable route name before activation.
|
||||
|
||||
## INTENT Fit
|
||||
|
||||
This work belongs in railiance-platform because it provides the dependable
|
||||
secret custody and delivery substrate for a shared runtime service. It does not
|
||||
decide which model or provider llm-connect should use. The platform-owned
|
||||
output is the OpenBao path, read policy, Kubernetes auth role, External Secrets
|
||||
target, verification evidence, and ops-warden handoff.
|
||||
|
||||
The plan supports these `INTENT.md` principles:
|
||||
|
||||
- secure custody: the provider key stays in OpenBao/operator custody;
|
||||
- stable interfaces: llm-connect consumes a documented path, field, role, and
|
||||
External Secrets target;
|
||||
- operable and observable: activation requires positive and negative checks
|
||||
plus non-secret audit evidence;
|
||||
- independently evolvable: the provider key storage and front-door routing can
|
||||
change without forcing runtime consumers to know internal topology.
|
||||
|
||||
## Proposed Contract
|
||||
|
||||
| Item | Proposed value |
|
||||
| --- | --- |
|
||||
| CCR | `CCR-2026-0003` |
|
||||
| ops-warden catalog id | `openrouter-llm-connect` |
|
||||
| Tenant/org | `activity-core` |
|
||||
| Workload/project | `llm-connect` |
|
||||
| KV mount | `platform` |
|
||||
| OpenBao CLI path | `platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets` |
|
||||
| Secret field | `OPENROUTER_API_KEY` |
|
||||
| Read policy | `workload-kv-read-llm-connect-provider-secrets` |
|
||||
| Policy file | `openbao/policies/workload-kv-read-llm-connect-provider-secrets.hcl` |
|
||||
| Auth method | Kubernetes auth |
|
||||
| Auth role | `external-secrets-activity-core` |
|
||||
| OpenBao auth service account | `external-secrets` |
|
||||
| OpenBao auth namespace | `external-secrets` |
|
||||
| Delivery surface | Future activity-core ExternalSecret to Secret `llm-connect-provider-secrets` |
|
||||
| ops-warden command | `warden access openrouter-llm-connect --fetch OPENROUTER_API_KEY` |
|
||||
|
||||
## Tasks
|
||||
|
||||
## T01 - Review CCR scope and selector naming
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b635b254-e24d-5f34-b5d9-06ca167765e8"
|
||||
```
|
||||
|
||||
Review `CCR-2026-0003` with the platform operator and activity-core owner
|
||||
before any live OpenBao apply.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The activity-core owner confirms that llm-connect should receive
|
||||
`OPENROUTER_API_KEY` through this platform lane.
|
||||
- ops-warden and railiance-platform agree on one stable catalog id/selector:
|
||||
`openrouter-llm-connect`.
|
||||
- Review comments and approval state are recorded in the CCR without secret
|
||||
values.
|
||||
- The lane remains clearly platform-owned secret custody, not llm-connect model
|
||||
routing or provider selection logic.
|
||||
|
||||
**2026-06-30:** Confirmed `activity-core` namespace exists and Kubernetes Secret
|
||||
`activity-core/llm-connect-provider-secrets` exists, but no activity-core
|
||||
`ExternalSecret` exists yet. Kept canonical CCR catalog id
|
||||
`llm-connect-openrouter-api-key`; ops-warden previously mentioned
|
||||
`openrouter-llm-connect`, so selector agreement remains open and this task stays
|
||||
`progress`. OpenBao public seal status now reports `sealed=false`; the prior
|
||||
sealed message is no longer the active blocker.
|
||||
|
||||
**2026-07-01:** Resolved the selector naming ambiguity in favor of ops-warden
|
||||
canon. The local ops-warden routing catalog and playbook define
|
||||
`openrouter-llm-connect` as the draft OpenRouter/llm-connect route, so
|
||||
`CCR-2026-0003` and this workplan now use that catalog id and command
|
||||
shape. T01 remains `progress` until activity-core/platform approval moves
|
||||
the CCR out of `proposed`.
|
||||
|
||||
## T02 - Confirm Kubernetes auth and External Secrets binding
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "c692c020-6705-55c4-9a80-358f83fc67f8"
|
||||
```
|
||||
|
||||
Confirm the exact Kubernetes service account, namespace, and External Secrets
|
||||
target that should consume this lane.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The service account and namespace are confirmed as
|
||||
`llm-connect`/`activity-core` or the CCR is updated with the approved
|
||||
alternative.
|
||||
- The auth role binds only the approved service account and namespace.
|
||||
- The External Secrets target is confirmed as
|
||||
`llm-connect-provider-secrets` or updated with the approved alternative.
|
||||
- No direct human or agent read path is activated unless separately approved.
|
||||
|
||||
**2026-06-30:** Confirmed the proposed `llm-connect` service account does not
|
||||
exist and the current `llm-connect` Deployment uses the namespace `default`
|
||||
service account. Updated `CCR-2026-0003` to the approved platform ESO pattern:
|
||||
OpenBao Kubernetes auth role `external-secrets-activity-core` bound to
|
||||
`external-secrets/external-secrets`. Added
|
||||
`argocd/platform-addons/openbao-secretstore/openbao-activity-core.clustersecretstore.yaml`,
|
||||
limited to the `activity-core` namespace, and Make target
|
||||
`openbao-configure-external-secrets-activity-core` for the matching OpenBao
|
||||
role/policy apply. `kubectl kustomize argocd/platform-addons/openbao-secretstore`
|
||||
renders both the existing issue-core store and the new activity-core store.
|
||||
`credential-change.py applier-dry-run CCR-2026-0003` now blocks only because the
|
||||
CCR is still `proposed`.
|
||||
|
||||
## T03 - Apply or confirm least-privilege OpenBao metadata
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "55abf986-bc9c-5025-9513-36ca0f2861d3"
|
||||
```
|
||||
|
||||
Apply the read policy and Kubernetes auth role only after review and binding
|
||||
confirmation.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- `openbao/policies/workload-kv-read-llm-connect-provider-secrets.hcl` grants
|
||||
only read access to the exact KV-v2 data and metadata paths.
|
||||
- The Kubernetes auth role attaches only
|
||||
`workload-kv-read-llm-connect-provider-secrets`.
|
||||
- Live apply uses an approved operator path or the delegated applier from
|
||||
`RAILIANCE-WP-0008`; broad `platform-admin` handoffs are avoided where
|
||||
possible.
|
||||
- Apply evidence records only policy name, role name, actor, timestamp, and
|
||||
non-secret OpenBao request ids.
|
||||
|
||||
## T04 - Provision the provider key through approved custody
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "cb1272ca-9cbc-5ca6-bf3c-af0c2c18c887"
|
||||
```
|
||||
|
||||
Have an approved operator create or confirm the OpenBao KV entry and
|
||||
`OPENROUTER_API_KEY` field.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The path exists at
|
||||
`platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets`.
|
||||
- Field `OPENROUTER_API_KEY` is present.
|
||||
- The value is entered directly through OpenBao/operator custody, never through
|
||||
Git, State Hub, chat, prompts, workplans, or shell history.
|
||||
- Non-secret evidence records only path, field name, actor, timestamp, and
|
||||
verification result.
|
||||
|
||||
## T05 - Verify positive and negative access
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "cdc65efd-a733-5a13-b439-85bc24712143"
|
||||
```
|
||||
|
||||
Prove that the approved llm-connect identity can consume the lane and that
|
||||
other identities cannot.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Positive verification shows the approved llm-connect service account can read
|
||||
`OPENROUTER_API_KEY` through OpenBao or External Secrets without printing the
|
||||
value.
|
||||
- Negative verification shows an unapproved service account cannot read the
|
||||
path.
|
||||
- OpenBao audit evidence exists for allowed and denied attempts, recorded only
|
||||
as non-secret request ids or timestamps.
|
||||
- Verification includes the External Secrets delivery path because that is the
|
||||
intended production consumer interface.
|
||||
|
||||
## T06 - Activate ops-warden catalog front door
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "83f6801c-1355-5b0f-95ba-c35f45175fff"
|
||||
```
|
||||
|
||||
Send ops-warden the non-secret pointers needed to promote the agreed
|
||||
OpenRouter/llm-connect selector from draft to active.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- The handoff includes only catalog id, mount, path, field name, auth role,
|
||||
policy name/path, External Secrets target, optional flex-auth ref, and
|
||||
runbook/workplan links.
|
||||
- ops-warden confirms the catalog entry has no unresolved placeholders.
|
||||
- ops-warden confirms it proxies access as the caller and holds no provider key
|
||||
value.
|
||||
- The CCR front-door readiness becomes active/resolvable only after positive
|
||||
and negative verification.
|
||||
|
||||
**2026-07-02:** T06 done. ops-warden promoted catalog id
|
||||
`openrouter-llm-connect` from draft to active (ops-warden commit `364eb7d`)
|
||||
following its own promotion checklist: concrete zero-placeholder handoff
|
||||
(`warden route show openrouter-llm-connect --json` reports `status: active`,
|
||||
`resolvable: true`), playbook gate marked met, draft tables updated, routing
|
||||
tests passing (45/45). The entry carries pointers only — ops-warden proxies
|
||||
reads as the caller and holds no provider key value. `CCR-2026-0003` recorded
|
||||
the `frontdoor_activation` evidence and moved to `status: active` with
|
||||
`readiness: ready`. Promotion happened only after the 2026-07-02
|
||||
positive/negative verification.
|
||||
|
||||
## T07 - Record lifecycle operations
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T07
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d9386de3-5b68-5ed2-a44b-3b21705b720f"
|
||||
```
|
||||
|
||||
Document how to deactivate, rotate, and respond to compromise for this lane.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Deactivation disables the ops-warden front door and removes or detaches the
|
||||
auth role policy without deleting required audit evidence.
|
||||
- Rotation keeps the provider key inside OpenBao/operator custody and records
|
||||
only non-secret evidence.
|
||||
- Compromise response names the immediate front-door disable, provider-key
|
||||
rotation, and follow-up incident workplan path.
|
||||
|
||||
## T08 - Reconcile the railiance01 consumer after provider 401
|
||||
|
||||
```task
|
||||
id: RPF-WP-0004-T08
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "934f7424-890a-57a7-93cd-56719f02c935"
|
||||
```
|
||||
|
||||
Restore the approved OpenBao-to-ESO delivery path for the railiance01
|
||||
llm-connect instance after its bootstrap key began returning OpenRouter 401.
|
||||
|
||||
Read-only diagnosis on 2026-08-20 found a healthy, 61-day-old Deployment using
|
||||
an unmanaged Secret created on 2026-06-19. No `ExternalSecret` exists on
|
||||
railiance01. `ClusterSecretStore/openbao-activity-core` is Valid, but its ESO
|
||||
token reports `deny` for both the canonical llm-connect data and metadata
|
||||
paths because the activity-core token bootstrap default omits
|
||||
`workload-kv-read-llm-connect-provider-secrets`.
|
||||
|
||||
Repair the durable bootstrap policy set, mint a replacement limited ESO token
|
||||
through the existing attended platform-admin handoff, apply the already
|
||||
reviewed llm-connect `ExternalSecret`, and wait for `SecretSynced=True`. Restart
|
||||
the Deployment only after sync, then run the in-cluster fixture smoke. If the
|
||||
OpenBao-delivered key still returns 401, stop and require provider-side
|
||||
rotation; do not copy or inspect either key value.
|
||||
|
||||
Done when railiance01 consumes the canonical lane, the fixture smoke passes,
|
||||
and rollback/non-secret evidence is recorded.
|
||||
|
||||
Progress 2026-08-20: repaired the durable delivery path. The activity-core ESO
|
||||
bootstrap now includes the approved exact-path llm-connect policy; a new
|
||||
periodic token was minted through the existing mode-0600 platform-admin
|
||||
handoff, and capabilities report `read` on only the requested data and metadata
|
||||
paths. The reviewed llm-connect `ExternalSecret` was applied on railiance01,
|
||||
reported `Ready=True` / `SecretSynced`, and took ownership of the one-key
|
||||
Secret. `deployment/llm-connect` rolled out successfully, and the real
|
||||
`actcore-worker` reaches its Service `/health` with `status=ok`.
|
||||
|
||||
The full fixture still returns sanitized OpenRouter HTTP 401 when run inside
|
||||
the new llm-connect pod. Therefore the canonical provider key itself is no
|
||||
longer accepted. T08 waits on an attended OpenRouter account owner to mint a
|
||||
replacement key. Keep the old key active until the new value is written from a
|
||||
mode-0600 file to the existing KV path, ESO reports a new successful refresh,
|
||||
the Deployment is restarted, and the fixture passes; then revoke the old key.
|
||||
No provider-key value was read or printed during diagnosis or repair.
|
||||
|
||||
Closure 2026-08-21: the railiance-platform portion is complete: the durable
|
||||
OpenBao-to-ESO delivery path is repaired, the `ExternalSecret` is synced, and
|
||||
the workload consumes the canonical lane. The remaining action is an attended
|
||||
replacement of a provider key rejected by OpenRouter, followed by a consumer
|
||||
fixture smoke. That operational incident is already tracked by the owning
|
||||
consumer as `ACTIVITY-WP-0031-T01`, so this duplicate task is cancelled rather
|
||||
than keeping the completed platform-lane workplan active.
|
||||
|
||||
## Exit Criteria
|
||||
|
||||
- `CCR-2026-0003` is reviewed, approved, applied, verified, and active.
|
||||
- llm-connect can consume `OPENROUTER_API_KEY` through the approved platform
|
||||
interface.
|
||||
- Unauthorized access is denied and recorded.
|
||||
- ops-warden can resolve the agreed OpenRouter/llm-connect selector without
|
||||
storing the value.
|
||||
- No secret values appear in Git, State Hub, chat, prompts, logs, or workplans.
|
||||
|
||||
|
||||
## Progress 2026-07-02 — approval and metadata apply
|
||||
|
||||
`CCR-2026-0003` approved by bernd.worsch (platform-operator +
|
||||
activity-core-owner); T01 closes on that approval with the
|
||||
`openrouter-llm-connect` selector already aligned.
|
||||
|
||||
- T03 done: policy `workload-kv-read-llm-connect-provider-secrets` and
|
||||
kubernetes auth role applied via the constrained prod-applier child token;
|
||||
State Hub apply evidence `04c70285`.
|
||||
- T04 remains the live gate: the KV entry at
|
||||
`platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets`
|
||||
does not exist yet — the operator must enter `OPENROUTER_API_KEY` through
|
||||
OpenBao custody. The activity-core namespace also has no ExternalSecret
|
||||
object for this lane yet. ops-warden checkpoint message: `6b058584`.
|
||||
|
||||
|
||||
## Progress 2026-07-02 — value provisioned, lane live end-to-end
|
||||
|
||||
- T04 done: the operator entered `OPENROUTER_API_KEY` directly through OpenBao
|
||||
custody (KV metadata: version 1, created 2026-07-02T10:18Z). The value never
|
||||
passed through Git, State Hub, chat, or agent hands.
|
||||
- T05 done: positive — new `ExternalSecret
|
||||
activity-core/llm-connect-provider-secrets` (ClusterSecretStore
|
||||
`openbao-activity-core`, creationPolicy Owner) reached `SecretSynced=True`
|
||||
at 10:54Z, took ownership of the previously manual Secret, and the
|
||||
llm-connect deployment rolled out cleanly on the OpenBao-delivered value
|
||||
(pod ready, 0 restarts, /health probes passing). Negative — default-policy
|
||||
token denied on the KV path (10:08Z probe, audit-logged). Manifest committed
|
||||
in llm-connect `dfd2ce7`
|
||||
(`deploy/k8s/activity-core-llm-connect/externalsecret.yaml`).
|
||||
- T06 progress: activation update sent to ops-warden; `openrouter-llm-connect`
|
||||
can now leave draft once the catalog confirmation lands.
|
||||
- Scope note: this closes the CoulombCore lane the CCR describes. The separate
|
||||
llm-connect instance on the railiance01 k3s cluster still consumes its
|
||||
bootstrap-provisioned Secret; migrating it is railiance01-cluster work, not
|
||||
part of CCR-2026-0003.
|
||||
|
||||
|
||||
## T07 completed 2026-07-02
|
||||
|
||||
Lifecycle operations documented in
|
||||
`docs/credential-lane-lifecycle-runbook.md`: the canonical per-action
|
||||
procedure is generated by `scripts/credential-change.py lifecycle-plan
|
||||
<CCR> --action {deactivate|rotate|compromise}`, and the runbook adds the
|
||||
lane-specific consumer facts (materialized-Secret persistence, second
|
||||
consumers, restart requirements, provider-side revocation for the OpenRouter
|
||||
key) plus the post-rotate verification contract. Front-door disable comes
|
||||
first in every action; audit evidence is never deleted; values stay in
|
||||
OpenBao/operator custody.
|
||||
|
||||
|
||||
## Recovery evidence reported 2026-09-04
|
||||
|
||||
Activity-core message `dcc0d7cc-0046-4c47-ba1c-fb1e0046e18e` supersedes
|
||||
`c32901ff-2072-4b93-81cd-db93dddfa5f3`. Owner decision
|
||||
`914e0e04-fd17-4fba-b2d5-be38f7aca185` approved intentional reuse from the
|
||||
reins provider lane into the canonical activity-core lane. Activity-core reports
|
||||
KV version 2, ESO synchronization, rollout, health and completion HTTP 200.
|
||||
This is owner-reported evidence, not an independent platform live verification;
|
||||
no further replacement was requested.
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
id: RPF-WP-0005
|
||||
type: workplan
|
||||
title: "reuse-surface Runtime Secrets OpenBao Lane"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-07"
|
||||
updated: "2026-07-07"
|
||||
depends_on_workplans:
|
||||
- RAILIANCE-WP-0007
|
||||
- RAILIANCE-WP-0008
|
||||
related_repos:
|
||||
- railiance-apps
|
||||
- reuse-surface
|
||||
- ops-warden
|
||||
state_hub_workstream_id: "7fe172fe-d987-52a0-aa36-67d6a1dd5a7c"
|
||||
---
|
||||
|
||||
# RPF-WP-0005 — reuse-surface Runtime Secrets OpenBao Lane
|
||||
|
||||
## Goal
|
||||
|
||||
Promote reuse-surface hub runtime secrets from bootstrap Kubernetes Secret
|
||||
custody to a reviewed OpenBao workload KV lane delivered by External Secrets
|
||||
Operator, matching the platform pattern used by issue-core, OpenRouter, and
|
||||
Forgejo mailer.
|
||||
|
||||
Today both secrets live in `reuse/reuse-surface-env` on Railiance01:
|
||||
|
||||
| Field | Consumer |
|
||||
| --- | --- |
|
||||
| `REUSE_SURFACE_TOKEN` | Hub write API; operators via `warden access` / kubectl |
|
||||
| `REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET` | Hub webhook receiver; Forgejo org webhook HMAC |
|
||||
|
||||
Functional custody in K8s is sufficient for production today (live since
|
||||
2026-07-07). This workplan is **hygiene and standardization**, not a blocker.
|
||||
|
||||
No task may paste, commit, log, or send secret values through Git, State Hub,
|
||||
chat, prompts, shell history, or workplan text.
|
||||
|
||||
## Proposed contract
|
||||
|
||||
| Item | Proposed value |
|
||||
| --- | --- |
|
||||
| CCR | `CCR-2026-0005` |
|
||||
| Tenant/org | `reuse` |
|
||||
| Workload | `reuse-surface` |
|
||||
| KV mount | `platform` |
|
||||
| OpenBao CLI path | `platform/workloads/reuse/reuse-surface/runtime-secrets` |
|
||||
| Secret fields | `REUSE_SURFACE_TOKEN`, `REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET` |
|
||||
| Read policy | `workload-kv-read-reuse-surface-runtime` (name TBD at CCR) |
|
||||
| K8s auth role | `external-secrets-reuse-surface` (name TBD at CCR) |
|
||||
| ExternalSecret | `reuse/reuse-surface-runtime` → target Secret `reuse-surface-env` |
|
||||
| ops-warden catalog | migrate `reuse-surface-hub-write-token` handoff to Bao path |
|
||||
|
||||
Dual-consumer note: Forgejo org webhook must be updated whenever the webhook
|
||||
HMAC rotates — document in `railiance-apps/docs/reuse-surface-on-railiance01.md`
|
||||
and keep `make reuse-forgejo-webhook` idempotent.
|
||||
|
||||
## Draft OpenBao + ESO Lane
|
||||
|
||||
```task
|
||||
id: RPF-WP-0005-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "4e7f5200-37a5-5208-b01e-a9633fb056df"
|
||||
```
|
||||
|
||||
- Draft CCR for the lane (path, fields, policy, k8s role, ESO target)
|
||||
- Align with `docs/openbao.md` path convention and
|
||||
`docs/credential-lane-lifecycle-runbook.md`
|
||||
- Negative review: no secret values in CCR or workplan text
|
||||
|
||||
**2026-07-07:** Drafted `CCR-2026-0005` and policy
|
||||
`openbao/policies/workload-kv-read-reuse-surface-runtime.hcl`. Metadata review
|
||||
confirms Railiance01 `reuse/reuse-surface-env` (two fields), ESO operator SA,
|
||||
and forgejo-style interim ClusterSecretStore delivery. CCR remains `proposed`;
|
||||
T02 blocked on platform-operator and reuse-surface-owner approval.
|
||||
|
||||
## Platform Apply And Verification
|
||||
|
||||
```task
|
||||
id: RPF-WP-0005-T02
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "01b661a1-315b-566c-ad15-00cb71640f5a"
|
||||
```
|
||||
|
||||
Blocked on CCR-2026-0005 approval.
|
||||
|
||||
- Apply OpenBao policy + Kubernetes auth role (mirror forgejo-mailer / issue-core scripts)
|
||||
- Seed path from existing cluster Secret (one-time operator step; value never logged)
|
||||
- Add `manifests/reuse-surface-runtime-externalsecret.yaml` in `railiance-apps`
|
||||
- Verify ExternalSecret `SecretSynced` and pod env injection after rollout
|
||||
- Record non-secret audit evidence (positive + negative reads)
|
||||
|
||||
**2026-07-07:** CCR-2026-0005 approved; delegated metadata apply recorded; KV path
|
||||
seeded (version 1); `openbao-reuse` ClusterSecretStore + `reuse-surface-runtime`
|
||||
ExternalSecret live on Railiance01 (`SecretSynced` 2026-07-07T20:33:17Z). Positive:
|
||||
`/v1/federated` 200, signed webhook 200. Negative: default-policy token denied on
|
||||
path. CCR status `verified`. T03 catalog migration remains open.
|
||||
|
||||
## Consumer Handoff And Catalog Migration
|
||||
|
||||
```task
|
||||
id: RPF-WP-0005-T03
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "a521036b-2858-5a42-9d23-6f142137ee6d"
|
||||
```
|
||||
|
||||
Blocked on T02 verification.
|
||||
|
||||
- Update `railiance-apps/docs/reuse-surface-on-railiance01.md` custody section
|
||||
- Update ops-warden `reuse-surface-hub-write-token` playbook + routing catalog
|
||||
(`fetch_command` → `bao kv get -field=...`)
|
||||
- Add lane to `docs/workload-kv-access-lanes.md`
|
||||
- Deprecate direct kubectl fetch as primary handoff (keep as break-glass note)
|
||||
|
||||
**2026-07-07:** ops-warden catalog `reuse-surface-hub-write-token` migrated to
|
||||
`bao kv get -field=REUSE_SURFACE_TOKEN platform/workloads/reuse/reuse-surface/runtime-secrets`
|
||||
(owner `railiance-platform`, `resolvable=true`). Playbook, CredentialRouting index,
|
||||
`docs/workload-kv-access-lanes.md`, and railiance-apps export handoff updated; kubectl
|
||||
documented as break-glass only. CCR-2026-0005 front door `ready`/`resolvable=true`.
|
||||
|
||||
## Forgejo Webhook Rotation Runbook
|
||||
|
||||
```task
|
||||
id: RPF-WP-0005-T04
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "cf1f198e-2af2-5f62-8e3b-1edfc9f537c8"
|
||||
```
|
||||
|
||||
Blocked on T03.
|
||||
|
||||
- Document rotation: update OpenBao field → ESO sync → rollout →
|
||||
`make reuse-forgejo-webhook` (updates org hook secret)
|
||||
- Add smoke: signed webhook POST returns 200/accepted or expected no-op
|
||||
|
||||
**2026-07-07:** Added `docs/reuse-surface-runtime-secrets-rotation-runbook.md`,
|
||||
CCR-2026-0005 lane in `docs/credential-lane-lifecycle-runbook.md`, and
|
||||
`railiance-apps` `make reuse-webhook-smoke` (unsigned 401, signed no-op 200,
|
||||
ESO Ready, `/v1/federated`). Live smoke passed on production.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] Both fields readable from `platform/workloads/reuse/reuse-surface/runtime-secrets`
|
||||
- [x] ESO owns `reuse-surface-env`; manual `kubectl create secret` no longer required for steady state
|
||||
- [x] `warden access reuse-surface-hub-write-token --fetch` uses OpenBao path
|
||||
- [x] Forgejo org webhook and hub HMAC aligned (smoke verifies signed/unsigned paths; rotation runbook documents reconcile step)
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
id: RPF-WP-0006
|
||||
type: workplan
|
||||
title: "rapp-openbao extraction boundary"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-25"
|
||||
updated: "2026-07-26"
|
||||
state_hub_workstream_id: "8d292bab-76dd-5ac3-b39d-6bc460ce27d7"
|
||||
---
|
||||
|
||||
# RPF-WP-0006 - rapp-openbao extraction boundary
|
||||
|
||||
## Goal
|
||||
|
||||
Prepare the first `rapp-*` extraction by separating the OpenBao workload package
|
||||
surface from the broader S3 platform ownership in `railiance-platform`.
|
||||
|
||||
This workplan follows the first-wave `rapp-*` order defined in
|
||||
`/home/worsch/railiance-master/docs/rapp-first-wave-candidates.md`.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This workplan may:
|
||||
|
||||
- identify which OpenBao assets belong to a future `rapp-openbao`
|
||||
- record which OpenBao-related concerns remain platform-owned
|
||||
- prepare the handoff contract between the future wrapper and S3 platform policy
|
||||
|
||||
It must not:
|
||||
|
||||
- weaken `railiance-platform` as the owner of secrets custody and policy
|
||||
- move shared credential lane or approval machinery into the workload wrapper
|
||||
- require a repo rename or live deployment change before the package boundary is clear
|
||||
|
||||
## T01 - Separate package assets from platform-governance assets
|
||||
|
||||
```task
|
||||
id: RPF-WP-0006-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "5c0e5411-e47a-5a90-9005-b01762351c0a"
|
||||
```
|
||||
|
||||
Classify the current OpenBao-related files into:
|
||||
|
||||
- workload package assets for `rapp-openbao`
|
||||
- shared platform governance and policy that stays in `railiance-platform`
|
||||
|
||||
Done when the distinction is written against real file paths and current usage.
|
||||
|
||||
2026-07-25: Added `docs/rapp-openbao-boundary.md` with file-path classification
|
||||
for OpenBao package assets, split-before-move assets, and retained S3
|
||||
governance material.
|
||||
|
||||
## T02 - Define the first `rapp-openbao` move set
|
||||
|
||||
```task
|
||||
id: RPF-WP-0006-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3e5f8893-d440-5ce5-a436-3f84edad2e7b"
|
||||
```
|
||||
|
||||
Prepare the first move set for the wrapper, including likely candidates such as:
|
||||
|
||||
- Helm values and middleware for the OpenBao workload
|
||||
- UI overlay wrapper assets
|
||||
- workload-specific deploy/verify scripts
|
||||
- workload-health and recovery runbooks
|
||||
|
||||
Done when the future wrapper has a concrete first file inventory.
|
||||
|
||||
2026-07-25: Recorded the first move set in
|
||||
`docs/rapp-openbao-boundary.md`, centered on Helm values, UI overlay assets,
|
||||
OpenBao deploy/verify helpers, and the matching `Makefile` targets.
|
||||
|
||||
## T03 - Record the retained S3 platform responsibilities
|
||||
|
||||
```task
|
||||
id: RPF-WP-0006-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9a6a2cd9-9306-5721-9652-85f007043c19"
|
||||
```
|
||||
|
||||
Record what must remain in `railiance-platform`, including:
|
||||
|
||||
- runtime secret custody as a platform capability
|
||||
- workload lane policy and approval flows
|
||||
- cross-workload secret delivery conventions
|
||||
- platform-wide operator guidance that is not OpenBao-package specific
|
||||
|
||||
Done when the wrapper cannot be mistaken for the new S3 ownership home.
|
||||
|
||||
2026-07-25: Recorded retained S3 responsibilities in
|
||||
`docs/rapp-openbao-boundary.md`, including platform-admin policy, workload KV
|
||||
lane governance, delegated automation, credential grants, and SSH signing.
|
||||
|
||||
## T04 - Prepare the repo-creation handoff for `rapp-openbao`
|
||||
|
||||
```task
|
||||
id: RPF-WP-0006-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "a276f76b-48a7-512c-b0f8-786225d88683"
|
||||
```
|
||||
|
||||
Blocked on T01-T03 and the creation of the future `rapp-openbao` repo.
|
||||
|
||||
Prepare the minimal handoff needed to create the wrapper repo without breaking
|
||||
current operators or losing source-of-truth clarity inside `railiance-platform`.
|
||||
|
||||
Done when the future package extraction can start from a stable boundary.
|
||||
|
||||
2026-07-26: Added `docs/rapp-openbao-compatibility-handoff.md` to define the
|
||||
current migration-window split: `rapp-openbao` is now the canonical home for
|
||||
package-owned deploy/overlay/smoke assets, while `railiance-platform` retains
|
||||
bootstrap, policy, credential-lane governance, and authenticated verification.
|
||||
`docs/rapp-openbao-boundary.md`, `docs/openbao.md`, and `SCOPE.md` now point to
|
||||
that split explicitly, so current operators can keep using temporary platform
|
||||
copies without losing source-of-truth clarity.
|
||||
|
||||
## Notes
|
||||
|
||||
This workplan is repo-local. The framework-level sequencing stays in
|
||||
`railiance-master/workplans/RMASTER-WP-0017-rail-rapp-reef-repo-separation.md`.
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
---
|
||||
id: RPF-WP-0007
|
||||
type: workplan
|
||||
title: "Forgejo admin PAT OpenBao consumer cutover"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-25"
|
||||
updated: "2026-07-26"
|
||||
related_repos:
|
||||
- activity-core
|
||||
- ops-warden
|
||||
state_hub_workstream_id: "f4fd52ba-4e84-52e7-a8d7-667b72d3cc1b"
|
||||
---
|
||||
|
||||
# RPF-WP-0007 - Forgejo admin PAT OpenBao consumer cutover
|
||||
|
||||
## Goal
|
||||
|
||||
Cut the Forgejo package-prune consumer over from workstation-local PAT handling
|
||||
to the approved OpenBao lane recorded in `CCR-2026-0006`.
|
||||
|
||||
The immediate trigger is the unread `ops-warden` coordination message from
|
||||
July 12, 2026 requesting that `tools/cmd/forgejo-package-prune` stop depending
|
||||
on `/tmp/forgejo-tegwick-api-token` as the steady-state fallback when
|
||||
`FORGEJO_ADMIN_TOKEN` is unset.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This workplan may:
|
||||
|
||||
- update the Forgejo package-prune token resolution path
|
||||
- update package-prune runbooks and operator handoff docs
|
||||
- coordinate the consumer contract with the approved credential lane
|
||||
|
||||
It must not:
|
||||
|
||||
- move platform secret-governance ownership out of `railiance-platform`
|
||||
- paste token values into Git, State Hub, chat, shell history, or logs
|
||||
- break the existing prune workflow before the replacement path is verified
|
||||
|
||||
## T01 - Inventory current consumer and fallback paths
|
||||
|
||||
```task
|
||||
id: RPF-WP-0007-T01
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "3e8ee5f4-cdca-5803-8a15-86156faf5673"
|
||||
```
|
||||
|
||||
Record where the current Forgejo admin PAT is consumed and documented, including:
|
||||
|
||||
- `scripts/forgejo_package_prune.py`
|
||||
- `tools/cmd/forgejo-package-prune`
|
||||
- `docs/forgejo-package-prune.md`
|
||||
- any activity-core automation handoff that still assumes workstation file drops
|
||||
|
||||
Done when the remaining `/tmp/forgejo-tegwick-api-token` dependency surface is explicit.
|
||||
|
||||
2026-07-26: Confirmed the remaining legacy surface in
|
||||
`scripts/forgejo_package_prune.py` and `docs/forgejo-package-prune.md`; the
|
||||
approved lane reference already lived in `CCR-2026-0006` and
|
||||
`docs/workload-kv-access-lanes.md`.
|
||||
|
||||
## T02 - Implement the approved non-file fallback path
|
||||
|
||||
```task
|
||||
id: RPF-WP-0007-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "2684056f-39a9-503a-91df-36f287fe4654"
|
||||
```
|
||||
|
||||
Change the package-prune consumer so that, when `FORGEJO_TOKEN` and
|
||||
`FORGEJO_ADMIN_TOKEN` are unset, it uses the approved OpenBao-backed access
|
||||
path rather than the workstation file as the steady-state fallback.
|
||||
|
||||
Done when the token loader prefers the approved lane and the old file drop is
|
||||
demoted to break-glass or removed if no longer needed.
|
||||
|
||||
2026-07-26: `scripts/forgejo_package_prune.py` now resolves
|
||||
`platform/workloads/forgejo/forgejo-admin` field `API_TOKEN` through `bao kv get`
|
||||
when `FORGEJO_TOKEN` and `FORGEJO_ADMIN_TOKEN` are unset. Explicit
|
||||
`FORGEJO_TOKEN_FILE` / `FORGEJO_ADMIN_TOKEN_FILE` remain supported as attended
|
||||
break-glass handoffs, and `/tmp/forgejo-tegwick-api-token` only works when
|
||||
`FORGEJO_ALLOW_LEGACY_FILE_FALLBACK=1` is set.
|
||||
|
||||
## T03 - Update operator guidance and lane references
|
||||
|
||||
```task
|
||||
id: RPF-WP-0007-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "34ecd9c9-486f-5509-bb74-6836d3515100"
|
||||
```
|
||||
|
||||
Refresh the operator docs so they align with `CCR-2026-0006`, the routing
|
||||
catalog, and the final consumer behavior.
|
||||
|
||||
Done when the package-prune runbook no longer presents the workstation file as
|
||||
the primary path.
|
||||
|
||||
2026-07-26: Updated `docs/forgejo-package-prune.md` so the primary operator path
|
||||
is `warden plan` + `bao login` against `forgejo-admin-workload-kv-read`; the
|
||||
retired `/tmp` drop is now documented as legacy unwind only, with explicit
|
||||
break-glass env/file overrides kept for attended sessions.
|
||||
|
||||
## T04 - Verify prune workflow and close the inbox request
|
||||
|
||||
```task
|
||||
id: RPF-WP-0007-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "90355dee-66dd-593f-9444-a42ff15f2398"
|
||||
```
|
||||
|
||||
Blocked on T01-T03.
|
||||
|
||||
Verify the consumer cutover with a non-secret dry-run and close the originating
|
||||
coordination loop from `ops-warden`.
|
||||
|
||||
Done when the replacement path is verified and the old unread message has a
|
||||
clear repo-local follow-up trail.
|
||||
|
||||
2026-07-26: Added focused token-resolution coverage in
|
||||
`tests/test_forgejo_package_prune.py` for direct env, explicit file overrides,
|
||||
OpenBao fallback, legacy-file gating, and operator-facing failure text. This
|
||||
closes the `ops-warden` coordination loop triggered by message
|
||||
`5be8e500-ebf5-405b-9aec-c902353ae719`; the repo-local follow-up trail is now in
|
||||
this workplan, the prune runbook, and the loader implementation.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] `forgejo-package-prune` no longer defaults to `/tmp/forgejo-tegwick-api-token`
|
||||
- [x] The steady-state fallback path reads the approved OpenBao lane from `CCR-2026-0006`
|
||||
- [x] Operator docs present OpenBao / `warden` routing as the primary path
|
||||
- [x] Repo-local tests cover the new token-resolution behavior without reading secret values
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
---
|
||||
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.
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
---
|
||||
id: RPF-WP-0009
|
||||
type: workplan
|
||||
title: "Platform rapp consistency and deployment-management contract"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-13"
|
||||
related_repos:
|
||||
- railiance-master
|
||||
- the-custodian
|
||||
- reef-railiance
|
||||
- rapp-openbao
|
||||
- rapp-postgres
|
||||
state_hub_workstream_id: "cd85bf28-7050-59a7-9af2-a7455b3df0fb"
|
||||
---
|
||||
|
||||
# RPF-WP-0009 - Platform rapp consistency and deployment-management contract
|
||||
|
||||
## Goal
|
||||
|
||||
Bring the platform-owned managed workload packages (`rapp-openbao`,
|
||||
`rapp-postgres`) onto one consistent, verifiable declaration and operations
|
||||
contract, and establish the S3 pattern that later platform-service rapps are cut
|
||||
from.
|
||||
|
||||
This workplan does **not** own the four-axis repo family model. That model lives
|
||||
in `railiance-master/docs/repository-axes.md` and is being promoted to custodian
|
||||
canon separately. S3's job here is to be the first family member that actually
|
||||
conforms, and to supply the platform-service reference shape.
|
||||
|
||||
## Findings that motivate this workplan
|
||||
|
||||
Surveyed 2026-08-11 against the live cluster and all six family repos.
|
||||
|
||||
The concepts are in better shape than their enforcement. The four families are
|
||||
cleanly defined and `RMASTER-WP-0018`/`RMASTER-WP-0019` in `railiance-master` are both
|
||||
`finished`. Nothing, however, validates a declaration file, so the model has
|
||||
been drifting quietly since the first wave.
|
||||
|
||||
1. **The rapp population diverged from the plan of record.** Planned wave 1 was
|
||||
`rapp-openbao` → `rapp-vergabe-teilnahme` → `rapp-forgejo`. Actual is
|
||||
`rapp-openbao`, plus `rapp-postgres` and `rapp-qonto` created ad hoc from
|
||||
immediate need. `rapp-vergabe-teilnahme` was never built, so the
|
||||
*user-facing* wrapper pattern it existed to prove is still unproven while the
|
||||
platform-service pattern has been proven twice.
|
||||
|
||||
2. **`rapp.yaml` has no schema and has drifted three ways.** The bootstrap
|
||||
contract names eight required fields but no shapes. Result: the
|
||||
rollout/smoke/rollback contracts are mutually unreadable (`supported_commands`
|
||||
lists in openbao and postgres versus `default_mode`/`production_gate`,
|
||||
`required:` and `order:` in qonto); only qonto carries `contract_version`,
|
||||
`readiness_state`, `data_classification` and `criticality`; only postgres has
|
||||
`consumer_contract`; `workload_identity.name` is the workload name twice and
|
||||
the repo name once. `rail.yaml` by contrast is consistent — the rail family
|
||||
got a tighter contract than the rapp family.
|
||||
|
||||
3. **The reef binding registry is stale.** `reef-railiance` declares
|
||||
`bound_rapps: [rapp-qonto]` while `rapp-openbao` and `rapp-postgres` both run
|
||||
on Railiance01. The reef's stated purpose is recording what is bound where,
|
||||
and it missed two of three.
|
||||
|
||||
4. **The model is not canon.** Custodian canon has no reef/rail/rapp standard,
|
||||
and `repo-classification-standard_v1.0` does not admit the prefixes — the
|
||||
same root cause as the open C-31 failures on `RAPP-*-WP-` work-record ids.
|
||||
|
||||
5. **Scale gap.** ~17 live non-system workloads, 3 rapps.
|
||||
|
||||
## Decisions taken (2026-08-11, operator-approved)
|
||||
|
||||
- **Granularity: grouped by bounded context.** One rapp per cohesive service
|
||||
group that deploys, versions and rolls back together, not one per deployable.
|
||||
A grouped rapp must declare its member services explicitly — grouping is only
|
||||
legitimate where the members share a rollout and rollback fate.
|
||||
- **Scope split.** S3 owns its own rapps and the platform-service pattern.
|
||||
Schema, validator and family-model changes are routed to `railiance-master`;
|
||||
canon promotion is routed to `the-custodian`. S3 does not author them.
|
||||
- **Canon: promote now**, so `fix-consistency` can validate declarations.
|
||||
- **Wave-1 gap: build `rapp-vergabe-teilnahme`** to prove the user-facing shape
|
||||
before further extraction. That build is `railiance-apps`/master territory,
|
||||
not S3's; this workplan only supplies the platform-service half of the pattern.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This workplan may:
|
||||
|
||||
- change declarations and operations contracts of platform-owned rapps
|
||||
(`rapp-openbao`, `rapp-postgres` — both declare `ownership_repo: railiance-platform`)
|
||||
- define the S3 platform-service rapp reference pattern
|
||||
- define how credential lanes and grant catalog entries bind to a rapp
|
||||
- send proposals to the repos that own the model, schema and canon
|
||||
|
||||
It must not:
|
||||
|
||||
- author the four-axis model, the `rapp.yaml` schema, or canon standards here
|
||||
- edit `reef-railiance`, `rail-*`, or `railiance-master` declarations directly
|
||||
- absorb platform-wide policy into a rapp (the "shadow S3 repo" failure mode
|
||||
named in `rapp-first-wave-candidates.md`)
|
||||
- change any credential gate, grant delivery, or revocation semantic
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "512adfef-a561-5b60-b4f3-f60e67696ef9"
|
||||
```
|
||||
|
||||
Publish the S3 platform-service rapp pattern as `docs/rapp-platform-service-pattern.md`:
|
||||
the reference `rapp.yaml` shape for a platform service, the ownership split
|
||||
between rapp and S3, the grouped-rapp member declaration rule, and the
|
||||
credential-lane binding. Generalize from the existing
|
||||
`docs/rapp-openbao-boundary.md` and `docs/rapp-postgres-boundary.md` rather than
|
||||
inventing a third boundary vocabulary.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "29b55ae5-74e2-5110-892c-ebb2b0cbf550"
|
||||
```
|
||||
|
||||
Bring `rapp-openbao/declarations/rapp.yaml` and
|
||||
`rapp-postgres/declarations/rapp.yaml` into a single consistent shape: add
|
||||
`contract_version`, `readiness_state`, `data_classification` and `criticality`
|
||||
(present in `rail.yaml` and in `rapp-qonto`, absent in both platform rapps), fix
|
||||
`workload_identity.name` to be the workload rather than the repo where it drifts,
|
||||
and align the rollout/smoke/rollback contract shape. Coordinate the target shape
|
||||
with the `railiance-master` schema proposal (T04) before editing, so the two do
|
||||
not converge on different answers.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "53cb32e3-5cdc-5664-b7be-c46828849c56"
|
||||
```
|
||||
|
||||
Correct the reef binding registry: propose to `reef-railiance` that
|
||||
`bound_rapps` include `rapp-openbao` and `rapp-postgres`, with the evidence that
|
||||
both are live on Railiance01. Proposal only — `reef-railiance` owns its
|
||||
declaration. Ask that the binding be derived or checked rather than hand-listed,
|
||||
since a hand-listed registry is what went stale.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b157de50-ff34-57aa-800e-d2d79e65a731"
|
||||
```
|
||||
|
||||
Route the schema and validator proposal to `railiance-master`: a
|
||||
`rapp.schema.json` covering the eight required fields plus the four consistency
|
||||
fields, a validator that runs over every family declaration, the grouped-rapp
|
||||
member field, and a refresh of `rapp-first-wave-candidates.md` to reflect what
|
||||
was actually built and the grouped-context wave-2 inventory.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "57ed22c9-94b9-526d-beb0-0a090eeaac3a"
|
||||
```
|
||||
|
||||
Route the canon promotion proposal to `the-custodian`: a
|
||||
`railiance-repo-families` standard, declaration schemas under `canon/standards/schemas/`,
|
||||
and admission of the `rail-`/`rapp-`/`reef-` prefixes into
|
||||
`repo-classification-standard` and `work-record-types.yaml` — the latter closing
|
||||
the open C-31 failures on multi-segment `RAPP-*-WP-` ids.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0009-T06
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "4423fa37-7e0d-5e2d-ac39-f6b505c60243"
|
||||
```
|
||||
|
||||
Define how a rapp binds to its credential lane: the relationship between
|
||||
`credential-grants/catalog.yaml` entries, CCR lanes, and a rapp's
|
||||
`runtime_dependencies`/`secret_references`, so that a new rapp has one documented
|
||||
way to acquire runtime secrets instead of re-deriving it per package. Must not
|
||||
alter existing gate, delivery or revocation semantics — this documents and binds
|
||||
the existing lane, it does not build a parallel one.
|
||||
|
||||
## Outcome
|
||||
|
||||
Session of 2026-08-11: T01 published the S3 platform-service pattern; T03, T04
|
||||
and T05 routed their proposals to the owning repos (reef-railiance
|
||||
f0f44ce0, railiance-master 04c776c4, the-custodian cc64764a). T02 was
|
||||
held until railiance-master settled the schema.
|
||||
|
||||
Session of 2026-08-13: T02 done. `rapp-openbao` and `rapp-postgres`
|
||||
`declarations/rapp.yaml` now pass `schemas/rapp.schema.json` (contract
|
||||
metadata, `composition`, `bound_reefs: [reef-railiance]`, `commands`,
|
||||
`smoke_contract.required`, `rollback_contract.order`). Live inventory for
|
||||
the T06 coverage check is
|
||||
`docs/evidence/reef-railiance-deployables.json`, refreshable with
|
||||
`scripts/capture-reef-deployables.py`. Family-validator remainder is
|
||||
outside this task: `rapp-qonto` still on the pre-schema shape, three
|
||||
undeclared `rapp-*` engine repos, and `reef-railiance` `bound_rapps`
|
||||
still hand-listed.
|
||||
|
||||
Session of 2026-08-13 (later): T06 done. Binding recipe is
|
||||
`docs/rapp-credential-lane-binding.md`. Standing secrets bind through
|
||||
a CCR `target.rapp` + `secret_references`; short-lived leases bind
|
||||
through grant `rapp_id` (required when the grant id is `rapp-*/…`).
|
||||
Stamped `rapp-postgres` catalog grants and `CCR-2026-0009`. Gate,
|
||||
delivery, and revocation semantics are unchanged. Workplan finished.
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
id: RPF-WP-0010
|
||||
type: workplan
|
||||
title: "Publish apps-pg resource and recovery evidence"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-11"
|
||||
updated: "2026-08-14"
|
||||
state_hub_workstream_id: "ee4a867f-eae2-5e85-b0b1-9802a3f31f10"
|
||||
related:
|
||||
- RAILIANCE-WP-0003
|
||||
- RESOURCE-WP-0003
|
||||
---
|
||||
|
||||
# RPF-WP-0010 — apps-pg resource evidence
|
||||
|
||||
## Goal
|
||||
|
||||
Provide platform-owned evidence for `resource:railiance:apps-pg`: demand,
|
||||
utilization, recovery, operations labor, and consumer allocation. Origin:
|
||||
`RESOURCE-WP-0003-T04` delegated evidence gap.
|
||||
|
||||
## T01 — Publish database capacity and utilization
|
||||
|
||||
```task
|
||||
id: RPF-WP-0010-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "4cba1304-9a5d-5a26-8706-fe1df7ca5d4e"
|
||||
```
|
||||
|
||||
Record instance count, CPU/memory requests and observed use, provisioned and
|
||||
used storage, database growth, connections, I/O or other available saturation
|
||||
proxies, and consumer database attribution with timestamps and provenance.
|
||||
|
||||
Done when resource-control can forecast database capacity without reading
|
||||
application data or credentials.
|
||||
|
||||
## T02 — Publish recovery and operational evidence
|
||||
|
||||
```task
|
||||
id: RPF-WP-0010-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "382751c3-b05c-51d1-9a9c-d64363978851"
|
||||
```
|
||||
|
||||
Record backup coverage, restore-test results, recovery objectives, upgrade and
|
||||
maintenance cadence, incidents, and setup/recurring operator labor. Keep
|
||||
service procedures and execution in railiance-platform.
|
||||
|
||||
Done when the portfolio can distinguish verified recovery, unresolved local
|
||||
storage risk, and platform labor cost.
|
||||
|
||||
## T03 — Define shared database allocation drivers
|
||||
|
||||
```task
|
||||
id: RPF-WP-0010-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "01148c0f-9d21-5c64-be99-cb5f42697274"
|
||||
```
|
||||
|
||||
Publish candidate consumer drivers such as database storage GB-month,
|
||||
connections, transactions, or measured I/O. Include shared overhead,
|
||||
unattributed residual, method version, and uncertainty.
|
||||
|
||||
Done when resource-control can allocate a referenced apps-pg cost without
|
||||
making railiance-platform a financial ledger.
|
||||
|
||||
## Outcome
|
||||
|
||||
Published 2026-08-14. Observation
|
||||
`docs/evidence/RPF-WP-0010-apps-pg-observation.json` and narrative
|
||||
`docs/evidence/RPF-WP-0010-apps-pg-resource-evidence.md`.
|
||||
|
||||
- T01: 1/1 instance, 10Gi local-path, 590 MiB PGDATA, no CPU/memory
|
||||
requests, two consumer catalogs (~16.6 MiB), `vergabe_db` unused.
|
||||
- T02: no ScheduledBackup, not an Option A target, RPO unbounded, RTO
|
||||
undefined — unresolved local-storage risk. Labor: ~6h setup, ~0.5h/month
|
||||
recurring, high uncertainty, no EUR.
|
||||
- T03: method `apps-pg-dbbytes-v1`, driver `database_gb`, residual
|
||||
`platform:apps-pg-overhead` (94.8% of used volume is WAL/catalog).
|
||||
|
||||
Refresh: `make apps-pg-evidence`. resource-control can now replace the
|
||||
illustrative `examples/control-cycle/apps-pg-*.json` fixtures.
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
---
|
||||
id: RPF-WP-0011
|
||||
type: workplan
|
||||
title: "Architecture cleanup backlog, WSJF-prioritized"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-12"
|
||||
updated: "2026-08-15"
|
||||
related_repos:
|
||||
- railiance-master
|
||||
- railiance-infra
|
||||
- railiance-cluster
|
||||
- railiance-enablement
|
||||
- railiance-telemetry
|
||||
- railiance-forge
|
||||
state_hub_workstream_id: "b3026cdc-ba4c-5da0-8e69-086e1691fca7"
|
||||
---
|
||||
|
||||
# RPF-WP-0011 - Architecture cleanup backlog, WSJF-prioritized
|
||||
|
||||
## Goal
|
||||
|
||||
Turn the INTENT/SCOPE gap analysis into an ordered backlog, so cleanup happens
|
||||
highest-value-least-effort first rather than in the order things were noticed.
|
||||
|
||||
Source: `history/2026-08-12-intent-scope-gap-analysis.md`.
|
||||
|
||||
## Boundary — read before working this
|
||||
|
||||
This workplan **coordinates and orders**; it does not execute. Every item below
|
||||
belongs to another repo, and each carries its owning repo in the table. S3 does
|
||||
not own fleet architecture cleanup — `railiance-master` does.
|
||||
|
||||
This backlog lives here because the analysis was done here. **It should be
|
||||
adopted by `railiance-master`**, and this workplan closed, once master has a
|
||||
place for it. Until then it is better recorded than lost. S3 executes only the
|
||||
items marked `railiance-platform`.
|
||||
|
||||
## Scoring method
|
||||
|
||||
WSJF = **Cost of Delay ÷ Job Size**, where Cost of Delay = Value + Time
|
||||
Criticality + Risk Reduction. Each component 1–10, job size 1–10.
|
||||
|
||||
Two honesty notes. These are **judgments, not measurements** — their value is
|
||||
the relative ordering and the explicit reasoning, not the arithmetic. And job
|
||||
sizes for unbuilt things (telemetry, the conformance loop) are the least
|
||||
reliable numbers here, because nobody has scoped them yet.
|
||||
|
||||
## The backlog
|
||||
|
||||
| # | Item | Owner | V | TC | RR | Size | **WSJF** |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | Converge the firewall allowlist; prune two stale grants | `railiance-infra` | 6 | 9 | 10 | 1 | **25.0** |
|
||||
| 2 | Ratify the five pending decisions | `railiance-master` | 8 | 7 | 5 | 1 | **20.0** |
|
||||
| 3 | Move the S1 goal off `railiance-hosts`, then retire it | `railiance-master` | 5 | 5 | 4 | 1 | **14.0** |
|
||||
| 4 | Settle ArgoCD: adopt, retire, or relocate | `railiance-master` | 6 | 6 | 6 | 2 | **9.0** |
|
||||
| 5 | Audit base role for further declared-vs-live drift | `railiance-infra` | 5 | 6 | 9 | 3 | **6.7** |
|
||||
| 6 | `rapp.yaml` schema + family declaration validator | `railiance-master` | 8 | 5 | 7 | 3 | **6.7** |
|
||||
| 7 | Reconcile hub capability attribution (C1) | `railiance-master` | 5 | 4 | 6 | 3 | **5.0** |
|
||||
| 8 | Deployable coverage check: every deployable → one rapp | `railiance-master` | 7 | 4 | 7 | 4 | **4.5** |
|
||||
| 9a | Telemetry: minimal metrics collection on railiance01 | `railiance-telemetry` | 8 | 5 | 5 | 4 | **4.5** |
|
||||
| 9b | Telemetry: one expectation-based alert (needs 10b) | `railiance-telemetry` | 8 | 5 | 2 | 2 | **7.5** |
|
||||
| ~~10a~~ | ~~Run `make verify`; tighten the UFW assertion~~ **DONE 2026-08-12** | `railiance-infra` | 8 | 7 | 9 | 1–2 | **12.0** |
|
||||
| 10b | Schedule verification; route failures where they are seen | `railiance-infra` / Q7 owner | 7 | 6 | 8 | 3 | **7.0** |
|
||||
| 11 | Consolidate the bootstrap path; sort inherited S2 content | `railiance-bootstrap` | 5 | 3 | 4 | 4 | **3.0** |
|
||||
| 12 | Forge migration: `rapp-forgejo` + S4 layer transfer | `railiance-forge` / S4 | 6 | 4 | 4 | 5 | **2.8** |
|
||||
| ~~13~~ | ~~Prove a restore end to end~~ **DONE 2026-08-15** | `railiance-platform` | 9 | 5 | 9 | 8 | **2.9** |
|
||||
| ~~14~~ | ~~Valkey extraction + legacy postgresql-ha retirement~~ **DONE 2026-08-15** | `railiance-platform` | 5 | 4 | 4 | 5 | **2.6** |
|
||||
| 15 | Sweep remaining Gitea prose (~31 files each) | `railiance-forge`, `railiance-apps` | 3 | 2 | 2 | 3 | **2.3** |
|
||||
| 16 | Declare the Q6 cost boundary with `resource-control`/`fin-hub` | `railiance-master` | 4 | 3 | 3 | 4 | **2.5** |
|
||||
| ~~17~~ | ~~Version S3 consumer service interfaces~~ **DONE 2026-08-15** | `railiance-platform` | 6 | 3 | 5 | 6 | **2.3** |
|
||||
| 18 | Resolve the C4 ecosystem-modelling overlap | `railiance-master` / `railiance-fabric` | 4 | 3 | 4 | 5 | **2.2** |
|
||||
| 19 | S4 build-out: pipeline templates, SDKs, portal | `railiance-enablement` | 7 | 3 | 4 | 9 | **1.6** |
|
||||
|
||||
## Reading the order
|
||||
|
||||
**Items 1–3 are nearly free and should happen first.** All three are "decided
|
||||
but unmoved" — waiting on ratification or a single command, not on effort.
|
||||
Item 1 in particular is a live security exposure: two standing firewall grants
|
||||
point at addresses the ISP has since reassigned, and the fix is one convergence
|
||||
run.
|
||||
|
||||
**Item 2 is the highest-leverage thing on the list.** Five pending
|
||||
ratifications in `railiance-master` block items 6, 7, 8, 12 and parts of 9 and
|
||||
10. It is a day of decisions that unblocks a quarter of the backlog.
|
||||
|
||||
**Items 9 and 10 are the strategic core** — Q2 and Q7, the two halves of the
|
||||
self-evidencing thread five layers independently asked for. They were rescoped
|
||||
on 2026-08-12 (see below) and item 10 turned out to be badly mis-sized: the
|
||||
conformance checker already exists in `railiance-infra` and has simply not run
|
||||
since 2026-03-09. **Slice 10a is now the highest-value item after the
|
||||
ratifications** at WSJF 12.0.
|
||||
|
||||
**Item 13 is done, not blocked.** `RESOURCE-WP-0002` finished 2026-08-15.
|
||||
Barman is live on `platform-pg`; T05 recorded full restore and PITR on
|
||||
2026-08-14; daily backups have completed since. Pointer:
|
||||
`docs/evidence/RPF-WP-0011-item13-restore-2026-08-15.md`.
|
||||
|
||||
**Item 19 is last and that is deliberate.** S4 build-out is the widest gap in
|
||||
the family, but it is large, and item 12 gives S4 a smaller first
|
||||
responsibility to prove delivery on. Building the portal before the forge
|
||||
transfer would be starting at the hard end.
|
||||
|
||||
## Rescoping items 9 and 10 (2026-08-12)
|
||||
|
||||
### What was assumed
|
||||
|
||||
That Q2 Observability and Q7 Governance were both greenfield builds of
|
||||
comparable size (5), sitting mid-table at WSJF 4.6.
|
||||
|
||||
### What is actually there
|
||||
|
||||
`railiance-infra` already has:
|
||||
|
||||
- `goss/baseline.yaml` — a host baseline assertion suite
|
||||
- `ansible/roles/goss` + `ansible/playbooks/verify.yaml` — the runner
|
||||
- `make verify` — runs it against all hosts, **commits TAP reports to git**, and
|
||||
exits non-zero on failure
|
||||
- `reports/*.tap` — an evidence trail, last written **2026-03-09**
|
||||
|
||||
So a check-and-evidence mechanism exists and is wired. Two things are wrong with
|
||||
it, and neither is a build:
|
||||
|
||||
1. **Nothing runs it.** Five months of silence. A verification suite that is not
|
||||
scheduled is a verification suite that does not exist.
|
||||
2. **Its firewall assertion is too loose in exactly the place that mattered.**
|
||||
It asserts `/6443\/tcp.*ALLOW/` — that the port is allowed. It does not
|
||||
assert *from whom*. That regex passes identically whether 6443 is restricted
|
||||
to one operator address or open to the entire internet, which is precisely
|
||||
the drift that went undetected.
|
||||
|
||||
It would, however, have caught the *other* finding: it asserts
|
||||
`Status: active`, and UFW is entirely inactive on `CoulombCore`.
|
||||
|
||||
### The rescoped slices
|
||||
|
||||
**Item 10 — conformance loop**
|
||||
|
||||
| Slice | Work | Size |
|
||||
| --- | --- | --- |
|
||||
| 10a | Run `make verify` against both hosts; tighten the UFW assertion to compare the live allowlist against `k3s_api_allowed_sources` rather than matching any ALLOW; fix what it surfaces | **2** |
|
||||
| 10b | Schedule it, and route failures somewhere a human or agent actually sees | 3 |
|
||||
| 10c | Extend to declaration conformance — rapp/rail/reef schema validation | blocked on item 6 |
|
||||
| 10d | Deployable coverage: every live deployable maps to exactly one rapp | blocked on item 8 |
|
||||
|
||||
**Item 9 — telemetry**
|
||||
|
||||
| Slice | Work | Size |
|
||||
| --- | --- | --- |
|
||||
| 9a | Minimal metrics collection on `railiance01` | 4 |
|
||||
| 9b | One expectation-based alert on the 10b path | 2 |
|
||||
| 9c | Retention sufficient to prove a restore or rollout held | 3 |
|
||||
| 9d | Dashboards and agent-queryable surfaces | 4 |
|
||||
|
||||
### The shared dependency worth naming
|
||||
|
||||
**10b and 9b are the same plumbing.** Both are "a check failed — now make that
|
||||
visible to someone who can act." Building an alert path twice would be waste,
|
||||
and building either of 9 or 10 *without* it produces logs nobody reads. That
|
||||
path is the real first dependency for both, and it is small.
|
||||
|
||||
It also has an obvious candidate already in the fleet: the Goss suite commits
|
||||
TAP evidence to git, and State Hub takes progress events. Neither is an alert,
|
||||
but the gap between them is narrow.
|
||||
|
||||
### Revised positions
|
||||
|
||||
| Item | Old WSJF | New WSJF | Effect |
|
||||
| --- | --- | --- | --- |
|
||||
| 10a run + tighten Goss | 4.6 (as part of 10) | **12.0** (V8 TC7 RR9 / size 2) | rises to 4th overall |
|
||||
| 10b schedule + alert path | — | **7.0** (V7 TC6 RR8 / size 3) | rises above ArgoCD |
|
||||
| 9b one real alert | — | **7.5** (V8 TC5 RR2 / size 2) | depends on 10b |
|
||||
| 9a metrics collection | 4.6 | **4.5** (unchanged) | stays mid-table |
|
||||
|
||||
**Conclusion: item 10a should be done next, immediately after the ratifications.**
|
||||
It is two points of effort, it directly closes the hole that produced this
|
||||
session's security finding, and it converts an existing but dormant asset into a
|
||||
working control. Item 9 is correctly mid-table and genuinely is a build.
|
||||
|
||||
### 10a outcome (2026-08-12) — the estimate held, and the check paid for itself immediately
|
||||
|
||||
Delivered in `railiance-infra`: `goss/baseline.yaml` became a template rendered
|
||||
per host from the *same* inventory declaration that converges the host, so the
|
||||
assertion cannot drift from what it checks. `verify.yaml` gained the
|
||||
`vars_files` the bootstrap play already had — without it the firewall assertions
|
||||
rendered empty and **silently asserted nothing**, which is worse than having no
|
||||
check at all.
|
||||
|
||||
Result on `Railiance01`: 32 assertions, 31 pass. And the one failure is a real
|
||||
defect the old assertion could never have seen:
|
||||
|
||||
> **Flannel VXLAN (`8472/udp`) is declared open to Anywhere**, with no source
|
||||
> restriction — the same defect pattern as the k3s API rule. It is currently
|
||||
> *absent* from the host, so converging the base role would **introduce** the
|
||||
> exposure rather than correct drift.
|
||||
|
||||
Tracked as `RAIL-HO-WP-0009-T06`. Two things worth taking from this:
|
||||
|
||||
1. **The check earned its keep on first run** — it found a latent defect that
|
||||
convergence would have activated, in under two points of effort.
|
||||
2. **It is an argument for finishing 10b.** This run happened because a human
|
||||
asked. Nothing schedules it, so the next latent defect waits for the next
|
||||
person who happens to look.
|
||||
|
||||
### The lesson worth keeping
|
||||
|
||||
The original size-5 estimate for item 10 was wrong because nobody looked. The
|
||||
gap analysis correctly identified "no conformance loop" as a *capability* gap,
|
||||
but the capability was two-thirds built and unrun. **Before sizing a gap as a
|
||||
build, check whether it is actually an abandonment.**
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: RPF-WP-0011-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d18ea91e-439b-57b4-a1b1-c39ede985579"
|
||||
```
|
||||
|
||||
Produce the INTENT/SCOPE gap analysis across all `railiance-*` repos, comparing
|
||||
declared aspiration against declared state against verified reality.
|
||||
|
||||
Delivered: `history/2026-08-12-intent-scope-gap-analysis.md`. Named the pattern
|
||||
that organizes the backlog — every gap is *declared but unbuilt*, *built but
|
||||
undeclared*, or *decided but unmoved*, and the third kind is cheapest to clear
|
||||
while blocking the most.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0011-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "bc7e49aa-b4a0-5f25-a6ba-a738dad0b3be"
|
||||
```
|
||||
|
||||
Score and order the backlog by WSJF, recording owner and reasoning per item so
|
||||
the ordering can be argued with rather than merely followed.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0011-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "80c39586-8c2a-59b8-ab7a-578d479d45c7"
|
||||
```
|
||||
|
||||
Route the backlog to `railiance-master` for adoption, with the recommendation
|
||||
that it takes items 2, 3, 4, 6, 7, 8, 16 and 18 — the ratification and taxonomy
|
||||
items — and that this workplan closes once adopted.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0011-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "302c718a-133c-544d-8b79-3b876fd25fb5"
|
||||
```
|
||||
|
||||
Rescope items 9 and 10 (telemetry MVP, conformance loop MVP) into deliverable
|
||||
slices before committing to their position. Their size scores are the least
|
||||
reliable on the list, and both are strategically central.
|
||||
|
||||
**Done 2026-08-12, and the answer changes the order.** See "Rescoping items 9
|
||||
and 10" below. The headline: item 10 was mis-sized by a wide margin, because the
|
||||
conformance checker **already exists** — `railiance-infra` has a Goss baseline
|
||||
suite with a `make verify` target that runs it against all hosts and commits TAP
|
||||
reports to git. It has not run since **2026-03-09**, five months. The work is not
|
||||
to build a loop; it is to run what exists, tighten two assertions, and schedule
|
||||
it.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0011-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d3568127-b2b2-5806-84f5-e482a41ccf55"
|
||||
```
|
||||
|
||||
Execute the S3-owned items in WSJF order — 13 (blocked on `9c21c0e0`), 14, 17 —
|
||||
and keep this table current as items complete or their sizes become known.
|
||||
|
||||
**Done 2026-08-15.** Item 13 unblocked by `RESOURCE-WP-0002` finish: restore
|
||||
already proven as T05 there; live `platform-pg-daily` backups completing.
|
||||
Item 14: Bitnami postgresql-ha deploy path fail-closed (never live on
|
||||
railiance01); Valkey has no S2 instance to extract and no consumer, so
|
||||
deploy is gated. Item 17: `docs/s3-consumer-interfaces.md` v1.0.0.
|
||||
|
||||
## Outcome
|
||||
|
||||
T01–T05 done. Routed to `railiance-master` (message `ac73b172`); master
|
||||
took items 6 and 8 as WP-0021 and declined the rest. S3-owned items 13,
|
||||
14 and 17 executed 2026-08-15 after the object-store purchase landed.
|
||||
Workplan finished. Remaining backlog rows belong to other repos.
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: RPF-WP-0012
|
||||
type: workplan
|
||||
title: "Enforce resource-control consumption mode"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-14"
|
||||
updated: "2026-08-15"
|
||||
related:
|
||||
- RESOURCE-WP-0005
|
||||
origin: residual
|
||||
origin_ref: RESOURCE-WP-0005
|
||||
state_hub_workstream_id: "519e512d-bef0-54ca-85f0-6912a5219ed5"
|
||||
---
|
||||
|
||||
# RPF-WP-0012 — enforce consumption mode
|
||||
|
||||
## Goal
|
||||
|
||||
Consume the `open` / `restricted` signal published by
|
||||
`resource-control` and enforce it on new orders and elastic usage.
|
||||
`resource-control` does not throttle the cluster.
|
||||
|
||||
Origin: `RESOURCE-WP-0005-T07`. Terms:
|
||||
`resource-control/docs/TermsOfResourceProcurement.md` § 11.
|
||||
Runbook: `resource-control/docs/resource-procurement-facility.md`.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Restricted monthly new-consumption is €50 transfer price minus that
|
||||
month's interest. At the default €1 000 overdue balance that is
|
||||
€45.83 transfer price / €38.19 delivered cost.
|
||||
- Already-committed provider contracts are flagged to human financial
|
||||
authority, not cancelled (OQ-2).
|
||||
- Safety paths (backup, identity, ingress needed to avoid data loss)
|
||||
may continue; overage is an exception line, not a hidden charge.
|
||||
|
||||
## T01 — Subscribe to the consumption-mode signal
|
||||
|
||||
```task
|
||||
id: RPF-WP-0012-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "c758776c-bd2a-5d38-a9b7-94db66fc0568"
|
||||
```
|
||||
|
||||
Define how platform procurement and admission read the latest
|
||||
per-entity consumption mode and remaining transfer-price allowance for
|
||||
the current period.
|
||||
|
||||
Done when a restricted entity cannot place a new order that would
|
||||
exceed the published allowance, and an `open` entity is unchanged.
|
||||
|
||||
Delivered 2026-08-15: `scripts/consumption_mode.py`,
|
||||
`docs/consumption-mode-enforcement.md`, `make consumption-preflight`.
|
||||
Restricted + estimate above allowance exits 2. Open and missing-signal
|
||||
admit. Safety/committed paths admit with an exception line. `apps-pg-deploy`
|
||||
runs the gate when `CONSUMING_ENTITY` is set.
|
||||
|
||||
## Outcome
|
||||
|
||||
T01 done. Workplan finished. resource-control still owns the signal;
|
||||
this repo only enforces it.
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
id: RPF-WP-0013
|
||||
type: workplan
|
||||
title: "Close agent high-risk OpenBao boundary coverage"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-22"
|
||||
related:
|
||||
- WARDEN-WP-0032
|
||||
- RISK-F-0009
|
||||
origin: routed
|
||||
origin_ref: "State Hub message 828e4903-30fe-4903-acfd-cd2ecdda437d"
|
||||
state_hub_workstream_id: "25c0b1c9-a1b7-5844-bd39-9db165fe196c"
|
||||
---
|
||||
|
||||
# RPF-WP-0013 — Agent high-risk boundary coverage
|
||||
|
||||
## Goal
|
||||
|
||||
Make the OpenBao `agent-high-risk-boundary` deny every concrete high-risk KV
|
||||
data path in the ops-warden routing catalog, verify the deployed policy, and
|
||||
establish whether any agent identity actually carries the boundary.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Read policy documents, token-role metadata and capabilities only; never read
|
||||
a Secret value.
|
||||
- A deny is added only for a concrete catalog path graded `risk: high`.
|
||||
- Pattern-only and non-KV lanes are reported but do not produce invented paths.
|
||||
- Operator identities do not receive this boundary; it is for coding-agent
|
||||
identities where deny must override any coincident workload read policy.
|
||||
|
||||
## T01 — Reconcile catalog coverage
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "35855316-3282-52d2-922e-43af1c4495c0"
|
||||
```
|
||||
|
||||
Run the capabilities-only ops-warden audit against the policy. The initial
|
||||
2026-08-21 reconciliation found 17 high-risk lanes: six covered, six concrete
|
||||
uncovered, and five without a concrete KV address. The final generated input
|
||||
contains 19 high-risk lanes, 14 concrete entries, and five without an address.
|
||||
No credential value was read.
|
||||
|
||||
## T02 — Close the concrete deny gaps
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9f2a6ffc-5f48-5e45-b636-76dff7d41743"
|
||||
```
|
||||
|
||||
Add deny-data/read-metadata pairs for the six catalog paths: whynot-design npm,
|
||||
rapp-qonto Keycape client, agent-harness Forgejo deploy key, audit-core senders,
|
||||
email-connect transactional, and Scaleway bootstrap. Add regression coverage
|
||||
for every concrete path currently emitted by the catalog audit.
|
||||
|
||||
Completed 2026-08-22. After ops-warden corrected two multi-field grades, the
|
||||
source policy covers all 13 unique concrete catalog paths plus the additional
|
||||
reviewed Core Hub path. The generated-input check reports all 14 concrete
|
||||
catalog entries covered with none uncovered.
|
||||
|
||||
## T03 — Apply and verify live
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "92b4b531-986d-54b4-a18b-cd8785dca5ce"
|
||||
```
|
||||
|
||||
Under attended platform authority, upload the reviewed policy, read it back,
|
||||
and rerun the catalog audit with `policy_source: server`. Inspect policy/token
|
||||
role metadata to determine whether an agent identity carries the boundary and
|
||||
whether any role combines it with a workload-read policy. Do not mint a token.
|
||||
|
||||
Completed initially on 2026-08-21 and reconciled again on 2026-08-22 under
|
||||
attended `platform-admin` OIDC. OpenBao accepted the policy; normalized
|
||||
readback matched source, and the final server-backed audit reported 19
|
||||
high-risk lanes, 14 covered entries, zero uncovered, and five pattern/non-KV
|
||||
lanes without a concrete address. No Secret value was read.
|
||||
|
||||
## T04 — Route the result
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "d394fcb7-1477-5dfe-9e4b-65bd14f08346"
|
||||
```
|
||||
|
||||
Reply to ops-warden with the deployment evidence and remaining attachment
|
||||
finding. Request a generated, versioned concrete-deny artifact so future policy
|
||||
updates consume catalog output rather than relying on a hand-maintained list.
|
||||
|
||||
Completed 2026-08-21 via State Hub message
|
||||
`fe727451-163a-4e14-8ce3-187fea8ce5b3`, including live audit counts, the zero-
|
||||
attachment finding, the distinct-agent-identity blocker, and the requested
|
||||
versioned generated artifact shape.
|
||||
|
||||
Ops-warden delivered revision `55f0f47a021375b8b25c924953d1b49a24e002c5`
|
||||
on 2026-08-21. The platform now vendors it as a checked policy input and has a
|
||||
repeatable upstream-equality plus policy-coverage command.
|
||||
|
||||
## T05 — Establish a distinct coding-agent identity
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6805ef60-bd20-5549-b955-cee94eb69dad"
|
||||
```
|
||||
|
||||
The policy is live but no role attaches it. Do not add the boundary to
|
||||
`platform-admin`: that is an attended human/operator role whose legitimate
|
||||
recovery work may require the protected values. The identity owner must define
|
||||
a distinct coding-agent issuance path, attach this boundary there, and prove
|
||||
deny-wins behavior when combined with an otherwise readable workload policy.
|
||||
Completed 2026-08-22. State Hub decision
|
||||
`f0955252-7b20-4c80-86e9-f8080ec60793` establishes the platform-owned AppRole
|
||||
`coding-agent-railiance-platform` as the operational machine identity. Its
|
||||
single-use SecretIDs expire after five minutes; its tokens last at most 15
|
||||
minutes, have eight uses, omit the default policy, and attach both
|
||||
`agent-high-risk-boundary` and the otherwise-readable issue-core workload
|
||||
policy. A live ephemeral login proved data capabilities resolve to `deny` and
|
||||
metadata to `read`; the token was revoked without reading the KV value.
|
||||
|
||||
The exact-bound KeyCape JWT role is also live as the issuer-backed migration
|
||||
target. KeyCape principal registration remains an identity hardening follow-up,
|
||||
not a blocker to the active AppRole boundary.
|
||||
|
||||
## T06 — Consume the generated catalog artifact
|
||||
|
||||
```task
|
||||
id: RPF-WP-0013-T06
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1b0c4f03-0ec7-5fcc-908d-beed236e4865"
|
||||
```
|
||||
|
||||
|
||||
Consume ops-warden's versioned `high-risk-data-paths.yaml` as a policy-check
|
||||
input, add the two newly regraded issue-core and reuse-surface paths, and rerun
|
||||
source plus live coverage. The input remains ops-warden's risk statement, not
|
||||
the policy authority; railiance-platform continues to own every deny decision.
|
||||
|
||||
Completed 2026-08-22. The vendored input matches the clean upstream artifact,
|
||||
the repository check covers all 14 entries, and the server-backed audit reports
|
||||
zero uncovered. Evidence: `docs/evidence/agent-high-risk-boundary-2026-08-21.md`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] Every concrete high-risk catalog path is denied in the source policy.
|
||||
- [x] The live policy matches source and the server-backed audit passes.
|
||||
- [x] A distinct AppRole attachment is established from live metadata.
|
||||
- [x] Result and generated-artifact follow-up are routed to ops-warden.
|
||||
- [x] A distinct coding-agent identity actually attaches the boundary.
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
id: RPF-WP-0014
|
||||
type: workplan
|
||||
title: "Hub-core candidate credential lanes"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-22"
|
||||
related:
|
||||
- CORE-WP-0010
|
||||
- RAPPCOREHUB-WP-0002
|
||||
- RAPP-POSTGRES-WP-0004
|
||||
state_hub_workstream_id: "ab1c2145-528b-50af-b36e-161f28325848"
|
||||
---
|
||||
|
||||
# Hub-core candidate credential lanes
|
||||
|
||||
## Extend exact-scope policy and projections
|
||||
|
||||
```task
|
||||
id: RPF-WP-0014-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b30ba596-14c8-54c2-92fc-530bbbc965a8"
|
||||
```
|
||||
|
||||
Add only `database/creds/hub-core-runtime` and
|
||||
`database/creds/hub-core-migration` to the existing namespace-limited Core Hub
|
||||
database store, with separate five-minute ExternalSecret projections.
|
||||
|
||||
## Activate and verify production lanes
|
||||
|
||||
```task
|
||||
id: RPF-WP-0014-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "68766bac-d032-57f9-84cd-a8725cbe0ada"
|
||||
```
|
||||
|
||||
Apply the reviewed policy and projections after rapp-postgres creates the
|
||||
roles. Verify store validity, SecretSynced status, role separation, and lease
|
||||
rotation without reading or logging values.
|
||||
|
||||
Completed 2026-08-22. The exact policy, projections, SecretSynced state, role
|
||||
separation, and production runtime/migration handoff passed on 2026-08-21. A
|
||||
subsequent scheduled five-minute reconciliation advanced both target Secret
|
||||
resource versions. After projected-volume propagation, the candidate watcher
|
||||
replaced only its application child while the pod UID remained stable,
|
||||
readiness stayed true, and the container restart count stayed zero. No
|
||||
credential value was read or logged. Evidence:
|
||||
`docs/evidence/core-hub-private-shadow-2026-08-21.md`.
|
||||
|
||||
## Hand off the private candidate
|
||||
|
||||
```task
|
||||
id: RPF-WP-0014-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "0af38f5b-7f59-5e14-8046-646c6fe526cd"
|
||||
```
|
||||
|
||||
Confirm both Secret metadata objects are ready, then hand the candidate
|
||||
migration and rollout gate back to `RAPPCOREHUB-WP-0002-T03`.
|
||||
|
||||
Completed 2026-08-21. Both projected Secret metadata objects were Ready, the
|
||||
migration completed, and the candidate advanced through all route groups to
|
||||
production authority without exposing credential values.
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
---
|
||||
id: RPF-WP-0016
|
||||
type: workplan
|
||||
title: "Version ephemeral custody projection and broker handoff"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-22"
|
||||
updated: "2026-08-22"
|
||||
related:
|
||||
- RAILIANCE-WP-0024
|
||||
- WHITEHAT-WP-0001
|
||||
- AUDIT-WP-0008
|
||||
origin: run-review
|
||||
origin_ref: "WH-ENG-20260822-AUDIT-E2-02 terminal clean admission abort"
|
||||
state_hub_workstream_id: "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
|
||||
|
||||
```task
|
||||
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
|
||||
|
||||
```task
|
||||
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
|
||||
|
||||
```task
|
||||
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
|
||||
|
||||
```task
|
||||
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
|
||||
|
||||
```task
|
||||
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
|
||||
|
||||
- [x] No projection can begin without a current consumer broker receipt.
|
||||
- [x] A new engagement is configuration, not copied executable code.
|
||||
- [x] Projection and cleanup receipts are versioned, canonical, and value-safe.
|
||||
- [x] Remote command arguments survive shell-hostile templates unchanged.
|
||||
- [x] Every modeled partial mutation cleans only its receipt-bound scope.
|
||||
- [x] Expired cleanup is executable but no unattended scheduler is deployed.
|
||||
|
||||
## T06 — Export the broker receipt consumed by admission
|
||||
|
||||
```task
|
||||
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.
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
id: RPF-WP-0017
|
||||
type: workplan
|
||||
title: "Contain attended OpenBao login output before authentication"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-23"
|
||||
updated: "2026-08-23"
|
||||
related:
|
||||
- RAILIANCE-WP-0024
|
||||
- WARDEN-WP-0027
|
||||
- WARDEN-WP-0027-T02-DRILL-20260822-01
|
||||
origin: routed
|
||||
origin_ref: "State Hub message b3f34c2d-941f-4ddd-b15d-e28075446021"
|
||||
state_hub_workstream_id: "b27975a7-e1bf-595e-8412-de03e167c9ed"
|
||||
---
|
||||
|
||||
# RPF-WP-0017 — attended OpenBao login output containment
|
||||
|
||||
## Goal
|
||||
|
||||
Make the governed `openbao-platform-admin-login` path fail before OIDC unless
|
||||
it can guarantee isolated private token-helper storage and contain every byte
|
||||
emitted by the underlying client. A persistence or output-contract failure must
|
||||
revoke any issued credential without placing its value, accessor, fingerprint,
|
||||
or derived material in agent-visible output, Git, State Hub, evidence, or logs.
|
||||
|
||||
This workplan records the direct fix interface requested by `railiance-infra`.
|
||||
It does not authorize OIDC authentication, minting, OpenBao administration, a
|
||||
seal/unseal ceremony, or reuse of the terminal drill scenario.
|
||||
|
||||
## Ownership and fixed boundaries
|
||||
|
||||
- `railiance-platform` owns the login lane, acceptance contract, and any future
|
||||
production rehearsal.
|
||||
- `ops-warden` owns the current proxy implementation in `src/warden/cli.py`,
|
||||
`src/warden/proxy.py`, and its focused tests.
|
||||
- key-cape remains the OIDC/MFA identity provider; this task does not weaken or
|
||||
replace MFA, change the OpenBao role, or introduce root/workload fallback.
|
||||
- `railiance-infra` is the requesting reviewer and independent abort owner.
|
||||
- Risk Nexus owns grading of State Hub filing request
|
||||
`5a344f53-14e9-4230-8874-2f01b0a85700`.
|
||||
- State Hub GO decision `449a697a-5303-4582-aa9e-b0bc8b35ab2d` was consumed by
|
||||
NO-GO decision `85724c0c-e70f-4e2f-a8c6-a9cb1ea6331b`. Neither decision nor
|
||||
scenario `WARDEN-WP-0027-T02-DRILL-20260822-01` may be reused.
|
||||
|
||||
## T01 — Harden the attended-login adapter and prove failure containment
|
||||
|
||||
```task
|
||||
id: RPF-WP-0017-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "e2448d67-8585-5d99-9c00-20c06f1186dd"
|
||||
```
|
||||
|
||||
Implement the fix in `ops-warden` and return one value-safe owner receipt to
|
||||
`railiance-platform` and `railiance-infra` naming the source revision, focused
|
||||
test command/result, and the five acceptance outcomes below. The receipt must
|
||||
contain no credential, accessor, fingerprint, output excerpt, callback code,
|
||||
or token-helper contents.
|
||||
|
||||
Acceptance is all of the following:
|
||||
|
||||
1. An isolated writable token-helper location is created before authentication,
|
||||
has mode `0600` (with private parent directories), and is removed or revoked
|
||||
through a deterministic cleanup path.
|
||||
2. A read-only or otherwise unusable default home fails before OIDC begins; the
|
||||
adapter never discovers persistence failure only after credential issuance.
|
||||
3. Adapter-owned stdout and stderr containment guarantees that no credential
|
||||
reaches agent-visible output even if the underlying CLI violates
|
||||
`-no-print`. Inherited agent-visible stdio is not permitted for this lane.
|
||||
4. Unexpected credential-bearing or otherwise non-allowlisted output fails
|
||||
closed and, whenever issuance may have occurred, triggers immediate
|
||||
self-revocation through the contained process without logging, returning,
|
||||
hashing, or fingerprinting the value.
|
||||
5. Focused tests cover successful attended-login handoff, unwritable/default
|
||||
home refusal before authentication, helper persistence failure, unexpected
|
||||
stdout, unexpected stderr, immediate revocation, cleanup, and value absence
|
||||
from captured test and audit output.
|
||||
|
||||
The implementation must also update the `openbao-platform-admin-login` worker
|
||||
playbook and catalog comment so they no longer claim safety from `-no-print`
|
||||
alone. A non-production test double must prove the complete failure path before
|
||||
any new live OIDC rehearsal is proposed.
|
||||
|
||||
Done when the implementation is committed and pushed in `ops-warden`, the
|
||||
focused suite passes, the value-safe owner receipt is delivered directly to
|
||||
both reviewers, and `railiance-platform` accepts the exact revision. Completion
|
||||
of this task still does not authorize a live drill; that requires fresh owner
|
||||
receipts, current preflight, and a new human decision under a new scenario id.
|
||||
|
||||
Completed 2026-08-23. Railiance Platform accepts ops-warden revision
|
||||
`0fae0904ce8d8694338dd53a8a79abec5fec788d`. The committed owner receipt at
|
||||
ops-warden revision `bc1966da825fbeaa4d83947a4f942b5d5f085408` has SHA-256
|
||||
`d2ba444ed16989590325697e69d25283dc75a9432c29a72e627e80bf9fd987e4`,
|
||||
reports 42 focused tests and 390 repository tests passing, and records all
|
||||
seven containment outcomes without sensitive material. Independent
|
||||
railiance-infra review at revision `186b030` approves the same implementation.
|
||||
This is source acceptance only and authorizes no live OIDC or drill.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] The adapter refuses unsafe storage before OIDC.
|
||||
- [x] No underlying login output can reach the agent transcript.
|
||||
- [x] Any issued credential is contained and revoked on failure.
|
||||
- [x] Focused success and failure-path tests pass without credential material.
|
||||
- [x] Both direct reviewers receive and accept the value-safe fix receipt.
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
---
|
||||
id: RPF-WP-0018
|
||||
type: workplan
|
||||
title: "Align S3 with the estate policy surface (Tenancy Posture + policy-nexus)"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-17"
|
||||
updated: "2026-08-18"
|
||||
related:
|
||||
- POLICY-NEXUS-WP-0001
|
||||
- TEN-WP-0009
|
||||
- RAPP-POSTGRES-WP-0002
|
||||
origin: routed
|
||||
origin_ref: "net-kingdom/canon/standards/tenancy-posture_v0.1.md §19.2, §20"
|
||||
state_hub_workstream_id: "4fcb6026-2630-59a3-b5de-15f54efcf59d"
|
||||
---
|
||||
|
||||
# RPF-WP-0018 — policy surface alignment
|
||||
|
||||
## Goal
|
||||
|
||||
Answer the two policy asks that landed on this repo, accept what fits,
|
||||
push back on what does not, and leave behind artifacts that are checkable
|
||||
rather than a promise to be good.
|
||||
|
||||
Done means: this repo has published a posture declaration, has accepted or
|
||||
declined placement ownership in writing, has told its consumers their
|
||||
quotas, and has answered `policy-nexus` on the one assignment in
|
||||
`POLICY-NEXUS-WP-0001` that contradicts the OAS stack.
|
||||
|
||||
## Where the policy comes from
|
||||
|
||||
Two documents, from two owners, arriving in the same week.
|
||||
|
||||
1. **`net-kingdom/canon/standards/tenancy-posture_v0.1.md`** (draft-5,
|
||||
proposed, reviewed by nobody). Routed by `rapp-postgres` on 2026-08-17
|
||||
(message `d9da7d11`), foreshadowed by `tenant-engine` on 2026-08-16
|
||||
(message `31aed179`). It asks this repo, **co-signed with
|
||||
`adaptive-pricing`**, to own database placement policy — §8.2, §19.2 —
|
||||
and to publish its own posture vector as the ratification test (§20.2).
|
||||
2. **`policy-nexus/workplans/POLICY-NEXUS-WP-0001`** (proposed). It
|
||||
assigns this repo the *substrate* for `policy.coulomb.social` — DNS,
|
||||
TLS, ingress, hosting — and includes this repo in the ~68-ADR corpus it
|
||||
intends to publish from `docs/adr/*.md`.
|
||||
|
||||
Both are drafts. Neither is ratified. Accepting them now is cheaper than
|
||||
accepting them later, because both are still willing to change.
|
||||
|
||||
## What actually applies to us, and what does not
|
||||
|
||||
**Applies, and fits.** The placement ladder (P0–P4) describes our estate
|
||||
accurately: `apps-pg` is a P1 shared cluster, `user-engine-pg` and
|
||||
`target-revenue-pg` are P2. The §10.2 quota-disclosure obligation lands on
|
||||
a document we already maintain, `docs/s3-consumer-interfaces.md`. The §9.1
|
||||
ban on static long-lived database credentials is already how the credential
|
||||
broker works. Nothing in the ladder requires us to move a single workload.
|
||||
|
||||
**Applies, but we cannot satisfy it yet.** §8.1 says placement triggers
|
||||
MUST be *monitored*, not merely recorded. This repo has no monitoring
|
||||
plane. `SCOPE.md` states we emit to `railiance-telemetry` "once the
|
||||
evidence plane exists — seeded 2026-08-11, not yet implemented". Claiming
|
||||
monitoring we do not have is the exact overclaim §6 prohibits, so T03
|
||||
records each trigger with a named monitor or an explicit `unmonitored`
|
||||
marker, and the marker is the honest answer until telemetry lands.
|
||||
|
||||
**Does not fit, and the policy should change.** Five findings, T07.
|
||||
|
||||
## Findings against the policy (routed 2026-08-17, T07)
|
||||
|
||||
**F1 — `POLICY-NEXUS-WP-0001` assigns S3 a concern S3 does not own.**
|
||||
It states "`railiance-platform` owns the substrate — DNS, TLS, ingress,
|
||||
hosting". Per `SCOPE.md`, DNS and OS-level concerns are S1
|
||||
`railiance-infra`, and Kubernetes ingress is S2 `railiance-cluster`;
|
||||
S3 owns shared *platform services*. Accepting the assignment as written
|
||||
would re-import the boundary violation that `RAIL-PL-WP-0001` and ADR-003
|
||||
exist to prevent.
|
||||
|
||||
*Recommend:* split T04 of that workplan. Ingress and TLS to S2, DNS to S1
|
||||
or the reef boundary, and the genuinely S3 parts — an object-storage bucket
|
||||
for the static output if it wants one, plus any credential lane — stay
|
||||
here. This repo can co-sign the deployment without owning the substrate.
|
||||
Adjacent and unresolved: `railiance-master` asked us on 2026-08-15
|
||||
(`ba477968`) to confirm `bao.coulomb.social` does not publish on
|
||||
reef-railiance. A second public name on the same rail should go through
|
||||
whatever answers that question, not around it.
|
||||
|
||||
**F2 — this repo's decisions are structurally unpublishable.**
|
||||
`policy-nexus` publishes canon and ADRs only, globbing `docs/adr/*.md`.
|
||||
This repo has **no `docs/adr/` directory and no ADRs**. Its load-bearing
|
||||
decisions live either in `docs/` as prose without frontmatter (24 files,
|
||||
no status, revision, review date or owner — the fields T02/T05 of the
|
||||
publication workplan require) or in the State Hub via `record_decision()`,
|
||||
which is a read model and is not a publication source. The estate's
|
||||
standing rule is that local files are the source of truth; for decisions,
|
||||
this repo does not follow it.
|
||||
|
||||
*Recommend:* not a mass conversion. T05 here promotes the small set that
|
||||
is genuinely decisional — the boundary rules, the credential-lane model,
|
||||
the consumption-mode gate — into ADR form with the frontmatter
|
||||
`policy-nexus` needs. The runbooks stay prose and stay unpublished, which
|
||||
is what that workplan's scope rule already wants.
|
||||
|
||||
**F3 — §19.8 asks this repo for a number that lives in another repo.**
|
||||
Cell sizing wants `platform-pg`'s declared maximum size. That spec —
|
||||
`instances: 1`, `max_connections: 100`, `1Gi` — is `rapp-postgres`'s
|
||||
cluster CR, not ours; `RAILIANCE-WP-0012` and `RAILIANCE-WP-0015`
|
||||
deliberately moved the deployable surface to the rapp repos while this repo
|
||||
kept custody and policy. The split is right and the question is misrouted
|
||||
by one hop.
|
||||
|
||||
*Recommend:* accept §8.2 with the scope stated — **this repo owns the rule,
|
||||
`rapp-postgres` owns the number**. We declare *that* a ceiling must be
|
||||
published and what happens at it; they declare what it is. Same shape for
|
||||
§19.9's retention floor and ceiling. `rapp-postgres`'s own analysis already
|
||||
concedes the point: memory probably binds before connections do, at roughly
|
||||
10MB per backend, and that is an observation only the package owner can
|
||||
make.
|
||||
|
||||
**F4 — the posture vector is service-shaped; this repo is a layer.**
|
||||
§5 asks a *service* to state one level per axis. `railiance-platform` is an
|
||||
OAS layer that holds custody of several services with different postures.
|
||||
One vector for the repo would be an average, which is exactly the
|
||||
inaccuracy §6 prohibits. §20.2 invites this: "if a repo cannot express
|
||||
itself in these five ladders, the ladders are wrong and this document
|
||||
changes, not the repo."
|
||||
|
||||
*Recommend:* a layer repo publishes a **vector set** — one per service it
|
||||
has custody of — plus a statement of which it owns versus operates. T01
|
||||
does that and routes the finding back to `net-kingdom` as the framework's
|
||||
first real correction from review rather than from research.
|
||||
|
||||
Refined while writing T01: the sharper form of F4 is that **the five
|
||||
ladders describe a consumer of storage, not a provider of it.** Every S3
|
||||
service scores at or near zero on I, A and E for the same structural
|
||||
reason — a storage or credential platform has no tenant dimension of its
|
||||
own. The `openbao` E line is the demonstration: `E: 0` is literally correct
|
||||
and actively misleading, because the mechanism in place is
|
||||
credential-scoped structural separation, the machinery E4 describes,
|
||||
pointed at a consumer boundary rather than a tenant one. Proposed remedy is
|
||||
a **provider declaration** beside the consumer vector, stating per axis the
|
||||
maximum level the platform makes reachable and what the consumer must do to
|
||||
reach it. Offered as an addition, not a renumbering.
|
||||
|
||||
**F5 — `policy-nexus` T02/T05 cannot be built against the corpus as it
|
||||
stands.** Measured across the workstation on 2026-08-17: **69 ADRs in 19
|
||||
repos** — closely matching that workplan's "roughly 68 across 18" — of
|
||||
which **21 carry YAML frontmatter**, **41 carry any status field**, and
|
||||
**2 carry any notion of a review date**. T02 specifies a front-matter-driven
|
||||
renderer taking title, status, revision and review date from the source; T05
|
||||
requires every page to show status, revision and last-reviewed, with a
|
||||
staleness marker once a review interval is exceeded. Against this corpus
|
||||
that renderer has nothing to read for 48 of 69 documents, and the currency
|
||||
half of the repo's purpose has data for 2.
|
||||
|
||||
*Recommend:* T03 of that workplan should treat frontmatter as an **ingestion
|
||||
precondition**, not a rendering input — a document without the required
|
||||
fields is reported as non-conformant and left unpublished, rather than
|
||||
rendered with blanks or with dates the site inferred. Inferring them is the
|
||||
failure mode that workplan already names as its top risk: the publication
|
||||
becomes a second source of truth. The corollary is that policy-nexus needs
|
||||
a conformance report aimed at source repos before it needs a site, and this
|
||||
repo's `docs/adr/README.md` is one repo's answer to it.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- No workload moves placement level in this workplan. Declaring where
|
||||
things are is separate from changing where they are.
|
||||
- No monitoring is built here. T03 records the gap; closing it belongs
|
||||
with `railiance-telemetry`.
|
||||
- Co-signature with `adaptive-pricing` is *requested*, not assumed. If they
|
||||
decline, T02 records single ownership and says so.
|
||||
- This repo does not amend NetKingdom canon. Findings are routed; the
|
||||
standard's owner decides.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "88d1342b-5093-5fbc-aa84-1608d163b979"
|
||||
```
|
||||
**Publish the S3 posture vector set.** Write `docs/tenancy-posture.md`:
|
||||
one vector per service under S3 custody (`openbao`, `apps-pg`, and the
|
||||
`rapp-postgres`-operated clusters we hold policy for), each with `current`,
|
||||
`target`, `reviewed`, and a `gap` note per axis below target. State plainly
|
||||
which services this repo *owns* and which it only holds *policy* for.
|
||||
Route F4 to `net-kingdom` with the vector set as the evidence.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "03f0a5bd-7876-5784-bf02-11cbcdf005bb"
|
||||
```
|
||||
**Accept placement ownership, scoped.** Write `docs/placement-policy.md`:
|
||||
adopt the P0–P4 ladder by reference (do not restate it — the canon copy is
|
||||
the source), record the default (P1 for platform services), and record a
|
||||
named **placement owner per workload** for every consumer on an S3-custody
|
||||
cluster. State the F3 split explicitly: rule here, number in
|
||||
`rapp-postgres`. Request `adaptive-pricing` co-signature; record the answer
|
||||
either way.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "b602226f-8eb5-5609-995f-94f9074b0895"
|
||||
```
|
||||
**Make triggers monitorable or honestly unmonitored.** For each of the five
|
||||
§8 triggers, record in `docs/placement-policy.md` what signal would fire it,
|
||||
who reads that signal, and at what cadence — or the literal marker
|
||||
`unmonitored: pending railiance-telemetry`. Include the §8.3.3 obligation:
|
||||
report which service classes are co-resident. Today that is
|
||||
`latency-critical` (`tenant-engine`) beside `batch` (`audit-core`) on
|
||||
`platform-pg`, which becomes a stated risk rather than an invisible one.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "92ce14f6-afee-50f6-abd4-197c4724a589"
|
||||
```
|
||||
**Disclose quotas to consumers (§10.2).** Extend
|
||||
`docs/s3-consumer-interfaces.md` to `1.1.0` — additive under its own
|
||||
compatibility rule — adding per-interface connection limits, statement and
|
||||
idle-transaction timeouts, and backup retention to `apps-pg.v1` and
|
||||
`rapp-postgres.v1`. Add the standing obligation that a change to any of
|
||||
these is announced to bound consumers, not discovered by them.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T05
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "58ef22f8-7f1b-5647-babd-eeb817b3ae31"
|
||||
```
|
||||
**Create the ADR surface (F2).** Create `docs/adr/` with an ADR template
|
||||
carrying the frontmatter `policy-nexus` T02/T05 consume: title, status,
|
||||
revision, owner, last-reviewed, review interval. Promote the decisions that
|
||||
are already load-bearing and already written down elsewhere — the S3
|
||||
boundary rule, the credential-lane model, the consumption-mode gate,
|
||||
and the outcome of T02 — into ADRs. Runbooks stay prose. State in each ADR
|
||||
which hub `record_decision()` id it supersedes, so the hub stops being the
|
||||
only home for a decision.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T06
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "49c682a0-a9b7-59f0-ad65-79b4fb9bb79c"
|
||||
```
|
||||
**Answer §19.9 — retention floor and ceiling.** Decide whether
|
||||
`backupRetentionDays` gets a platform minimum (so a consumer asking for one
|
||||
day gets a validation error rather than a quiet disappointment) and a
|
||||
maximum (so nobody exhausts the volume). Record the rule here; the
|
||||
enforcing validator is `rapp-postgres`'s. Carry `rapp-postgres` ADR-0002's
|
||||
consequence forward: on a shared cluster a consumer's erasure horizon is the
|
||||
maximum declared across co-residents, so a shorter horizon is a P2 trigger.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0018-T07
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ad7a159b-a395-50e0-a517-d605a1d70108"
|
||||
```
|
||||
**Route the findings.** Reply to `rapp-postgres` and `tenant-engine` with
|
||||
T01/T02 outcomes and F3/F4. Reply to `policy-nexus` with F1 (substrate
|
||||
misassignment, with the S1/S2 split recommended) and F2 (ADR surface now
|
||||
being built, plus the hub-decisions gap). Reply to `railiance-master` on
|
||||
`ba477968`, since a second public name on reef-railiance depends on the
|
||||
same answer. Mark the routed messages read.
|
||||
|
||||
## Sequencing
|
||||
|
||||
T01 and T02 are the ratification inputs and go first; T07 cannot be
|
||||
answered without them. T03 hangs off T02's document. T04 and T05 are
|
||||
independent and can run any time. T06 is last and cheap.
|
||||
|
||||
Deliberately not blocking on ratification: this repo publishes its
|
||||
declaration whether or not the standard is ratified, because §6 makes
|
||||
accuracy the conformance test and an accurate declaration is useful even if
|
||||
the ladders are later renumbered.
|
||||
|
||||
## Risks
|
||||
|
||||
**Accepting ownership of a policy we cannot enforce.** §8.1 monitoring is
|
||||
the specific case. Mitigation is T03's explicit `unmonitored` marker — an
|
||||
owner who says what is not covered still owns it usefully; one who implies
|
||||
coverage does not.
|
||||
|
||||
**Scope creep into S1/S2.** F1 is the live instance. Mitigation is that
|
||||
this workplan routes the finding and does not build the ingress.
|
||||
|
||||
**A declaration that goes stale the day it is written.** Mitigation is the
|
||||
`reviewed:` date on the vector set and the review interval in the ADR
|
||||
template — the same currency mechanism `policy-nexus` T05 will read.
|
||||
|
||||
## Closed 2026-08-18
|
||||
|
||||
All seven tasks done. What the workplan produced, and what it changed
|
||||
elsewhere:
|
||||
|
||||
- `docs/tenancy-posture.md` + `tenancy.yaml` — the vector set, machine-readable
|
||||
with the human reasoning kept beside it.
|
||||
- `docs/placement-policy.md` — placement rule, owner per workload, triggers,
|
||||
retention floor and ceiling.
|
||||
- `docs/s3-consumer-interfaces.md` `1.1.0` — quota disclosure.
|
||||
- `docs/adr/` — created from nothing; `ADR-0001`, `ADR-0002`, `ADR-0003`.
|
||||
|
||||
**Two findings were adopted upstream.** The provider-declaration proposal (F4,
|
||||
narrowed) is in the framework and its canonical form is the `provider:` block
|
||||
in `tenancy.yaml`. `adaptive-pricing` declined the standing co-signature and
|
||||
supplied a stronger replacement — typed tier minima joined at tier definition —
|
||||
which draft-8 adopted; `ADR-0002` records the outcome as single ownership plus
|
||||
a mandatory typed constraint join, not as an absent signature.
|
||||
|
||||
**Three corrections were issued against our own output**, all in the same
|
||||
direction — claiming levels we could not evidence. `openbao A: 2` retracted to
|
||||
`A: 0`; the provider finding narrowed once §6's `flex-auth` precedent was read;
|
||||
the §11 summary to `adaptive-pricing` corrected, since §11.2 keeps marketing
|
||||
vocabulary free and only the *cannot-reach* claim is restricted, to E4. All
|
||||
three are recorded in the documents rather than edited away.
|
||||
|
||||
**What this workplan deliberately did not do:** fix anything. It found that
|
||||
`apps-pg` had no backup, no per-consumer controls and no isolation probes, and
|
||||
published those as visible defects. `RPF-WP-0019` closes them.
|
||||
|
||||
**Left open, not owned here:** `bao.coulomb.social` still needs confirmation
|
||||
against live reef state (`railiance-master` `ba477968`), and F1's substrate
|
||||
split is with `policy-nexus` to act on.
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
---
|
||||
id: RPF-WP-0019
|
||||
type: workplan
|
||||
title: "apps-pg: backup, per-consumer controls, and the isolation probes they make possible"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-17"
|
||||
updated: "2026-08-20"
|
||||
related:
|
||||
- RPF-WP-0018
|
||||
origin: residual
|
||||
origin_ref: RPF-WP-0018
|
||||
state_hub_workstream_id: "6ded9d76-e3a8-5d52-9221-2c7935f3b364"
|
||||
---
|
||||
|
||||
# RPF-WP-0019 — apps-pg recoverability and per-consumer controls
|
||||
|
||||
## Goal
|
||||
|
||||
Close the three defects `RPF-WP-0018` surfaced in `apps-pg` by writing its
|
||||
quota disclosure. Documentation found them; only this workplan fixes them.
|
||||
|
||||
## Why this is separate from RPF-WP-0018
|
||||
|
||||
That workplan declared posture and policy. This one changes a live cluster.
|
||||
Keeping them apart matters: a declaration workplan that quietly starts editing
|
||||
production is how "we wrote it down" becomes indistinguishable from "we fixed
|
||||
it". The declaration is published as-is, with the defects visible, and this is
|
||||
the record of closing them.
|
||||
|
||||
## The three defects
|
||||
|
||||
**D1 — `apps-pg` has no backup.** No `barmanObjectStore`, no `retentionPolicy`,
|
||||
nothing. This is not a short retention window; it is no recovery path at all,
|
||||
on a cluster holding two S5 application databases. Its R level is `R0` and
|
||||
`R0` here means unrecoverable, not merely un-erasable.
|
||||
|
||||
**D2 — no per-consumer controls.** The connection pool is unpartitioned, so
|
||||
one consumer can exhaust the cluster while staying politely inside its own
|
||||
expectations. No `statement_timeout`, no `idle_in_transaction_session_timeout`,
|
||||
no CPU or memory limits — the pod is BestEffort QoS and is the first thing
|
||||
evicted under node pressure.
|
||||
|
||||
**D3 — no isolation probes**, so the `P1` levels recorded for `vergabe` and
|
||||
`coulomb_social` in `docs/placement-policy.md` §3.1 are provisioning
|
||||
declarations without the §13 artifact.
|
||||
|
||||
## Sequencing, and why it is not the obvious one
|
||||
|
||||
**D1 first.** It is the only one whose failure is unrecoverable. A cluster
|
||||
with no backup is one bad afternoon from data loss that no amount of isolation
|
||||
evidence compensates for.
|
||||
|
||||
**D2 before D3, necessarily.** Tenancy Posture §13.4: an artifact must assert
|
||||
something achievable. The noisy-neighbour artifact requires showing the
|
||||
governance controls *bind*. With no controls there is nothing to bind, so a
|
||||
probe written now could only demonstrate degradation — an artifact that "can
|
||||
only fail, or that passes by being run gently enough". Writing the probe first
|
||||
would produce an overclaim wearing the costume of evidence.
|
||||
|
||||
D1 also depends on a backup target, which is `resource-control`'s bucket and
|
||||
the `platform-pg-backup-s3` credential lane — the same handoff
|
||||
`make postgres-backup-deploy` waits on. Check whether that is now live before
|
||||
assuming this is blocked.
|
||||
|
||||
## Status 2026-08-18 — repository-complete, live-blocked
|
||||
|
||||
Everything this repo can do without touching the cluster is done and
|
||||
committed. What remains on T01, T02 and T04 is a single operator window
|
||||
against a live shared rail, in this order:
|
||||
|
||||
1. `make apps-pg-deploy` — Cluster reconcile: role connection limits,
|
||||
Burstable requests/limits, explicit aggregate parameters.
|
||||
2. Apply `helm/apps-pg-consumer-controls.sql` — the two 15s role timeouts.
|
||||
Idempotent; CNPG 1.28 has no managed-role settings field, so this is
|
||||
operator SQL by necessity, not by preference.
|
||||
3. `make apps-pg-backup-deploy` — the ScheduledBackup, once the governed
|
||||
Secret is confirmed live.
|
||||
4. Capture `LastBackupSucceeded=True` and a scratch restore. **Until both
|
||||
exist, `apps-pg` R stays 0** — declared configuration is not a §13
|
||||
artifact, and this workplan exists because that distinction was missed once
|
||||
already.
|
||||
5. T04's probes, in an announced window, after 1–3 have settled.
|
||||
|
||||
**Blocker resolved 2026-08-18, and it was ours.** The earlier note recorded
|
||||
this as `kubectl` returning `Unauthorized` — an access problem outside the
|
||||
repo. That was wrong. railiance01 is reachable and healthy
|
||||
(`~/.kube/config-railiance01`, k3s v1.35.1, `apps-pg` 9d, both consumers
|
||||
present). What failed was our own wiring: `KUBECONFIG` is an environment
|
||||
variable, so the Makefile's `?=` default never applied, and
|
||||
`RAILIANCE01_KUBECONFIG` pointed at `config-hosteurope` — a different cluster
|
||||
that happens to be unauthorized from here.
|
||||
|
||||
**The near-miss is the finding.** Two reachable clusters each carry a CNPG
|
||||
`Cluster` named `apps-pg` in a namespace named `databases`. The other one
|
||||
(k3s v1.30.3) holds `gitea-db` and only one apps-pg consumer. Had `KUBECONFIG`
|
||||
pointed there instead of at an unauthorized file, `make apps-pg-deploy` would
|
||||
have applied this workplan's connection limits, role timeouts and backup
|
||||
configuration **to the wrong cluster, and reported success.** The
|
||||
`Unauthorized` error was the only thing that prevented it.
|
||||
|
||||
Fixed by pinning cluster *identity* rather than kubeconfig *filename*:
|
||||
`railiance01-guard` compares the live `kube-system` namespace UID against
|
||||
`RAILIANCE01_CLUSTER_UID` and fails closed on mismatch or unreachability. It
|
||||
gates `apps-pg-deploy`, `apps-pg-backup-deploy`, `apps-pg-overflow-dry-run`,
|
||||
`apps-pg-status` and `apps-pg-shell`. Filename selection could not have
|
||||
protected against this: both kubeconfigs resolve to a `127.0.0.1` tunnel port,
|
||||
and the environment overrides the default either way. `make cluster-id` prints
|
||||
what is currently selected.
|
||||
|
||||
The guard is deliberately **not** global. `db-status` legitimately targets the
|
||||
other cluster for `gitea-db`, so a blanket guard would break a working target
|
||||
and teach people to bypass it.
|
||||
|
||||
|
||||
**Do not treat the rollout as evidence.** T04's P1 claim and the R-axis both
|
||||
need artifacts produced *after* application, and `docs/placement-policy.md`
|
||||
§3.1 and `tenancy.yaml` should be updated only then.
|
||||
|
||||
## Status 2026-08-20 — recoverability and controls live
|
||||
|
||||
The guarded live rollout completed against railiance01. The pod reconciled
|
||||
from BestEffort to Burstable QoS, both consumer roles now have a 20-connection
|
||||
limit, the explicit aggregate/logging parameters bind, and controlled SQL
|
||||
applied and verified both 15-second role timeouts. T02 is complete.
|
||||
|
||||
The first WAL archive attempt exposed a repository defect before any recovery
|
||||
claim was made: the runtime identity is intentionally restricted by bucket
|
||||
policy to `platform-pg/*`, while the reviewed manifest used sibling prefix
|
||||
`apps-pg/`. Scaleway correctly denied `PutObject`. Desired state now keeps the
|
||||
cell distinct beneath the governed prefix at `platform-pg/apps-pg/` (and the
|
||||
unprovisioned overflow at `platform-pg/apps-pg-2/`). Continuous archiving then
|
||||
became healthy, the immediate base backup completed in eight seconds, and a
|
||||
separate scratch Cluster restored both consumer databases in 56 seconds.
|
||||
Evidence is `docs/evidence/RPF-WP-0019-backup-restore-2026-08-20.md`. T01 and
|
||||
T02 are complete. T04 subsequently passed 14/14 and the workplan is finished.
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: RPF-WP-0019-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9f0c7e4f-6351-51c1-8c5e-39f770668605"
|
||||
```
|
||||
**Establish a backup target for `apps-pg`.** Confirm the state of the
|
||||
`resource-control` bucket and the `platform-pg-backup-s3` OpenBao Secret; if
|
||||
live, configure `barmanObjectStore` and a `retentionPolicy` on the cluster. If
|
||||
not live, record the dependency and say so — do not leave the absence
|
||||
undocumented a second time.
|
||||
|
||||
2026-08-18 repository readiness: the governed Secret existed live and source
|
||||
carried 30-day retention, continuous WAL and a daily 02:15 backup. At that
|
||||
point it incorrectly used sibling prefix `apps-pg/`; the 2026-08-20 live run
|
||||
proved the bucket policy denied it and corrected the path beneath
|
||||
`platform-pg/`. The ScheduledBackup had not yet been applied and no successful
|
||||
backup/restore evidence existed, so T01 correctly remained progress then.
|
||||
|
||||
Completed live 2026-08-20. The governed path is
|
||||
`platform-pg/apps-pg/`, continuous archiving is healthy, Backup
|
||||
`apps-pg-daily-20260820204148` completed in eight seconds, and a separately
|
||||
named scratch Cluster restored and matched both consumer databases in 56
|
||||
seconds. See `docs/evidence/RPF-WP-0019-backup-restore-2026-08-20.md`.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0019-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8c95e2b5-884c-5504-9998-5bdd8ae64b5d"
|
||||
```
|
||||
**Declare and enforce per-consumer controls.** Per-consumer connection
|
||||
allowance, `statement_timeout`, `idle_in_transaction_session_timeout`, and
|
||||
pod resource requests/limits to lift `apps-pg` off BestEffort QoS. Publish
|
||||
every value in `docs/s3-consumer-interfaces.md` before it takes effect —
|
||||
§10.2 is a disclosure rule, and applying a timeout consumers learn about by
|
||||
hitting it would breach the rule while implementing it.
|
||||
|
||||
2026-08-18 repository readiness: both roles declare a 20-connection limit,
|
||||
the pod has Burstable requests/limits, aggregate/logging parameters are
|
||||
explicit, and controlled operator SQL sets both 15s role timeouts. Every value
|
||||
was published in `docs/s3-consumer-interfaces.md` before application. At that
|
||||
point, live SQL and Cluster reconciliation still required an operator window.
|
||||
|
||||
Completed live 2026-08-20. The railiance01 identity guard passed, the single
|
||||
instance reconciled healthy with Burstable QoS, and PostgreSQL reported both
|
||||
roles at connection limit 20 with `statement_timeout=15s` and
|
||||
`idle_in_transaction_session_timeout=15s`. The declared aggregate and logging
|
||||
parameters were also verified live.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0019-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "9d8c534d-72b7-5cac-ada1-72273fb3ab01"
|
||||
```
|
||||
**Declare the ceiling and overflow target.** Owed under this repo's own
|
||||
Rule P-4.1 before `apps-pg`'s third consumer; it is at two. Name the binding
|
||||
resource per Rule P-4.2 — memory or connections — and a named overflow
|
||||
substrate per P-4.3.
|
||||
|
||||
Completed 2026-08-18. The declared ceiling is three, memory is the binding
|
||||
constraint, and `apps-pg-2` is a named, source-provisionable overflow cell with
|
||||
a distinct credential and backup prefix. `make apps-pg-verify-capacity`
|
||||
rejects a fourth consumer per cell and unbounded/duplicate roles. The cell
|
||||
intentionally remains absent until a fourth consumer is approved.
|
||||
|
||||
```task
|
||||
id: RPF-WP-0019-T04
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "88ef2973-98cd-508a-9b10-73efcf6dce14"
|
||||
```
|
||||
**Isolation probes, after T02.** Consumer-boundary probes on the
|
||||
`rapp-postgres` model, then the §13 noisy-neighbour artifact: per-consumer
|
||||
baseline, saturation run, evidence the controls bind, degradation measured and
|
||||
judged against each consumer's declared service class. Update
|
||||
`docs/placement-policy.md` §3.1 and `docs/tenancy-posture.md` when the P1
|
||||
claims become evidenced.
|
||||
|
||||
Waiting on T02 live application and an announced probe window. No saturation
|
||||
or destructive recovery experiment is run against the shared production rail
|
||||
as part of repository preparation.
|
||||
|
||||
Started 2026-08-20 after T02 completed. The first privilege preflight found
|
||||
that all three databases still inherited PostgreSQL's default `PUBLIC`
|
||||
`CONNECT` and `TEMPORARY` grants, so either consumer could connect to the
|
||||
other's database even though relation grants remained separate. The probe did
|
||||
not launder that into a P1 pass. The controlled SQL and published interface now
|
||||
revoke the defaults and grant each role access only to its own database; live
|
||||
boundary and noisy-neighbour evidence follows that enforcement.
|
||||
|
||||
Completed 2026-08-20. `make apps-pg-isolation-probe` passed 14/14 using the
|
||||
real consumer credentials. The greedy role bound at 20 connections and the
|
||||
next connection was denied; five peer queries stayed available, with measured
|
||||
five-query wall time increasing from 5,285ms to 8,146ms. Both consumers are
|
||||
interactive but declare no numeric database latency objective, so this proves
|
||||
P1 boundary and continued service, not a latency SLO or resource fairness.
|
||||
Evidence: `docs/evidence/RPF-WP-0019-isolation-2026-08-20.md`.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- `apps-pg` only. `platform-pg`'s equivalents are `rapp-postgres`'s.
|
||||
- No consumer is migrated. This changes the cluster, not who is on it.
|
||||
- Values are published before they are enforced, never after.
|
||||
|
||||
## Risks
|
||||
|
||||
**Applying limits to a live cluster breaks a consumer that was relying on
|
||||
their absence.** Most likely with `statement_timeout`. Mitigation is the
|
||||
disclosure-first ordering in T02, which gives consumers a window to object.
|
||||
|
||||
**T01 stays blocked on a handoff outside this repo and the cluster keeps no
|
||||
backup meanwhile.** Mitigation is that T01 requires the dependency be recorded
|
||||
explicitly rather than left as a silent absence — which is exactly how D1
|
||||
survived this long.
|
||||
162
workplans/archived/260905-RPF-WP-0020-ccr-schema-drift.md
Normal file
162
workplans/archived/260905-RPF-WP-0020-ccr-schema-drift.md
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
---
|
||||
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.
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
id: RPF-WP-0026
|
||||
type: workplan
|
||||
title: "Adopt canonical flex-auth credential-grant checks"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-23"
|
||||
updated: "2026-08-23"
|
||||
related:
|
||||
- FLEX-WP-0012
|
||||
origin: routed
|
||||
origin_ref: "State Hub decision 1f9f257d-c9f2-4a5e-a018-8058a3f2a51a"
|
||||
state_hub_workstream_id: "7677326a-04db-52ef-b05c-967dabe1759e"
|
||||
---
|
||||
|
||||
# RPF-WP-0026 — canonical flex-auth credential-grant checks
|
||||
|
||||
## Goal
|
||||
|
||||
Adopt flex-auth's single canonical `POST /v1/check` decision surface for
|
||||
credential-grant preflight without exposing credential values or adding a
|
||||
consumer-specific flex-auth endpoint.
|
||||
|
||||
## T01 — Resolve translation ownership
|
||||
|
||||
```task
|
||||
id: RPF-WP-0026-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "07f3fead-76d6-5e53-9a7b-9930560182d9"
|
||||
```
|
||||
|
||||
The operator explicitly approved Option A in State Hub decision
|
||||
`1f9f257d-c9f2-4a5e-a018-8058a3f2a51a`: railiance-platform maps its grant
|
||||
metadata to `CheckRequest` and reads `DecisionEnvelope`. Duration parsing and
|
||||
normalization belong here, before the flex-auth policy boundary.
|
||||
|
||||
## T02 — Implement the canonical request and response
|
||||
|
||||
```task
|
||||
id: RPF-WP-0026-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "659ac0ee-c2b7-56fc-80d8-92b2fcf30e7b"
|
||||
```
|
||||
|
||||
Change the helper default to `/v1/check`, emit the coordinated
|
||||
`tenant:platform` / `credential-grant:<id>` / `issue` request vocabulary, send
|
||||
`requested_ttl_seconds` as an integer, and accept only `effect: allow`.
|
||||
|
||||
Completed in source. Actor classes map to canonical subject types (`Human`,
|
||||
`Agent`, or `Automation`); the bound subject and non-secret actor metadata are
|
||||
carried in context. Missing, deny, redact, audit-only, and not-applicable
|
||||
effects all fail closed. An allow also requires a non-empty decision id,
|
||||
evaluator provenance, and subject/resource binding back to the request.
|
||||
|
||||
## T03 — Verify and route the contract
|
||||
|
||||
```task
|
||||
id: RPF-WP-0026-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "8f6b7481-e8c2-56eb-98b5-c49cae562d60"
|
||||
```
|
||||
|
||||
Exercise focused allow and deny tests, validate the complete repository suite,
|
||||
and route the adopted mapping to flex-auth without requesting live credentials
|
||||
or a production mutation.
|
||||
|
||||
Completed with 70 focused credential tests, all credential-helper dry-runs,
|
||||
credential-catalog validation, and the complete 146-test offline suite passing.
|
||||
No flex-auth production endpoint was called and no credential was issued.
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
id: RPF-WP-0028
|
||||
type: workplan
|
||||
title: "Make Forgejo image protection survive checkout replacement"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-05"
|
||||
state_hub_workstream_id: "622d1208-b085-5ec2-9fb7-5e41f23e1843"
|
||||
---
|
||||
|
||||
# Make Forgejo image protection survive checkout replacement
|
||||
|
||||
Source: State Hub message `868a2326-cdad-4256-be4c-7cd6c8ec4b5b`. Reviewed against current repository state
|
||||
on 2026-09-05. Repository implementation and live inventory migration are complete.
|
||||
|
||||
## Implement and verify durable publication
|
||||
|
||||
```task
|
||||
id: RPF-WP-0028-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "869d4114-3642-5e69-88d1-1d14e5547634"
|
||||
```
|
||||
|
||||
Implemented scripts/refresh_live_images.py and make live-images-refresh. Publication validates exports before mutation, locks concurrent writers, retains all previous cluster entries, and fsyncs an atomic replacement. Offline tests prove repeatability, multi-cluster retention, and preservation on missing, empty, or malformed input.
|
||||
|
||||
The local prune CLI was additionally hardened on 2026-09-05 to refuse apply
|
||||
before credential lookup if any explicitly requested export is missing,
|
||||
unreadable, empty, or comment-only. Regression coverage includes a valid file
|
||||
alongside a bad one, proving partial coverage cannot authorize deletion.
|
||||
|
||||
## Install production projection and rollout refresh
|
||||
|
||||
```task
|
||||
id: RPF-WP-0028-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "2d0795ba-ccc0-5ba9-8315-2deb4d0d71a6"
|
||||
```
|
||||
|
||||
Requires the production host inventory, activity-core directory mount/configuration update, and cluster rollout hook adoption. Follow docs/forgejo-package-prune.md. Preserve the restored union and worker refusal on missing/empty inventory; do not manually trigger prune. Completed 2026-09-05: installed the versioned helper outside the checkout,
|
||||
seeded all 51 restored entries and merged a fresh railiance01 export (86 total),
|
||||
added the read-only directory mount, rolled out actcore-worker, and synced the
|
||||
exact definition override. API readback confirms the durable path. The resolver
|
||||
accepts that path and refuses missing input before subprocess execution; the
|
||||
command construction check used a mock and did not run prune. A post-rollout
|
||||
capture succeeded. Activity-core's refresh target delegates to this hook; invoke
|
||||
it after subsequent cluster rollouts (no new periodic schedule was introduced).
|
||||
Evidence: `docs/evidence/RPF-WP-0028-live-inventory-2026-09-05.json`.
|
||||
Source revisions: platform `da42f76`, activity-core `4083f31`.
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
---
|
||||
id: RPF-WP-0030
|
||||
type: workplan
|
||||
title: "Unblock rapp-core-hub publication and platform onboarding"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-20"
|
||||
updated: "2026-09-05"
|
||||
related:
|
||||
- CORE-WP-0011
|
||||
- RAPPCOREHUB-WP-0001
|
||||
- RAPP-POSTGRES-WP-0003
|
||||
origin: request
|
||||
origin_ref: CORE-WP-0011
|
||||
state_hub_workstream_id: "f7a13cc2-7b1f-5644-89a8-b4e9a934b018"
|
||||
---
|
||||
|
||||
# RPF-WP-0030 — Core Hub platform onboarding
|
||||
|
||||
## Goal
|
||||
|
||||
Provide the platform-owned dependencies that let the validated
|
||||
`rapp-core-hub` package publish and deploy as a private shadow runtime on
|
||||
railiance01 before the 2026-08-31 CoulombCore retirement deadline.
|
||||
|
||||
This work stops before public traffic cutover, the final data freeze, or
|
||||
retirement of the old runtime. Those remain explicit operator gates in
|
||||
`CORE-WP-0011`.
|
||||
|
||||
## Current evidence
|
||||
|
||||
- `/home/worsch/rapp-core-hub` is clean at commit `18e4e70`; its full package
|
||||
check, family validation, and railiance01 server-side dry-run passed.
|
||||
- `coulomb/rapp-core-hub` is private and authoritative in Forgejo. Its history
|
||||
preserves validated package commit `4403c9b`, and unauthenticated API access
|
||||
returns 404.
|
||||
- State Hub registered the repository and canonical workplan prefix
|
||||
`RAPPCOREHUB-WP-`. The production registrar still needs to assign the
|
||||
workplan UUID.
|
||||
- `agent-high-risk-boundary` deliberately denies agent data-read to the
|
||||
Forgejo site-admin PAT. That control is not removed to make publication
|
||||
convenient; an attended operator identity must authorize the child-process
|
||||
transport.
|
||||
- The package requests a `rapp-postgres.v1` consumer and a Kubernetes Secret
|
||||
containing `CORE_HUB_DATABASE_URL` plus `CORE_HUB_API_TOKEN`.
|
||||
- A live metadata-only railiance01 check on 2026-08-20 found OpenBao Ready and
|
||||
the Kubernetes-auth-backed `openbao` ClusterSecretStore Valid. The existing
|
||||
audit-core KV and database stores are also Valid and their ExternalSecrets
|
||||
are synced, so the two-store shape has a live reference on the target rail.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- No secret value enters Git, State Hub, logs, command output, or agent
|
||||
context.
|
||||
- A repository is created only through the owned Forgejo admin lane.
|
||||
- The static Core Hub API token and dynamic PostgreSQL lease remain distinct
|
||||
custody sources even if the workload consumes both as environment data.
|
||||
- A short-lived database lease is not copied into a standing OpenBao KV path.
|
||||
- A private shadow deployment is allowed only after the database credential
|
||||
rotation behavior is explicit and testable.
|
||||
- Public Ingress, final transfer, DNS/tunnel changes, and old-runtime removal
|
||||
remain outside this workplan.
|
||||
|
||||
## T01 — Publish and register `rapp-core-hub`
|
||||
|
||||
```task
|
||||
id: RPF-WP-0030-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b561e71e-213e-506f-8eaf-578eef54977f"
|
||||
```
|
||||
|
||||
Under an attended `net-kingdom-admins` OIDC login to
|
||||
`forgejo-admin-workload-kv-read`, verify capabilities on the Forgejo admin KV
|
||||
data and metadata paths without reading the value. Then use
|
||||
`warden access forgejo-admin-api-token --exec` to create the private
|
||||
`coulomb/rapp-core-hub` repository, push commit `4403c9b`, configure the remote,
|
||||
and run `statehub fix-consistency` from the published repo.
|
||||
|
||||
Current blocker: both the original request and a 2026-08-20 retry reached
|
||||
OpenBao but received HTTP 403 on
|
||||
`sys/internal/ui/mounts/platform/workloads/forgejo/forgejo-admin`. The retry
|
||||
also found the local warden audit path read-only. Do not weaken
|
||||
`agent-high-risk-boundary`; repair or establish the operator session and use
|
||||
the non-disclosing exec transport.
|
||||
|
||||
Concurrent publication evidence, discovered at 07:55Z: Forgejo repository
|
||||
`coulomb/rapp-core-hub` was created at 07:42:41Z, but it is public rather than
|
||||
private and contains only Forgejo's `Initial commit` (`eea94d9`, README only).
|
||||
The local validated commit `4403c9b` is not the remote `main`, although the
|
||||
local remote is configured. Do not push the package into the public repo.
|
||||
First change visibility to private through the owned admin lane, correct the
|
||||
repository description, then push and verify `refs/heads/main` equals the
|
||||
validated commit.
|
||||
|
||||
Completed 2026-08-20 after operator authorization. Unauthenticated Forgejo API
|
||||
access now returns 404 while the configured Git remote is accessible. Remote
|
||||
`main` is `18e4e70`: its history preserves validated package commit `4403c9b`,
|
||||
the Forgejo README stub through merge `7dd057e`, publication evidence, the
|
||||
project goal, and the registered-prefix alignment. Local and remote `main`
|
||||
match.
|
||||
`make check`, the railiance01 server-side dry-run, and family validation
|
||||
(`4 declaration(s) ok`) passed after publication. The repo is registered in
|
||||
State Hub; workplan UUID assignment remains with the production registrar.
|
||||
|
||||
## T02 — Accept the Core Hub PostgreSQL consumer
|
||||
|
||||
```task
|
||||
id: RPF-WP-0030-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "5ed30960-336c-5650-96c6-9395ea7f2584"
|
||||
```
|
||||
|
||||
Review `/home/worsch/rapp-core-hub/handoffs/postgres-consumer.yaml` in
|
||||
`rapp-postgres`, add the accepted declaration, render it, and run package
|
||||
tests. The requested database, schema, role split, connection limits, timeout,
|
||||
service class, and tenant-keying posture match the existing consumer contract.
|
||||
|
||||
Capacity is an admission condition. With `audit-core`, `tenant-engine`, and
|
||||
the counted isolation probe, Core Hub is the fourth declaration on
|
||||
`platform-pg`: it reaches but does not exceed the ADR-0004 ceiling. Before
|
||||
admitting this third workload consumer, record the required measured memory
|
||||
baseline. The untracked `consumers/issue-core.yaml` is not a real consumer —
|
||||
`ISSUE-WP-0007` explicitly removed Postgres from that package — and must not
|
||||
silently consume a slot.
|
||||
|
||||
OpenBao database role configuration remains an attended operation under T04.
|
||||
|
||||
Read-only preflight 2026-08-20: `platform-pg-1` used 9m CPU and 362Mi memory
|
||||
against a 1Gi limit, with only `audit_core` and operator sessions present;
|
||||
`tenant_engine` was not yet a database. This establishes current headroom but
|
||||
does not satisfy ADR-0004's representative multi-consumer peak measurement.
|
||||
Evidence: `docs/evidence/core-hub-postgres-capacity-preflight-2026-08-20.md`.
|
||||
|
||||
Capacity admission completed 2026-08-20. A bounded live probe opened 56
|
||||
sessions in four declaration groups and repeated the occupancy with one active
|
||||
bounded sort per group. `platform-pg` peaked at 174Mi/1Gi; the 85Mi increase is
|
||||
about 1.52Mi per opened backend. Even adding that delta to the earlier 362Mi
|
||||
sample yields 447Mi, under 44% of the limit. Core Hub is accepted as the fourth
|
||||
and final declaration without raising the pod limit. Evidence:
|
||||
`docs/evidence/core-hub-postgres-capacity-admission-2026-08-20.md`.
|
||||
|
||||
Completed 2026-08-20. `rapp-postgres` commit `4f316cc` accepts and publishes
|
||||
the Core Hub declaration as the fourth `platform-pg` consumer. All 31 package
|
||||
tests and consumer rendering passed; the railiance01 server-side dry-run
|
||||
accepted the generated resource. The idempotent package provisioner then
|
||||
created `core_hub`, its `core_hub` schema, distinct NOLOGIN owner/migration/
|
||||
runtime roles and bounded role settings. CNPG `Database/core-hub` reports
|
||||
`status.applied=true`, targets `platform-pg`, retains the database on resource
|
||||
deletion, and names `core_hub_owner` as owner.
|
||||
|
||||
## T03 — Correct the runtime credential delivery contract
|
||||
|
||||
```task
|
||||
id: RPF-WP-0030-T03
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ad022406-0ae5-58db-9b9d-2e958ab73237"
|
||||
```
|
||||
|
||||
Separate the two credential sources before shadow deployment:
|
||||
|
||||
1. `CORE_HUB_API_TOKEN` is a standing workload secret in OpenBao KV, governed
|
||||
by a proposed CCR and projected by a namespace-limited ESO store.
|
||||
2. Runtime and migration PostgreSQL credentials come from distinct
|
||||
`database/creds/core-hub-*` roles and the database-engine ESO store. One
|
||||
extract must provide each username/password pair so leases are not mixed.
|
||||
|
||||
The current package consumes one `core-hub-runtime` Secret through `envFrom`
|
||||
for both the Deployment and migration Job. That is not yet a safe dynamic
|
||||
lease contract: environment variables do not update when ESO refreshes a
|
||||
Secret, and no workload reloader is declared. Update the package to consume
|
||||
separate runtime/migration database Secrets and the static API-token Secret,
|
||||
then either:
|
||||
|
||||
- restart the Deployment automatically and demonstrably before each lease
|
||||
expires; or
|
||||
- change Core Hub to re-read mounted credential files when opening a new
|
||||
database connection.
|
||||
|
||||
Prefer the mounted-file approach for steady state. A time-bounded automatic
|
||||
restart contract may be used for the relocation only if rollback and lease
|
||||
overlap are proven and the temporary limitation is recorded.
|
||||
|
||||
Completed 2026-08-21. Static API, runtime database, and migration database
|
||||
credentials are mounted from three disjoint Secrets; the database URL exists
|
||||
only in the supervised child environment, and the migration Job mounts only
|
||||
its role. Live proof exposed that chart `0.3.0` watcher exit 75 could accumulate
|
||||
planned Kubelet restarts into CrashLoopBackOff. Chart `0.3.1` (`rapp-core-hub`
|
||||
commit `7cfa8bb`) instead keeps PID 1 alive and restarts only the application
|
||||
child after reading the refreshed files. Nine package tests and live proof
|
||||
showed a changed Secret resourceVersion and child PID with stable pod UID,
|
||||
container restart count `0 -> 0`, restored readiness, and the five-minute
|
||||
refresh interval restored.
|
||||
|
||||
## T04 — Declare and apply the OpenBao/ESO lanes
|
||||
|
||||
```task
|
||||
id: RPF-WP-0030-T04
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d4c2d69d-186a-5d0d-9ab7-5a4a48cb1e8d"
|
||||
```
|
||||
|
||||
After T03 fixes the consuming contract:
|
||||
|
||||
- draft and approve a workload-KV CCR for the static API token;
|
||||
- add a least-privilege ESO policy covering only the Core Hub static-token KV
|
||||
path and `database/creds/core-hub-runtime` / `core-hub-migration`;
|
||||
- configure the database roles from the accepted Postgres declaration;
|
||||
- create namespace-limited KV and database `ClusterSecretStore` objects;
|
||||
- project runtime and migration Secrets without printing values; and
|
||||
- prove positive sync, cross-namespace denial, lease rotation, and migration
|
||||
role separation.
|
||||
|
||||
The working audit-core implementation is the reference for the two-store
|
||||
shape. Do not copy its earlier, rejected idea of freezing a dynamic lease in
|
||||
KV.
|
||||
|
||||
Progress 2026-08-20: drafted `CCR-2026-0013` for the static API token, added
|
||||
its exact-path read policy, added a not-yet-applied namespace-limited
|
||||
`openbao-core-hub-runtime` ClusterSecretStore, and extended the agent
|
||||
high-risk boundary to deny direct data reads on the new path. Database-engine
|
||||
policy/store manifests wait for the accepted Postgres declaration and the T03
|
||||
consumer correction.
|
||||
|
||||
Progress 2026-08-20 after T02 admission: added an exact two-path database ESO
|
||||
policy, a namespace-limited `openbao-core-hub-database` store, and three
|
||||
disjoint ExternalSecrets. Runtime and migration each use one `dataFrom.extract`
|
||||
so a username/password pair comes from one lease; both refresh every five
|
||||
minutes. The database store and all projections passed railiance01 server-side
|
||||
dry-run. The package namespace is live with the reviewed `platform-pg` client
|
||||
label. Live role/store activation correctly stopped because the current
|
||||
OpenBao session receives 403 and CCR-2026-0013 is still proposed; no authority
|
||||
or placeholder Secret was improvised. State Hub decision
|
||||
`4f70311b-a4c4-4959-b1a1-cdd1be97d523` now carries the non-secret review
|
||||
coordinates and awaits the required platform-operator/Core-Hub-owner approval.
|
||||
`rapp-postgres` commit `cfde57a` now also owns the Core Hub database-engine
|
||||
roles, 30-minute runtime/10-minute migration TTLs, exact two-path ESO policy,
|
||||
and non-disclosing renewable-token delivery script. Its 33 tests pass. Live
|
||||
configuration still waits for the attended OpenBao authority; concurrent
|
||||
tenant-engine workplan edits in that repository were preserved and excluded
|
||||
from this commit.
|
||||
|
||||
Completed 2026-08-21 after the operator approved State Hub decision
|
||||
`4f70311b-a4c4-4959-b1a1-cdd1be97d523` and completed attended OpenBao OIDC.
|
||||
The policy, auth role, database roles, two namespace-limited stores, and three
|
||||
disjoint ExternalSecrets are live and Ready. The existing API token moved
|
||||
directly from source Kubernetes custody into OpenBao without appearing in
|
||||
output. Outside-namespace store denial, exact-path Kubernetes-auth denial,
|
||||
runtime DDL denial, migration DDL success, ESO sync, and live lease rotation
|
||||
all passed. `CCR-2026-0013` is verified.
|
||||
|
||||
## T05 — Support the private shadow restore and verification
|
||||
|
||||
```task
|
||||
id: RPF-WP-0030-T05
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1b608d2e-d660-50dd-8765-c429afbcb14c"
|
||||
```
|
||||
|
||||
After T01-T04, support `CORE-WP-0011-T03`: label the namespace for
|
||||
`platform-pg`, restore or logically transfer the source database, reconcile
|
||||
table and row counts, run the migration Job with the migration lease, deploy
|
||||
with Ingress disabled, and verify health plus authenticated consumers against
|
||||
the private endpoint.
|
||||
|
||||
This task ends with repeatable shadow evidence. It does not flip
|
||||
`hub.coulomb.social`, freeze production writes, or remove CoulombCore.
|
||||
|
||||
Preflight 2026-08-20: the source has Alembic revision `20260627_0002`, eight
|
||||
public tables and 39 total rows. The admitted target intentionally has no
|
||||
application tables before restore. A ready disposable pod in the labeled
|
||||
`core-hub` namespace resolved the `platform-pg` service and reached its
|
||||
PostgreSQL port; it was deleted after the check. No dump or restore was
|
||||
attempted ahead of the T04 credential gate. Evidence:
|
||||
`docs/evidence/core-hub-shadow-preflight-2026-08-20.md`.
|
||||
|
||||
Completed 2026-08-21. A consistent logical archive restored all eight source
|
||||
tables and 39 rows at Alembic revision `20260627_0002`; the restored tables
|
||||
were reconciled into the accepted `core_hub` schema with owner and runtime
|
||||
grants verified. Helm release revision 2 deployed chart `0.3.1` with Ingress
|
||||
disabled, and the migration Job completed. The hardened private verifier and
|
||||
authenticated smoke `20260820224419-43dc05` passed all health, readiness,
|
||||
catalog, denial, and protected-operation checks. Detailed non-secret evidence:
|
||||
`docs/evidence/core-hub-private-shadow-2026-08-21.md`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [x] Private Forgejo repo exists, validated commit `4403c9b` is preserved,
|
||||
and the registered workplan prefix is consistent.
|
||||
- [x] Core Hub is an accepted, capacity-reviewed `rapp-postgres` consumer.
|
||||
- [x] Static API-token and dynamic database credentials have distinct,
|
||||
least-privilege delivery paths.
|
||||
- [x] Database credential rotation cannot leave a running pod using an expired
|
||||
environment value.
|
||||
- [x] Private shadow restore, reconciliation, migration, and consumer smokes
|
||||
pass without enabling public Ingress.
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
id: RPF-WP-0031
|
||||
type: workplan
|
||||
title: "Separate duplicated apps-pg and Core Hub workplan identities"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-05"
|
||||
state_hub_workstream_id: "dcc4fab2-2e95-570a-a415-6528c4cd8d11"
|
||||
---
|
||||
|
||||
# Separate duplicated workplan identities
|
||||
|
||||
## Diagnose and prepare the exact repair
|
||||
|
||||
```task
|
||||
id: RPF-WP-0031-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "8f75c85f-b442-5188-8b07-47a99251c0cf"
|
||||
```
|
||||
|
||||
The supported `rmgr sync --path . --push` path reached the verified primary
|
||||
railiance01 projection in 5.8 seconds, but refused six duplicate identities.
|
||||
Both the May apps-pg archive and August Core Hub onboarding use RPF-WP-0021,
|
||||
the same workplan UUID, and the same first five task UUIDs. No projection rows
|
||||
were created, changed, or retired by the refused reconciliation.
|
||||
|
||||
`docs/evidence/RPF-WP-0021-collision-repair-proposal.json` fixes the proposed
|
||||
choice: retain the older archive and reidentify the newer onboarding record as
|
||||
RPF-WP-0030, with six Repo Manager-derived UUIDs and four evidence-reference
|
||||
updates. Existing source UUIDs have not been changed.
|
||||
|
||||
## Apply the identity repair and reconcile
|
||||
|
||||
```task
|
||||
id: RPF-WP-0031-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "2990a940-634c-5d76-b74c-740de8c36b16"
|
||||
```
|
||||
|
||||
Requires a one-time user exception to AGENTS.md's prohibition on editing managed
|
||||
UUID fields. The existing Repo Manager migration command considers only live
|
||||
workplans and unfinished tasks, so it does not repair these finished records.
|
||||
After approval, apply the exact proposal, preserve the archived identity and
|
||||
all completion evidence, check uniqueness across root and archived workplans,
|
||||
commit/push, and run `rmgr sync`. Inspect any retirement refusal before proceeding;
|
||||
never blanket-acknowledge unrelated retirements.
|
||||
|
||||
|
||||
User approved the exact exception on 2026-09-05. Applied the six proposed UUIDs
|
||||
and four evidence-reference updates; the archived file is byte-for-byte unchanged.
|
||||
All 196 source IDs and 196 UUIDs are unique across root and archived files.
|
||||
Primary/railiance01 verified the pushed `6b41a43` commit and applied the source
|
||||
projection in 12 seconds: four workplans created, 30 updated, no retirements,
|
||||
no refusals, no cancelled tasks. RPF-WP-0028/0029/0030/0031 are now projected.
|
||||
Receipt: `docs/evidence/RPF-WP-0031-reconciliation-2026-09-05.json`.
|
||||
The approved identity repair and its authoritative reconciliation are complete.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
id: RPF-WP-0032
|
||||
type: workplan
|
||||
title: "Design secrets-engine service JWT login"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-05"
|
||||
state_hub_workstream_id: "bd036850-e1bf-5b70-bbc3-683dfa4b125c"
|
||||
---
|
||||
|
||||
# Design secrets-engine service JWT login
|
||||
|
||||
## Prepare the platform design
|
||||
|
||||
```task
|
||||
id: RPF-WP-0032-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "166ece0b-840b-54b8-b10c-45f96eda0429"
|
||||
```
|
||||
|
||||
Reviewed owner source and the current platform CCR contract. Delivered
|
||||
`docs/credential-lane-designs/secrets-engine-service-jwt.md` with proposed exact scope, custody, lifecycle, implementation gaps,
|
||||
approval requirements and positive/negative acceptance evidence. This is a
|
||||
completed design deliverable, not a live lane or approval. No secrets accessed,
|
||||
production objects changed or owner messages sent.
|
||||
|
||||
## Obtain owner inputs and implement the approved lane
|
||||
|
||||
```task
|
||||
id: RPF-WP-0032-T02
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "d1f4a9f6-4ea5-5daa-97bb-039856855bc2"
|
||||
```
|
||||
|
||||
Confirm issuer, verification endpoint, actual KeyCape registration and live auth mount survey. Approve the login-only role/self policy, implement reviewed declarative support and prove effective-policy, wrong-claim, expiry and cleanup checks. Native lane execution still requires its separate exact authorization and scoped authority.
|
||||
|
||||
Review the linked design and pin current source revisions before implementation.
|
||||
Do not interpret this workplan or a proposed coordinate as live authorization.
|
||||
|
||||
## Portfolio review — 2026-09-05
|
||||
|
||||
The design deliverable is complete. The implementation obligation is preserved
|
||||
in **RPF-WP-0035-T02**, the single credential-lane implementation queue.
|
||||
T02 is `cancel` here only because it is superseded there; it is not implemented,
|
||||
waived or externally accepted. The approved design scope and all existing
|
||||
identifiers remain unchanged. Archived on 2026-09-05 after this consolidation.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
id: RPF-WP-0033
|
||||
type: workplan
|
||||
title: "Design fluid-telegram attended operator KV lane"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-05"
|
||||
state_hub_workstream_id: "957d49b9-6b84-5fde-89d0-4c2efef70067"
|
||||
---
|
||||
|
||||
# Design fluid-telegram attended operator KV lane
|
||||
|
||||
## Prepare the platform design
|
||||
|
||||
```task
|
||||
id: RPF-WP-0033-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "6d305189-61f3-5750-8e4f-5cd97b92f324"
|
||||
```
|
||||
|
||||
Reviewed owner source and the current platform CCR contract. Delivered
|
||||
`docs/credential-lane-designs/fluid-telegram-operator-kv.md` with proposed exact scope, custody, lifecycle, implementation gaps,
|
||||
approval requirements and positive/negative acceptance evidence. This is a
|
||||
completed design deliverable, not a live lane or approval. No secrets accessed,
|
||||
production objects changed or owner messages sent.
|
||||
|
||||
## Obtain owner inputs and implement the approved lane
|
||||
|
||||
```task
|
||||
id: RPF-WP-0033-T02
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "a542697f-adf8-59ac-9704-0bcde1d9fd0f"
|
||||
```
|
||||
|
||||
Obtain tenant/group/MFA decisions; extend the CCR schema, validator, renderer and ops-mason executor for the exact four-entry matrix; correct the consumer tenant default, atomic salt creation and preflight output. Complete an attended installed-engine probe and boundary checks before any routing activation.
|
||||
|
||||
Review the linked design and pin current source revisions before implementation.
|
||||
Do not interpret this workplan or a proposed coordinate as live authorization.
|
||||
|
||||
## Portfolio review — 2026-09-05
|
||||
|
||||
The design deliverable is complete. The implementation obligation is preserved
|
||||
in **RPF-WP-0035-T03**, the single credential-lane implementation queue.
|
||||
T02 is `cancel` here only because it is superseded there; it is not implemented,
|
||||
waived or externally accepted. The approved design scope and all existing
|
||||
identifiers remain unchanged. Archived on 2026-09-05 after this consolidation.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
id: RPF-WP-0034
|
||||
type: workplan
|
||||
title: "Design State Hub preflight signing custody"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: finished
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-05"
|
||||
state_hub_workstream_id: "5233ef7d-200e-5ca7-8b8c-897b12de4377"
|
||||
---
|
||||
|
||||
# Design State Hub preflight signing custody
|
||||
|
||||
## Prepare the platform design
|
||||
|
||||
```task
|
||||
id: RPF-WP-0034-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "bb9e53a9-63b1-5500-8b30-96c5252b8d61"
|
||||
```
|
||||
|
||||
Reviewed owner source and the current platform CCR contract. Delivered
|
||||
`docs/credential-lane-designs/state-hub-preflight-signing.md` with proposed exact scope, custody, lifecycle, implementation gaps,
|
||||
approval requirements and positive/negative acceptance evidence. This is a
|
||||
completed design deliverable, not a live lane or approval. No secrets accessed,
|
||||
production objects changed or owner messages sent.
|
||||
|
||||
## Obtain owner inputs and implement the approved lane
|
||||
|
||||
```task
|
||||
id: RPF-WP-0034-T02
|
||||
status: cancel
|
||||
priority: high
|
||||
state_hub_task_id: "96e4864a-fd17-529b-a72f-69ffd885a962"
|
||||
```
|
||||
|
||||
Confirm exact primary deployment and delivery identity; approve the writer and read CCR; implement dedicated ESO/API-only delivery and a concrete rotation fence. Provision only in an approved window, prove preflight signing without executing a rename, and record API/ESO health and negative access evidence.
|
||||
|
||||
Review the linked design and pin current source revisions before implementation.
|
||||
Do not interpret this workplan or a proposed coordinate as live authorization.
|
||||
|
||||
## Portfolio review — 2026-09-05
|
||||
|
||||
The design deliverable is complete. The implementation obligation is preserved
|
||||
in **RPF-WP-0035-T04**, the single credential-lane implementation queue.
|
||||
T02 is `cancel` here only because it is superseded there; it is not implemented,
|
||||
waived or externally accepted. The approved design scope and all existing
|
||||
identifiers remain unchanged. Archived on 2026-09-05 after this consolidation.
|
||||
Loading…
Add table
Add a link
Reference in a new issue