Name the execute-time digest target; record the tenant collision

flex-auth published binding.approval_binding_digest (FLEX-DEC-2026-007) after
secrets-engine found that a claim-bearing request's request_digest covers the
carried claim, so it can never equal a pdp_digest recorded before that claim
existed. A consumer obeying GH-DEC-2026-008 against request_digest would have
failed closed permanently on every claim rather than on a bad one.

The value recorded at issue was already correct, so no code changes. What was
wrong was this repo's description of the comparison target: a reader would
reach for request_digest and fail closed forever. The schema and
docs/approval-claim.md now name approval_binding_digest as the execute-time
target and state that request_digest is never it, while leaving the issue-time
description as it stood.

Separately, docs/keycape-service-registrations.md now records a live collision
in the deployment inputs: the manifest serves --tenant platform while the
requested registrations issue tenant:coulomb, and ApiApplication.identity
compares them with exact string equality before any object lookup, so those
tokens would be denied 403 on every non-health route. flex-auth's
tenant:platform is a PDP subject this engine never reads and cannot bridge the
two. The values are left as-is on purpose — resolving it needs an owner
statement on whether the two name the same layer, and guessing grants
cross-tenant access to the approval store. The doc's stale issuer is corrected
to the live https://kc.coulomb.social from 06544b0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PM5HnEAhokxdfcPqBNpT7D

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 715850@bnt-lap001
Assistant-Session: eb557e93-7cb1-45d0-9e57-7d15b3edc60e
This commit is contained in:
tegwick 2026-09-06 20:35:59 +02:00
parent 06544b0fb4
commit 5c87ba8610
4 changed files with 115 additions and 12 deletions

View file

@ -17,10 +17,49 @@ Required claims remain those in `docs/caller-authentication.md`: `iss`, `sub`,
| Field | Value |
| --- | --- |
| Audience | `approval-engine` |
| Issuer | the deployed KeyCape issuer (manifest uses `https://auth.netkingdom.local`) |
| Issuer | the deployed KeyCape issuer (manifest uses `https://kc.coulomb.social`) |
| JWKS | `GET /jwks` on the KeyCape service |
| Scopes | `approval:create`, `approval:read`, `approval:approve`, `approval:revoke`, `approval:supersede`, `approval:consume`, `approval:observe`, `approval:emit` |
## Tenant reconciliation — unresolved, blocks token issuance
**This is a live collision, not a naming preference.** `ApiApplication.identity`
compares the verified JWT `tenant` claim to the engine's configured store tenant
with exact string equality and raises `Forbidden` before any object lookup
(`approval_engine/api.py:66`). There is no mapping table, no normalisation, and
no prefix handling anywhere in this engine.
The three values currently in play:
| Value | Where it is set | Current content |
| --- | --- | --- |
| Store tenant | `deploy/approval-engine.yaml` `--tenant` (CLI default `platform`) | `platform` |
| JWT `tenant` claim | the client registrations below | `tenant:coulomb` |
| CheckRequest tenant | flex-auth policy subject | `tenant:platform`**never read by this engine** |
`platform` != `tenant:coulomb`, so tokens issued under the registrations below
would be denied `403` on every non-health route. Spelling similarity between
`platform` and `tenant:platform` is not a mapping either; the flex-auth policy
subject is a PDP input this engine never inspects, so it cannot participate in
the comparison at all.
Denial evidence: `tests/test_auth.py::test_wrong_tenant_is_forbidden` — a
signature-valid token whose tenant differs from the store tenant is refused
without mutation.
**Resolution is an owner decision and is deliberately not taken here.** Either
KeyCape issues `tenant: platform` to match the store, or this repo's manifest
sets `--tenant tenant:coulomb` to match the registration. Which is correct
depends on whether `platform` and `tenant:coulomb` name the same layer — a
question this engine cannot answer, and answering it wrongly grants a token
cross-tenant access to the approval store. The values below are left as
requested until that mapping is stated by an owner, so the mismatch stays
visible rather than being silently resolved by whichever document was edited
last.
Tracked against `APPROVAL-WP-0002-T01`; related `KEY-WP-0013-T02`,
`SECRETS-WP-0009-T03`.
## Clients
Confidential client secrets stay in OpenBao/operator custody. `secretRef`