NK-WP-0048-T05: build revised memo r2 after ops-mason's review
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s

The first memo described the type before the materialization review. r2 uses a
new memo id (a delivered idempotency key refuses new content) and says it
supersedes the first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 330051@bnt-lap001
Assistant-Session: b98d4912-95a3-4619-b7fb-57aa1db7407b
This commit is contained in:
tegwick 2026-10-08 23:41:32 +02:00
parent ad71665bd5
commit 00bcb17479
4 changed files with 60 additions and 29 deletions

View file

@ -13,7 +13,9 @@ from pathlib import Path
HERE = Path(__file__).resolve().parent
HUB_DECISION = "e418263e-a71f-4f01-a970-c87c9e187c09"
MEMO_ID = "nk-wp-0048-t05-oidc-browser-relying-party"
# r2 supersedes the first memo (delivered before ops-mason's review). A new id is
# needed: the dispatcher refuses new content under a delivered idempotency key.
MEMO_ID = "nk-wp-0048-t05-oidc-browser-relying-party-r2"
ITEM = f"{MEMO_ID}-packet"
packet = (HERE / "packet.md").read_text()
@ -45,7 +47,8 @@ envelope = {
"NK-WP-0048-T05. Acknowledging admits the shape of browser OIDC clients for internal "
"services, so that each later client is a light SecurityCase: accepted, materialized by "
"ops-mason, followed through by ops-warden. It registers nothing and accepts no case; the "
"Forgejo case keeps its own acceptance. One attended operator session remains per case, "
"Forgejo case keeps its own acceptance. Supersedes memo "
"nk-wp-0048-t05-oidc-browser-relying-party; answer this one. One attended operator session remains per case, "
"because KeyCape's live client registry is a Kubernetes Secret."
),
"binding": {

File diff suppressed because one or more lines are too long

View file

@ -4,6 +4,10 @@ Workplan: NK-WP-0048 (net-kingdom), task NK-WP-0048-T05
Hub decision: e418263e-a71f-4f01-a970-c87c9e187c09
Canon: canon/standards/security-case-types_v0.1.md (accepted 2026-10-08), section 5
Type: security-case-types/oidc-browser-relying-party/ (type.yaml, README.md, tests)
Memo: nk-wp-0048-t05-oidc-browser-relying-party-r2. It supersedes memo
nk-wp-0048-t05-oidc-browser-relying-party, delivered earlier on 2026-10-08,
which described the type before ops-mason's review. Please answer this one;
both serve the same hub decision, and the first answer resolves it.
## Question
@ -23,7 +27,9 @@ ops-mason materializes it and ops-warden follows through. The type becomes
- It registers no client, creates no group, mints no secret and changes nothing
live.
- It does not accept any case. The Forgejo case needs its own acceptance; its
parameters were accepted in KEY-WP-0038-T01 and carry over.
parameters were accepted in KEY-WP-0038-T01 and carry over, except custody:
the type puts Forgejo's secret at `platform/workloads/keycape/forgejo`, not
the request's proposed `platform/workloads/forgejo/netkingdom-oidc-client`.
- It does not adopt the existing hand-built clients. Adoption, when it happens,
does not change their live registrations.
@ -31,9 +37,10 @@ ops-mason materializes it and ops-warden follows through. The type becomes
Parameters: client id, display name, exact https redirect URIs (no wildcards),
scopes from a closed list, client type (confidential or public), MFA pin, the
LLDAP groups that gate sign-in and their initial members, the custody reference
for a confidential client's secret, the consuming service and its owner.
Secrets never appear in a case, only `bao:` custody references.
LLDAP groups that gate sign-in and their initial members, the consuming service
and its owner. A case cannot choose where a confidential client's secret lives:
the type derives `platform/workloads/keycape/<client_id>`, as the live
secrets-engine-openbao client already uses. Secrets never appear in a case.
Steps, in order, each on its owner's entry point:
@ -46,9 +53,14 @@ Steps, in order, each on its owner's entry point:
| register-client | net-kingdom (keycape-client.py) | attended operator | no |
| hand-over | the consuming service's owner | owner | no |
ops-mason builds, for confidential clients, the custody path and two narrow read
policies (KeyCape and the consuming service). For every case it adds a catalog
entry.
ops-mason builds, for confidential clients, the custody path; two read
policies in the existing family, `workload-kv-read-keycape-<client>-eso` and
`workload-kv-read-keycape-<client>-<consuming service>`, each granting `read`
on that one data path and nothing else; and the Kubernetes-auth role
`external-secrets-keycape-<client>` that ESO uses to deliver the secret (its
service account only, 15m, no default policy). For every case it adds the
catalog entry `<consuming service>-keycape-client`. A case adds no new path
layout or policy family.
Verification never reads a value. The authorization endpoint accepts each
registered redirect and refuses another; the groups exist; for confidential
@ -62,7 +74,9 @@ is allowed it. Rollback is the exact inverse, in reverse order.
- Wildcard or prefix redirect URIs: the classic open-redirect weakness.
- Automatic accounts for every NetKingdom user: sign-in is gated by explicit
groups; the consumer decides account creation.
- Secrets in case files for convenience: cases carry custody references only.
- Secrets in case files for convenience: cases carry no secrets.
- A custody path chosen per case: every case would add its own layout and
policy family to review (rejected in ops-mason's review).
## Attended steps
@ -82,18 +96,22 @@ user-engine portal and vergabe fit 1.0 exactly.
## Evidence
- Validator and template: tools/security-case-types/, 32 tests
- This type: 11 tests, including the Forgejo case checked field by field against
- Validator: tools/security-case-types/, 19 tests (a policy or role must
template its rules, not only its name)
- This type: 12 tests, including the rendered Forgejo materialization (path,
both policy bodies, ESO role, catalog entry), the Forgejo case checked field by field against
the accepted request, and a regression showing that the vergabe case reproduces
its hand-built registration exactly
- Entry points: identity-provisioner groups ensure/revoke (39 tests),
keycape-client.py (15 tests; all 71 KeyCape helper tests pass)
keycape-client.py (15 tests; it refuses a case-set custody path)
- Declaration net-kingdom.keycape-client-registration passes the Playbook
Capability Contract validator
## Reviews before this decision
ops-mason (MASON-WP-0010-T01) and ops-warden (WARDEN-WP-0044-T01) review their
sections of the type. Answering before their reviews are in is possible, but
then the type's acknowledgment covers sections its executors have not yet
confirmed.
ops-mason reviewed the materialization section (MASON-WP-0010-T01) and asked
for a derived custody path, reuse of the existing policy family, templated
policy rules and the ESO role; all are in this version, and ops-mason finds the
section acceptable. ops-warden's review of the follow-through section
(WARDEN-WP-0044-T01) is still in progress. Answering now acknowledges a
follow-through its executor has not yet confirmed.

View file

@ -227,6 +227,16 @@ re-sent; and Forgejo's custody path moves from the accepted request's proposed
railiance-apps (RAPPS-WP-0016-T02) need to adopt in T06. ops-warden's review
(WARDEN-WP-0044-T01) is still in progress.
2026-10-08: revised memo `nk-wp-0048-t05-oidc-browser-relying-party-r2` built
(`packet.md`, `intake.json`, packet `sha256:af6435e2…`); it states that it
supersedes the first memo and passes informed-decision's and the dispatcher's
validation. It needs a new memo id because the dispatcher refuses new content
under a delivered idempotency key (`idempotency_conflict`). Queuing it is the
same attended step as above. Both memos serve hub decision `e418263e`; the
first answer resolves it, so the founder answers r2 and leaves the first memo
unanswered. key-cape and railiance-apps were told about Forgejo's new custody
path.
```task
id: NK-WP-0048-T06
status: wait