2026-09-05 00:41:17 +02:00
|
|
|
---
|
|
|
|
|
id: KEY-WP-0014
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "Review native login and client credential lane handoffs"
|
|
|
|
|
domain: infotech
|
|
|
|
|
repo: key-cape
|
2026-09-05 01:08:58 +02:00
|
|
|
status: blocked
|
2026-09-05 00:41:17 +02:00
|
|
|
owner: codex
|
|
|
|
|
topic_slug: native-credential-lane-handoff
|
|
|
|
|
created: "2026-09-05"
|
Close the KEY-WP-0009 handoff gap and deliver the two blocked admissions
KEY-WP-0009-T04 is done. Re-ran verification on main with an explicit Go 1.23.0
toolchain and a writable build cache: contract validator PASS, build, vet and the
full test suite pass, git diff --check clean. gofmt had drifted on
internal/server/telemetry/events.go and tests/migration/scenario_c_test.go
(comment alignment only, no semantic change); both reformatted so the task's
formatting claim holds. The four handoffs to netkingdom, secrets-engine,
ops-warden and railiance-platform were then actually sent -- the 2026-09-05 audit
had shown the earlier claimed delivery had no receipts -- and each receipt id is
recorded in the workplan and readable back from the hub.
KEY-WP-0013-T02 and KEY-WP-0014-T04 stay in wait. Their remaining work is not
ours to do, so what was owed was the request, and it is now delivered: custody
admission for the two approval clients to railiance-platform, the exact human
client id and callback URI to approval-engine, and the OpenBao-token vs
issuer-JWT split plus Qonto rotation execution authority to ops-warden. Each
message quotes the existing non-secret packet or reviewed sequence and states
what is explicitly not being treated as authorization.
No secret was read, no production resource changed, no route retired.
SCOPE.md updated to match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV8zoCKpA1WRAxsKRYbdH
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1182213@bnt-lap001
Assistant-Session: 966597b9-ae61-46a4-8b9e-1594ab3ec4ad
2026-09-08 10:22:52 +02:00
|
|
|
updated: "2026-09-08"
|
2026-09-05 00:41:17 +02:00
|
|
|
state_hub_workstream_id: "0d003df3-f7d3-5063-8ca0-e1e33f7df74a"
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Source: ops-warden inbox message 0dd9c7bd-0ecd-42d1-806f-7cc4ba9730ed.
|
2026-09-05 01:08:58 +02:00
|
|
|
The native service exchange and public PKCE login commands are now implemented.
|
|
|
|
|
Cross-owner rotation and consumer-specific route cutover remain outstanding.
|
2026-09-05 00:41:17 +02:00
|
|
|
|
|
|
|
|
## Design owner command and custody boundaries
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0014-T01
|
2026-09-05 01:08:58 +02:00
|
|
|
status: done
|
2026-09-05 00:41:17 +02:00
|
|
|
priority: medium
|
|
|
|
|
state_hub_task_id: "0c0a0b61-c19e-5631-9cda-8b2dc0f47d8f"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Review ops-warden's existing key-cape-oidc-login proxy and
|
|
|
|
|
rapp-qonto-keycape-client route contracts. Specify the native interactive login
|
|
|
|
|
and bounded exchange commands, token delivery, renewal and custody-mediated
|
|
|
|
|
rotation before implementation. Keep secret custody with OpenBao and avoid
|
|
|
|
|
retiring the proxy until replacement commands have equivalent verification.
|
|
|
|
|
|
|
|
|
|
## Verify handoff delivery evidence
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0014-T02
|
2026-09-05 01:08:58 +02:00
|
|
|
status: done
|
2026-09-05 00:41:17 +02:00
|
|
|
priority: low
|
|
|
|
|
state_hub_task_id: "d9a5de97-b7d5-5599-98c2-eaab32f51495"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Ops-warden reports KEY-WP-0009-T04's claimed reply did not arrive. Verify prior
|
|
|
|
|
receipts for all four named recipients before claiming successful notification.
|
|
|
|
|
No outbound coordination messages were sent during the 2026-09-05 repo review.
|
2026-09-05 01:08:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
## Implement and verify native caller commands
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0014-T03
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "4e46f474-a15e-594f-ae07-ad37a9667d89"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Implemented keycape service-token and login with HTTPS discovery, RS256/JWKS
|
|
|
|
|
verification, exact audience bindings, PKCE/state/nonce, private out-of-Git file
|
|
|
|
|
delivery and redacted errors. Service Basic authentication now form-decodes
|
|
|
|
|
credentials. Integration tests exercise the real token/JWKS handlers and browser
|
|
|
|
|
callback, including forged state, tampering, excess scope and unsafe output.
|
|
|
|
|
See docs/native-authentication.md for invocation and ownership boundaries.
|
|
|
|
|
|
|
|
|
|
## Admit rotation and verify consumer handoff
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0014-T04
|
|
|
|
|
status: wait
|
|
|
|
|
priority: high
|
|
|
|
|
state_hub_task_id: "e7632c71-9676-5837-a925-7f905e3015c5"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Qonto rotation requires admitted custody/provider transaction and rollback
|
|
|
|
|
semantics; see the exact review sequence in docs/native-authentication.md.
|
|
|
|
|
The current login proxy yields an OpenBao token, so it cannot be replaced by a
|
|
|
|
|
JWT-writing command without adapting its consumer contract. Verify that split
|
|
|
|
|
with the platform owner and ops-warden before route changes. No route was changed.
|
|
|
|
|
|
|
|
|
|
2026-09-05 receipt audit: GET /messages/?from_agent=key-cape returned one
|
|
|
|
|
2026-03 image-publication message and no KEY-WP-0009 handoff receipts for
|
|
|
|
|
NetKingdom, secrets-engine, ops-warden or railiance-platform. Corrected the
|
|
|
|
|
unsupported statement in KEY-WP-0009-T04. This proves only that no receipts
|
|
|
|
|
are present in the current Hub response, not that no message ever existed.
|
Close the KEY-WP-0009 handoff gap and deliver the two blocked admissions
KEY-WP-0009-T04 is done. Re-ran verification on main with an explicit Go 1.23.0
toolchain and a writable build cache: contract validator PASS, build, vet and the
full test suite pass, git diff --check clean. gofmt had drifted on
internal/server/telemetry/events.go and tests/migration/scenario_c_test.go
(comment alignment only, no semantic change); both reformatted so the task's
formatting claim holds. The four handoffs to netkingdom, secrets-engine,
ops-warden and railiance-platform were then actually sent -- the 2026-09-05 audit
had shown the earlier claimed delivery had no receipts -- and each receipt id is
recorded in the workplan and readable back from the hub.
KEY-WP-0013-T02 and KEY-WP-0014-T04 stay in wait. Their remaining work is not
ours to do, so what was owed was the request, and it is now delivered: custody
admission for the two approval clients to railiance-platform, the exact human
client id and callback URI to approval-engine, and the OpenBao-token vs
issuer-JWT split plus Qonto rotation execution authority to ops-warden. Each
message quotes the existing non-secret packet or reviewed sequence and states
what is explicitly not being treated as authorization.
No secret was read, no production resource changed, no route retired.
SCOPE.md updated to match.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV8zoCKpA1WRAxsKRYbdH
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1182213@bnt-lap001
Assistant-Session: 966597b9-ae61-46a4-8b9e-1594ab3ec4ad
2026-09-08 10:22:52 +02:00
|
|
|
The 2026-09-05 audit's finding stands as recorded; the replacement outbound
|
|
|
|
|
messages were sent on 2026-09-08 (below).
|
|
|
|
|
|
|
|
|
|
2026-09-08: `0a6c9d88-cf50-45d8-acdc-99a40747683e` -> ops-warden, readable back
|
|
|
|
|
via `GET /messages/?from_agent=key-cape`. It puts both open questions to the
|
|
|
|
|
route and custody owner in one place:
|
|
|
|
|
|
|
|
|
|
1. The `key-cape-oidc-login` proxy yields an OpenBao token and `keycape login`
|
|
|
|
|
yields an issuer JWT — different credential types, different verifiers,
|
|
|
|
|
different enforcement owners, so not interchangeable. Two admissible options
|
|
|
|
|
are offered: keep the proxy and run `keycape login` alongside it for JWT
|
|
|
|
|
consumers, or adapt the route's consumer contract to a JWT and then cut over.
|
|
|
|
|
Option (a) is recommended until every consumer of the route is enumerated.
|
|
|
|
|
2. Qonto rotation for `rapp-qonto-keycape-client`, quoting the five-step reviewed
|
|
|
|
|
sequence from `docs/native-authentication.md` and asking who executes the
|
|
|
|
|
successor generation and CAS update, in which transport, under what authority.
|
|
|
|
|
It records that `warden route`/`warden plan` returned no exact admitted lane
|
|
|
|
|
and that a generic match is not being treated as authorization.
|
|
|
|
|
|
|
|
|
|
The KEY-WP-0009 handoff ops-warden reported missing has also now been delivered
|
|
|
|
|
(`5bc58847-eed5-4164-bb0f-a0d8455e75b8`), closing the KEY-WP-0014-T02 correction.
|
|
|
|
|
|
|
|
|
|
Task remains `wait` — no route was changed and no rotation command ships until
|
|
|
|
|
ops-warden answers (1) and an execution/rollback authority is admitted for (2).
|
Ship the live-registration check both blocked tasks depend on
KEY-WP-0013-T02 and KEY-WP-0014-T04 stay blocked on custody and on ops-warden,
but each contains a KeyCape-owned piece that had been left as prose. T02 requires
proving "live JWKS verification and denied excess scopes without logging values";
T04 step 4 requires verifying a rotated secret, refusing its predecessor and
refusing excess scope. Both were describable and neither was runnable, so the
proof would have been improvised by hand against production at the moment custody
lands -- the worst possible time for it.
keycape verify-client does it in one command. Per registration it checks
discovery origin, the client_credentials exchange and its RS256 signature against
the deployed JWKS, exact sub/tenant/roles/principal_type, that every -deny-scope
is refused, and that the token carries no scope that was not requested. That last
check is a real gap: the caller commands prove every requested scope was granted,
never that nothing extra came back. -previous-secret-env additionally requires
the predecessor to be refused, and treats an unchanged secret as a rotation that
did not happen.
Nothing is written to disk and no value is printed. Failures name the claim, not
the observed value, so running this against production cannot turn a verification
into a disclosure. Every check runs before it reports, so one failure does not
hide the rest.
The exact invocation for each approval client is recorded in the verification
block of the provisioning packet, so custody admission hands back a command
rather than a description.
Tests cover the passing case, an over-broad registration, a live predecessor, an
identical rotation and output non-disclosure; neutering mustFail makes the suite
fail, so the checks have teeth.
Also recorded in KEY-WP-0014: read from ops-warden's catalog rather than waiting
for a reply, key-cape-oidc-login is asked-and-waiting on us since 2026-08-28 and
is a pointer lane with no programmatic consumers, and the rapp-qonto-keycape-client
blocker citing an absent native exchange command went stale when service-token
shipped on 2026-09-05.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV8zoCKpA1WRAxsKRYbdH
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1182213@bnt-lap001
Assistant-Session: 966597b9-ae61-46a4-8b9e-1594ab3ec4ad
2026-09-08 14:30:43 +02:00
|
|
|
|
|
|
|
|
2026-09-08, second pass — read ops-warden's own catalog rather than waiting for a
|
|
|
|
|
reply, and it changes the shape of both questions.
|
|
|
|
|
|
|
|
|
|
`registry/routing/catalog.yaml`, lane `key-cape-oidc-login`: `intended_owner` was
|
|
|
|
|
already corrected to key-cape, and `verified: asked-and-waiting` since
|
|
|
|
|
2026-08-28. **ops-warden is waiting on us, not the other way round.** The lane is
|
|
|
|
|
also `warden_executes: false` with a `wiki_ref` into `CredentialRouting.md` — a
|
|
|
|
|
pointer, per their ADR-0001, not a code path with programmatic consumers. So the
|
|
|
|
|
consumer-contract risk behind question (1) is smaller than assumed: adding
|
|
|
|
|
`keycape login` alongside retires nothing, and the acceptance we owe them is a
|
|
|
|
|
statement of ownership, not a cutover.
|
|
|
|
|
|
|
|
|
|
Lane `rapp-qonto-keycape-client`: `rotation.owner: key-cape`,
|
|
|
|
|
`automatable: true`, and `blocked_on` reads "still no key-cape-native
|
|
|
|
|
exchange/rotation command", `verified: source-read` 2026-08-28. **That blocker is
|
|
|
|
|
stale.** `keycape service-token` (T03) shipped 2026-09-05 and is exactly the
|
|
|
|
|
native `client_secret_basic` exchange they record as absent. It does not clear
|
|
|
|
|
the lane, and should be narrowed rather than closed.
|
|
|
|
|
|
|
|
|
|
Shipped here: `keycape verify-client`, which is rotation step 4 and the denial
|
|
|
|
|
checks step 5 rests on — new exchange verified against deployed JWKS, predecessor
|
|
|
|
|
refused, excess scope refused, no value printed or written. See
|
|
|
|
|
`docs/native-authentication.md`, "Verifying a live registration". The identical
|
|
|
|
|
predecessor case is treated as a failure, because an unchanged secret is a
|
|
|
|
|
rotation that did not happen.
|
|
|
|
|
|
|
|
|
|
Steps 1-3 remain custody's and are deliberately not automated. Task stays `wait`
|
|
|
|
|
on exactly two answers: which option ops-warden takes for the login proxy, and
|
|
|
|
|
who executes the successor generation and CAS update under what authority. No
|
|
|
|
|
route changed.
|
2026-09-08 14:49:01 +02:00
|
|
|
|
|
|
|
|
Both catalog corrections were sent, receipts readable via
|
|
|
|
|
`GET /messages/?from_agent=key-cape`:
|
|
|
|
|
|
|
|
|
|
- `12f1bdfa-b240-414b-aa49-128a4d2acf20` — accepts ownership of lane
|
|
|
|
|
`key-cape-oidc-login`, answering the WARDEN-WP-0033-T04 follow-up they have
|
|
|
|
|
carried as `asked-and-waiting` since 2026-08-28. States the boundary the lane's
|
|
|
|
|
`fetch_command` crosses: key-cape owns browser authentication and the identity
|
|
|
|
|
token; the `netkingdom` auth mount, `role=<domain>` mapping, token store and
|
|
|
|
|
enforcement of the resulting OpenBao token are not ours. Supplies the source
|
|
|
|
|
paths they need to move the lane to `verified: source-read`, and records our
|
|
|
|
|
revised, lower estimate of the consumer risk — a pointer lane under ADR-0001
|
|
|
|
|
retires nothing when `keycape login` runs alongside it — while asking them to
|
|
|
|
|
correct us if the catalog understates its consumers.
|
|
|
|
|
- `08d42f47-8e19-4976-98f5-dd259e7b1225` — reports lane
|
|
|
|
|
`rapp-qonto-keycape-client`'s blocker as stale against its 2026-08-28
|
|
|
|
|
source-read, since `keycape service-token` is the native `client_secret_basic`
|
|
|
|
|
exchange it records as absent and `keycape verify-client` is its rotation step 3
|
|
|
|
|
verbatim. Asks them to **narrow** it to steps 1-2 rather than clear it, with
|
|
|
|
|
proposed replacement text, and notes `rotation.automatable: true` is now
|
|
|
|
|
half-true and should say so precisely rather than be flipped either way.
|
|
|
|
|
|
|
|
|
|
Neither message asks for a route change and neither was one.
|