Request sitting-requester OpenBao custody without allocating a CCR.
Verifier + attended reader on a new informed-decision KV path, not a widening of CCR-2026-0024/0025. Intents still match approval-engine canonical binding. No secret, no apply, no bind. Assistant: grok Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267
This commit is contained in:
parent
c333063185
commit
8c03eb85c0
6 changed files with 123 additions and 3 deletions
|
|
@ -63,6 +63,7 @@ Open in this order. One question each. No approve-all.
|
|||
— `live_accept` must stay `open`.
|
||||
2. Owning requester creates eight `human_control=true` objects, required_count 1,
|
||||
no entries. Carry the native id and `binding.digest`; do not invent a digest.
|
||||
Platform custody (unallocated CCR): `docs/sitting-requester-custody-request.md`.
|
||||
3. `uv run python tools/attach_compact_bindings.py --principal <exact-keycape-sub> --receipt <created.json>`
|
||||
writes `bound/` copies. Unsigned drafts stay unsigned.
|
||||
4. Flex Auth admits a **new** package pinning those eight `memo:` ids to the
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
**Copied to:** `approval-engine` (`docs/keycape-service-registrations.md` —
|
||||
“no requester identity has been settled for `approval:create`”)
|
||||
**Status:** requested 2026-09-14. **Not registered. Not in OpenBao. No secret
|
||||
is in this repository.**
|
||||
is in this repository.** Custody request (no CCR id):
|
||||
`docs/sitting-requester-custody-request.md`.
|
||||
|
||||
This is the missing presenter for compact Decision Memo sittings whose
|
||||
protected side effect is a **work-record update** (`INFD-WP-0002-T04`), not a
|
||||
|
|
|
|||
39
docs/sitting-requester-custody-request.md
Normal file
39
docs/sitting-requester-custody-request.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Sitting requester custody — requested, not allocated
|
||||
|
||||
**Workplan:** `INFD-WP-0002-T03`
|
||||
**Owner:** `railiance-platform` (OpenBao KV + ESO + attended reader)
|
||||
**Peer:** `key-cape` (client row; not yet registered)
|
||||
**Status:** requested 2026-09-14. **No CCR id is allocated here. No secret
|
||||
is in this repository. Do not apply from this file.**
|
||||
|
||||
Same split as `CCR-2026-0024` / `CCR-2026-0025` for
|
||||
`secrets-engine-requester`: one KeyCape **verifier** path (ESO) and one
|
||||
**attended operator reader**. Do not widen those CCRs or that KV path.
|
||||
|
||||
## What to allocate
|
||||
|
||||
Platform assigns the next CCR pair. Suggested shape, names only:
|
||||
|
||||
| Piece | Suggested value |
|
||||
| --- | --- |
|
||||
| KV path | `platform/workloads/informed-decision/sitting-requester` |
|
||||
| Field | `CLIENT_SECRET` only |
|
||||
| Verifier policy | read that path; Kubernetes auth for `external-secrets` in `external-secrets` |
|
||||
| Reader policy | read that path; OIDC attended operator; sibling paths and parent listing denied |
|
||||
| ESO / env | `KEYCAPE_INFORMED_DECISION_SITTING_REQUESTER_CLIENT_SECRET` (already the `secretRef` name in the KeyCape request) |
|
||||
| Workload | `informed-decision` |
|
||||
| Tenant | `platform` / `tenant:platform` |
|
||||
|
||||
Do not put `approval:approve` or `approval:consume` material on this path.
|
||||
The human PKCE client stays public and secretless.
|
||||
|
||||
## Activation conditions (when platform and key-cape accept)
|
||||
|
||||
1. KeyCape owns `informed-decision-sitting-requester` (`applied: false` today).
|
||||
2. Attended authority writes CAS=0 custody to the new path only.
|
||||
3. Exact policy/auth readback; sibling `secrets-engine/approval-requester` denied.
|
||||
4. Excess scopes (`approval:approve`, `approval:consume`, `approval:read`) refused at token exchange.
|
||||
5. Wrong secret refused. No human entry synthesized. No POST of sitting intents until that proof exists.
|
||||
|
||||
Registration contract: `docs/keycape-sitting-requester-registration.md`.
|
||||
Create intents (not posted): `docs/batches/2026-09-14/approval-create-intents.json`.
|
||||
51
docs/sitting-requester-custody-request.yaml
Normal file
51
docs/sitting-requester-custody-request.yaml
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Request only. railiance-platform allocates the CCR id.
|
||||
# status is requested — not applied, not approved, no secret values.
|
||||
id: unallocated
|
||||
kind: credential-change-request
|
||||
schema_version: 1
|
||||
request_type: workload-kv-read
|
||||
title: Informed Decision sitting-requester KeyCape client secret (verifier + attended reader)
|
||||
status: requested
|
||||
created: "2026-09-14"
|
||||
updated: "2026-09-14"
|
||||
origin: INFD-WP-0002-T03
|
||||
origin_ref: informed-decision/docs/keycape-sitting-requester-registration.md
|
||||
requester:
|
||||
agent: grok
|
||||
reason: >-
|
||||
Compact sitting needs a create-only presenter whose binding.actor is
|
||||
informed-decision. Do not widen CCR-2026-0024/0025 or secrets-engine-requester.
|
||||
review:
|
||||
required: true
|
||||
required_approvers:
|
||||
- platform-operator
|
||||
- key-cape-owner
|
||||
target:
|
||||
domain: infotech
|
||||
tenant: platform
|
||||
workload: informed-decision
|
||||
environment: production
|
||||
purpose: create-only sitting requester; work-record decisions, not PEP consume
|
||||
openbao:
|
||||
mount: platform
|
||||
kv_path: platform/workloads/informed-decision/sitting-requester
|
||||
fields:
|
||||
- CLIENT_SECRET
|
||||
delivery:
|
||||
surface: external-secrets
|
||||
env_name: KEYCAPE_INFORMED_DECISION_SITTING_REQUESTER_CLIENT_SECRET
|
||||
risk:
|
||||
classification: high
|
||||
notes:
|
||||
- Scope must remain approval:create only.
|
||||
- Human disposition uses informed-decision-approver (public PKCE).
|
||||
- infd-20260914-c01 may stay on secrets-engine-requester if consume is in-scope.
|
||||
verification:
|
||||
negative:
|
||||
- approval:approve and approval:consume refused at token exchange
|
||||
- sibling secrets-engine/approval-requester denied
|
||||
- parent listing denied
|
||||
activation_conditions:
|
||||
- KeyCape row exists
|
||||
- attended CAS=0 write to this path only
|
||||
- no sitting POST until exchange proof exists
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from informed_decision.records import memo_from
|
||||
|
|
@ -45,3 +46,26 @@ def test_create_intents_cover_the_sitting_and_are_not_posted():
|
|||
memo = memo_from(json.loads((batch_root / batch / f"{row['memo_id']}.memo.json").read_text()))
|
||||
assert binding["target"]["id"] == memo.binding.target.id
|
||||
assert memo.question.startswith(binding["purpose"][:20]) or binding["purpose"] in memo.question or memo.question.rstrip("?") in binding["purpose"]
|
||||
|
||||
|
||||
def test_create_intents_match_approval_engine_canonical_binding():
|
||||
engine = Path("/home/worsch/approval-engine")
|
||||
sys.path.insert(0, str(engine))
|
||||
from approval_engine.binding import BINDING_FIELDS, binding_digest, canonical_binding
|
||||
|
||||
for row in INTENTS["intents"]:
|
||||
canon = canonical_binding(row["binding"])
|
||||
assert tuple(canon) == BINDING_FIELDS
|
||||
digest = binding_digest(canon)
|
||||
assert digest.startswith("sha256:") and len(digest) == 71
|
||||
|
||||
|
||||
def test_custody_request_is_unallocated_and_does_not_widen_t03_path():
|
||||
text = (ROOT / "docs" / "sitting-requester-custody-request.yaml").read_text()
|
||||
assert "status: requested" in text
|
||||
assert "id: unallocated" in text
|
||||
assert "kv_path: platform/workloads/informed-decision/sitting-requester" in text
|
||||
assert "kv_path: platform/workloads/secrets-engine/approval-requester" not in text
|
||||
md = (ROOT / "docs" / "sitting-requester-custody-request.md").read_text()
|
||||
assert "Do not widen" in md
|
||||
assert "No secret" in md
|
||||
|
|
|
|||
|
|
@ -150,8 +150,12 @@ create-only confidential client (`informed-decision-sitting-requester`,
|
|||
`sub=informed-decision`, scope `approval:create` only, no approve/consume,
|
||||
no redirect). Intents for the eight bindings are in
|
||||
`docs/batches/2026-09-14/approval-create-intents.json` (`posted: false`;
|
||||
`c01` create-client undecided). No secret, no POST, no bind. Task stays
|
||||
`wait`.
|
||||
`c01` create-client undecided). No secret, no POST, no bind.
|
||||
|
||||
2026-09-14 23:00 UTC — **custody requested from railiance-platform, no CCR
|
||||
id allocated.** `docs/sitting-requester-custody-request.md` asks for a new
|
||||
KV path `platform/workloads/informed-decision/sitting-requester` (verifier +
|
||||
attended reader), not a widening of CCR-2026-0024/0025. Task stays `wait`.
|
||||
|
||||
## Feed outcomes back to State Hub without hub-authoring
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue