diff --git a/docs/approval-engine-provisioning-request.yaml b/docs/approval-engine-provisioning-request.yaml index 64e1e4c..0875120 100644 --- a/docs/approval-engine-provisioning-request.yaml +++ b/docs/approval-engine-provisioning-request.yaml @@ -85,6 +85,30 @@ verification: - Preserve existing registrations and signing key; record versions and image digest. - Human consume denial is approval-engine's to verify at its resource; KeyCape proves only that the human client is never issued a consume grant. +# Asked by railiance-platform 2026-09-09 (CCR-2026-0020 has no named presenting +# actor in any owner source, and they declined to guess one). This is KeyCape's +# view as the issuer of the identity, not a decision: who may hold the +# credential is approval-engine's call and the doctrine question is +# gate-house's. +presenting_actor_note: + client_id: approval-engine-operator + observation: | + The registration as issued carries both approval:create and approval:approve, + so a single presenter can create an entry and then approve it. That is a + separation-of-duties property of the credential holder, not a defect in the + token -- KeyCape issues exactly the grants approval-engine requested, and + splitting them would be a change to that request rather than to issuance. + options_keycape_can_support: + - Two registrations with disjoint grants, one creating and one approving, if + approval-engine wants the split enforced at issuance. KeyCape can do this + today; it needs approval-engine to say so, since it changes their contract. + - Keep one registration and constrain the holder by custody instead, which is + where it sits now. + keycape_does_not_decide: | + Who presents this credential, and whether self-approval is acceptable for the + lifecycle operator, are not KeyCape's to settle. Recorded here so the question + is answered from the registration rather than reconstructed from it. + blockers: - Admit exact custody paths, field delivery, consumer identities and lifecycle authority. - Resolve attended first-provision authority through the custody owner. diff --git a/docs/operations.md b/docs/operations.md index f889513..c2aaf82 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -139,8 +139,11 @@ grant is not `client_credentials`; those fields were silently ignored there, so registration could look effective and do nothing. This is a **startup** error: a stray field in the deployed config stops the process from booting rather than degrading. The live `sso/keycape-config` was checked on 2026-09-09 and none of -its three browser clients carries either field, so it passes as deployed — but -re-check if that config changed since. `tenant` is deliberately not rejected; +its three browser clients carries either field, so it passes as deployed. The +custody owner confirmed independently that the config was last written during the +2026-09-09 activation (resource version 58747126) and has not been edited since, +so the inspected state is the state that will boot — and that they will re-check +the browser clients if anything writes that Secret before the window. `tenant` is deliberately not rejected; see below. **2. A conflicting tenant binding refuses issuance (`329e48f`, KEY-WP-0013-T05).** diff --git a/workplans/KEY-WP-0013-approval-engine-resource-audience.md b/workplans/KEY-WP-0013-approval-engine-resource-audience.md index e93c2bc..8bc39b3 100644 --- a/workplans/KEY-WP-0013-approval-engine-resource-audience.md +++ b/workplans/KEY-WP-0013-approval-engine-resource-audience.md @@ -280,6 +280,37 @@ anyone. Predecessor rejection is implemented and unit-tested in `keycape verify-client`; it has not been run against a real rotation, which is KEY-WP-0014-T04's territory and still has no admitted execution authority. +**Independently confirmed by the custody owner, 2026-09-09** (railiance-platform +`ae6ff4bc`, `570e6746`). They reached the same reading from their own side and +add one datum this record did not carry: `human_client_consume_denied: true` for +both clients, alongside the signature, exact-claim, lifetime, excess-scope and +wrong-secret results. They confirm the verifier ran twice — once during +activation and again after rollout — at deployment generation 38, single ready +replica, signing key unchanged, no credential values emitted, and state that T02 +can be closed against that receipt rather than against a run KeyCape cannot make. + +They also correct one thing in our framing, and they are right: the packet says +*client-side retrieval* is unadmitted, which remains true, but the attended +operator path is not a client-side read and never required one. The two are +distinct and this task had been treating them as the same constraint. + +**Do not cite this receipt as rotation evidence.** Both owners now state the same +two gaps independently: `real_predecessor_rotation_tested: false` and +`observed_wall_clock_expiry: false`. Neither is a T02 acceptance criterion, and +neither is closed by anything recorded here — see KEY-WP-0014-T04. + +**Client-side retrieval is prepared but still unadmitted.** CCR-2026-0019 +(secrets-engine reader) and CCR-2026-0020 (approval-engine-operator reader) are +`in_flight` under RPF-WP-0035-T06. 0020 has no named presenting actor in any +owner source, and railiance-platform left it undetermined rather than guessing — +correctly. KeyCape's view, asked for as the issuer of the identity and recorded +in `docs/approval-engine-provisioning-request.yaml`, is that the registration as +issued carries both `approval:create` and `approval:approve`, so a single +presenter can create and then approve the same entry. That is a +separation-of-duties question about who may hold the credential, not a defect in +the token: KeyCape issues the grants approval-engine requested. The decision is +approval-engine's and the doctrine question is gate-house's. + ## Assign and register the human approver browser client ```task diff --git a/workplans/KEY-WP-0014-native-credential-lane-handoff.md b/workplans/KEY-WP-0014-native-credential-lane-handoff.md index eaf1f2c..53689a2 100644 --- a/workplans/KEY-WP-0014-native-credential-lane-handoff.md +++ b/workplans/KEY-WP-0014-native-credential-lane-handoff.md @@ -212,3 +212,18 @@ be worse than the imprecision. No reply needed on that point. T04 stays `wait`: the rotation authority now has a named owner (railiance-platform, transport `secrets-engine exec`) but does not yet exist, and nothing here changed a route. + +2026-09-09, guarding against a misreading that is now easy to make. The approval +clients went live and `docs/evidence/2026-09-09-keycape-verifier-admission.json` +records a passing verifier run, so there is now a committed receipt in this repo +that looks like rotation evidence and is not. It records +`real_predecessor_rotation_tested: false` and `observed_wall_clock_expiry: false`, +and under `limits`, `actual_predecessor_rotation_observed: false` and +`wall_clock_jwt_expiry_observed: false`. railiance-platform stated the same two +gaps unprompted from their side (`ae6ff4bc`): "do not cite this receipt as +rotation evidence." + +So `keycape verify-client`'s predecessor rejection has been exercised only +against unit tests and a first provisioning where predecessor and successor were +never distinct. Rotation step 4 is implemented and unproven, which is a different +state from either "missing" or "done", and T04 is where that distinction lives.