2026-09-09 14:42:26 +02:00
|
|
|
---
|
|
|
|
|
id: KEY-WP-0028
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "Reject service-identity fields that a browser client silently ignores"
|
|
|
|
|
domain: infotech
|
|
|
|
|
repo: key-cape
|
|
|
|
|
status: finished
|
|
|
|
|
owner: claude
|
|
|
|
|
topic_slug: browser-client-field-validation
|
|
|
|
|
created: "2026-09-09"
|
|
|
|
|
updated: "2026-09-09"
|
Record live custody admission and re-verify the new rule against it
Read-only inspection shows KEY-WP-0013-T02's custody gate has moved since
yesterday: both approval clients are registered in sso/keycape-config, both
secrets exist in the namespace and are wired into the pod, and the image is
pinned to the digest T06 published. The live issuer passes every conformance
check that needs no credential.
That does not establish the claim contract. Subject, tenant, roles, scopes,
lifetime and excess-scope denial are what keycape verify-client proves, and it
needs the client secret in the environment. Reading either secret is client-side
retrieval, which the provisioning packet records as not admitted, so that run is
an attended operator action. T02 now waits on the run, not on custody.
Also re-verified the KEY-WP-0028 rule against the deployed config, after a peer
noted it fails closed at startup with a rollout imminent. The three browser
clients there carry neither serviceSubject nor roles; the three service clients
carry both legitimately. Kept as errors rather than warnings on that evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-09 14:44:38 +02:00
|
|
|
state_hub_workstream_id: "6d0cb4fd-17da-5466-8011-5ade1ac46171"
|
2026-09-09 14:42:26 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
`serviceSubject` and `roles` are read only on the `client_credentials` path. On a
|
|
|
|
|
browser client they are accepted at startup and then ignored: the subject and
|
|
|
|
|
roles come from the directory user. A registration that looks effective and is
|
|
|
|
|
not fails later, somewhere else, as a downstream rejection rather than as a
|
|
|
|
|
registration defect.
|
|
|
|
|
|
|
|
|
|
`tokenLifetime` was already rejected this way for non-service clients, so the
|
|
|
|
|
rule exists — it was just incomplete.
|
|
|
|
|
|
|
|
|
|
## Reject the ignored fields
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0028-T01
|
|
|
|
|
status: done
|
|
|
|
|
priority: medium
|
Record live custody admission and re-verify the new rule against it
Read-only inspection shows KEY-WP-0013-T02's custody gate has moved since
yesterday: both approval clients are registered in sso/keycape-config, both
secrets exist in the namespace and are wired into the pod, and the image is
pinned to the digest T06 published. The live issuer passes every conformance
check that needs no credential.
That does not establish the claim contract. Subject, tenant, roles, scopes,
lifetime and excess-scope denial are what keycape verify-client proves, and it
needs the client secret in the environment. Reading either secret is client-side
retrieval, which the provisioning packet records as not admitted, so that run is
an attended operator action. T02 now waits on the run, not on custody.
Also re-verified the KEY-WP-0028 rule against the deployed config, after a peer
noted it fails closed at startup with a rollout imminent. The three browser
clients there carry neither serviceSubject nor roles; the three service clients
carry both legitimately. Kept as errors rather than warnings on that evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-09 14:44:38 +02:00
|
|
|
state_hub_task_id: "e4bce8c7-0e60-55e8-ad32-a3a0c4e46044"
|
2026-09-09 14:42:26 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Config validation now rejects `serviceSubject` and `roles` on any client that
|
|
|
|
|
does not use `client_credentials`, naming where the value actually comes from.
|
|
|
|
|
Nothing in `config/dev-config.yaml`, the example fixture or the live deployment
|
|
|
|
|
sets either field on a browser client, so this breaks no existing configuration —
|
|
|
|
|
checked against all three rather than assumed.
|
|
|
|
|
|
Record live custody admission and re-verify the new rule against it
Read-only inspection shows KEY-WP-0013-T02's custody gate has moved since
yesterday: both approval clients are registered in sso/keycape-config, both
secrets exist in the namespace and are wired into the pod, and the image is
pinned to the digest T06 published. The live issuer passes every conformance
check that needs no credential.
That does not establish the claim contract. Subject, tenant, roles, scopes,
lifetime and excess-scope denial are what keycape verify-client proves, and it
needs the client secret in the environment. Reading either secret is client-side
retrieval, which the provisioning packet records as not admitted, so that run is
an attended operator action. T02 now waits on the run, not on custody.
Also re-verified the KEY-WP-0028 rule against the deployed config, after a peer
noted it fails closed at startup with a rollout imminent. The three browser
clients there carry neither serviceSubject nor roles; the three service clients
carry both legitimately. Kept as errors rather than warnings on that evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-09 14:44:38 +02:00
|
|
|
Re-verified against `sso/keycape-config` on 2026-09-09, after a peer raised that
|
|
|
|
|
this validation fails closed at startup and a rollout is imminent, so a stray
|
|
|
|
|
field would surface as KeyCape failing to boot. The deployed config now holds six
|
|
|
|
|
clients: `demo-app`, `netkingdom-bootstrap-console` and `openbao-admin` are
|
|
|
|
|
browser clients carrying neither field, while `rapp-qonto-client`,
|
|
|
|
|
`secrets-engine-approval` and `approval-engine-operator` carry both legitimately
|
|
|
|
|
on the `client_credentials` path. The rule rejects none of them. Kept as errors
|
|
|
|
|
rather than downgraded to warnings on that evidence: a warning for a field that
|
|
|
|
|
does nothing is the state this change exists to end.
|
|
|
|
|
|
2026-09-09 14:42:26 +02:00
|
|
|
**`tenant` is deliberately excluded from the rule**, and a test pins that. A
|
|
|
|
|
browser client may declare a tenant; `humanTenant` resolves it against the
|
|
|
|
|
directory and refuses issuance when the two disagree (KEY-WP-0013-T05). An
|
|
|
|
|
earlier version of this change rejected `tenant` too, which would have made that
|
|
|
|
|
feature unusable.
|
|
|
|
|
|
|
|
|
|
## Correction
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: KEY-WP-0028-T02
|
|
|
|
|
status: done
|
|
|
|
|
priority: medium
|
Record live custody admission and re-verify the new rule against it
Read-only inspection shows KEY-WP-0013-T02's custody gate has moved since
yesterday: both approval clients are registered in sso/keycape-config, both
secrets exist in the namespace and are wired into the pod, and the image is
pinned to the digest T06 published. The live issuer passes every conformance
check that needs no credential.
That does not establish the claim contract. Subject, tenant, roles, scopes,
lifetime and excess-scope denial are what keycape verify-client proves, and it
needs the client secret in the environment. Reading either secret is client-side
retrieval, which the provisioning packet records as not admitted, so that run is
an attended operator action. T02 now waits on the run, not on custody.
Also re-verified the KEY-WP-0028 rule against the deployed config, after a peer
noted it fails closed at startup with a rollout imminent. The three browser
clients there carry neither serviceSubject nor roles; the three service clients
carry both legitimately. Kept as errors rather than warnings on that evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NV9oijZukGyGbRQGGKnK4P
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713576@bnt-lap001
Assistant-Session: 384c511d-9bce-4cb8-a676-2aef6c0c8df6
2026-09-09 14:44:38 +02:00
|
|
|
state_hub_task_id: "5ab951f8-2f9c-522c-b6ea-7f6d572cd618"
|
2026-09-09 14:42:26 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This work started from KEY-WP-0013-T05's blocker paragraph, which described a
|
|
|
|
|
human token as unable to carry `tenant:platform`. That was true when written and
|
|
|
|
|
had already been fixed in a concurrent session by the time this task began; the
|
|
|
|
|
paragraph was read as current state rather than as a dated record.
|
|
|
|
|
|
|
|
|
|
Two consequences, both corrected within the session:
|
|
|
|
|
|
|
|
|
|
- the `tenant` rejection was removed before it was committed, and a test now
|
|
|
|
|
asserts a browser client carrying `tenant: tenant:platform` validates cleanly;
|
|
|
|
|
- a hub decision (`0145ab57`) recording the tenant question as open and
|
|
|
|
|
unimplemented was withdrawn with a rationale pointing at the implementation.
|
|
|
|
|
Nothing was built on it.
|
|
|
|
|
|
2026-09-09 16:41:10 +02:00
|
|
|
A third instance followed the same day, outside this task: a message to
|
|
|
|
|
railiance-platform (d361bf28) listed the upstream issuer pin as outstanding when
|
|
|
|
|
`docs/evidence/2026-09-09-upstream-issuer-pin.json` showed it done ten hours
|
|
|
|
|
earlier — `check_before.issuer_matches: false`, then pinned to
|
|
|
|
|
`https://auth.coulomb.social`. Corrected in dd827b9f. The concern itself was
|
|
|
|
|
sound; only the claim that it was still owed was wrong, and the two are worth
|
|
|
|
|
separating rather than letting the correct half excuse the other.
|
|
|
|
|
|
2026-09-09 14:42:26 +02:00
|
|
|
The lesson worth keeping: in a repository where several sessions work at once,
|
2026-09-09 16:41:10 +02:00
|
|
|
prose ages faster than the code and the receipts it describes. `docs/evidence/`
|
|
|
|
|
is the authoritative artifact for anything claiming a live proof here. Read it
|
|
|
|
|
before writing "outstanding", "unproven" or "not done" — that check is cheaper
|
|
|
|
|
than any of the corrections it would have prevented.
|