Enforce declared human controls at approval binding
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
a3c94fb241
commit
be1a388a84
17 changed files with 441 additions and 40 deletions
|
|
@ -47,15 +47,37 @@ Create additionally requires `binding.actor == sub`. Approval-entry subject,
|
|||
assurance, evidence reference, and **principal type** are derived from the
|
||||
verified JWT, never the request body.
|
||||
|
||||
`principal_type` is recorded on the entry (schema v4) because `subject_id`
|
||||
alone cannot answer what kind of principal bound the approval — `user:alice` is
|
||||
a naming convention, not a verified claim. This engine does not restrict
|
||||
`/entries` to human principals: whether a service or agent may supply approver
|
||||
evidence is approval doctrine and belongs to `gate-house`, and the
|
||||
`approval-engine-operator` registration holds `approval:approve` today. What
|
||||
this engine owes is that the evidence chain says which it was. Entries written
|
||||
before v4 stay `null` rather than being back-filled into a claim nobody made. KeyCape owns client registration and scope grants; approval-engine
|
||||
only verifies and enforces them. Requested registrations are:
|
||||
`principal_type` is recorded from verified identity (since schema v4). Schema v5
|
||||
implements GH-DEC-2026-016: when an approval declares `human_control: true`,
|
||||
`/entries` refuses a service, agent or unknown principal with 403 before inserting
|
||||
an entry or emitting issuance. The request body cannot supply the approver type
|
||||
or downgrade the declaration. Undeclared approvals retain service-to-service use;
|
||||
a human entry does not retroactively declare a human control.
|
||||
|
||||
**Requesting and binding are separate operations.** `POST /v1/approvals` creates
|
||||
an unapproved request and records the strict boolean declaration. A service or
|
||||
agent with `approval:create` may draft that request. The principal contributing
|
||||
judgment is known only at `POST /entries`; this is the bind/issue boundary where
|
||||
GH-DEC-2026-016's non-human refusal applies. A draft is never a valid approval.
|
||||
No statement about the approver is inferred from `binding.principal` or the
|
||||
requesting actor's type. Dual control also needs its declared `required_count`;
|
||||
human control alone does not imply two approvers or decide which acts need it.
|
||||
|
||||
**Identity provenance:** reviewed KeyCape source
|
||||
`f9812ab3b2bfe8f0817185f44071e612264ec3ee:src/internal/server/oidc/token.go`
|
||||
sets `principal_type=human` only after consuming a client/redirect-bound PKCE
|
||||
session and looking up the current user. Its separate client-credentials path
|
||||
sets `service`; no registration field supplies a human principal type. This is
|
||||
different from registration-supplied tenant routing. Production acceptance must
|
||||
pin and prove that issuer behavior with a real human flow; signed fixtures here
|
||||
prove engine enforcement, not native identity admission. If an issuer introduces
|
||||
a registration-supplied route to `human`, GH-DEC-2026-016 §5 requires independent
|
||||
provenance and refusal of that route before admitting it. A consumer must not
|
||||
relax the identity contract simply because the JWT verifies.
|
||||
|
||||
Entries written before v4 stay null; pre-v5 objects have `human_control: false`.
|
||||
KeyCape owns client registration and scope grants; approval-engine verifies and
|
||||
enforces them. Requested registrations are:
|
||||
|
||||
- audience/resource server `approval-engine` with the scopes above;
|
||||
- the secrets-engine PEP service client with `approval:read` and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue