Propose SecurityCaseTypes canon and add NK-WP-0048
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 1s

security-case-types_v0.1 (proposed): types designed once with docs, tests and
an informed-decision; known cases light (accept, ops-mason materializes,
ops-warden follows through). Founder direction 2026-10-08.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5457@bnt-lap001
Assistant-Session: 792bf84a-3783-4f5d-a811-cded61dd2012
This commit is contained in:
tegwick 2026-10-08 22:17:03 +02:00
parent d5dd19dfe2
commit 4b21f7bdee
2 changed files with 357 additions and 0 deletions

View file

@ -0,0 +1,173 @@
---
id: netkingdom-security-case-types-v0.1
type: standard
title: "NetKingdom Security Case Types v0.1"
domain: netkingdom
status: proposed
version: "0.1"
owner: net-kingdom
created: "2026-10-08"
updated: "2026-10-08"
last_reviewed: "2026-10-08"
review_interval: 3m
scope: meta-orchestration
related:
- canon/standards/playbook-capability-contract_v0.2.md
- canon/standards/security-scenario-composition_v0.1.md
- canon/standards/credential-management_v0.2.md
- docs/security-bootstrap-use-cases.md
---
# NetKingdom Security Case Types v0.1
## 1. Purpose
Most security work in the ecosystem repeats a small number of shapes: a browser
service that signs users in through NetKingdom, a service that authenticates
with its own credential, a workload that reads one KV path, an agent that needs
a short-lived SSH certificate. Until now each occurrence was built by hand: a
new helper script, a new custody path, a new founder checklist. That is slow,
and every hand-built instance can drift from the last one.
This standard separates **designing a shape** from **using it**:
- A **SecurityCaseType** is designed once, with ample documentation and tests,
and acknowledged as an informed-decision, because its shape is part of the
security architecture as a whole.
- A **SecurityCase** of an implemented type is light: the requester fills in the
type's parameters, the case is accepted, ops-mason arranges it, and ops-warden
carries it out on the authentication path the type provides.
Making a new type is deliberately harder than making a new case.
## 2. Terms
| Term | Meaning |
| --- | --- |
| **SecurityCaseType** | A reusable, versioned security pattern for one kind of use case. Defines parameters, composition, materialization, execution route, verification, rollback and threats. |
| **SecurityCase** | One instance of a type, with concrete parameter values, an owner and an acceptance record. |
| **KnownSecurityCase** | A SecurityCase whose type is `implemented` (section 5). Only known cases take the light path. |
| **Type acknowledgment** | The informed-decision that admits a type, or a new major version of a type. |
| **Case acceptance** | The record that the case's owner, and where the type requires it the founder, accepted this instance. |
| **Materialization** | ops-mason building the structure a case needs: OpenBao policies, roles and KV path structure (never values), and catalog entries. |
| **Follow-through** | ops-warden executing the case's declared entry points on the type's authentication path, and verifying it. |
A SecurityCaseType is not a new orchestration engine. It is a NetKingdom-owned
**composition** of playbook capabilities that their owning repos declare under
the Playbook Capability Contract, plus the guarantees in section 3. Execution
stays with the declared entry points (ADR-0007, ADR-0012).
## 3. What a SecurityCaseType must define
A type is a directory `security-case-types/<type-id>/` in net-kingdom containing:
1. **`type.yaml`** (machine-readable, schema `canon/schemas/security-case-type_v0.1.schema.json`):
- `id`, `version`, `status` (section 5), `title`, `purpose`
- `parameters`: each with type, validation, allowed range and whether a case
may set it. Secret values are never parameters, only custody references.
- `composition`: required playbook capability ids with exact provider pins,
in the security-scenario-composition form (fail-closed ordering, explicit
initial trust, owner attribution)
- `materialization`: the OpenBao structure ops-mason creates per case, as
templates over the parameters: policy, role, KV path, catalog entry
- `follow_through`: the ops-warden route for each step, `warden_executes`,
the auth method and the entry point; which steps need an attended human
login, if any, and why
- `verification`: the checks that prove a case is live (positive and
negative), runnable without reading a secret value
- `rollback`: the exact inverse of each step
- `acceptance`: who accepts a case (owner only, or owner and founder) and
what risk class this type carries
2. **`README.md`**: the threat model, what the type protects and from whom,
design alternatives considered, and known limits.
3. **Tests**: validation of `type.yaml`, a rendered example case, and the
composer's output for that case. A type with no runnable tests cannot be
acknowledged.
4. **Reference instances**: existing hand-built instances this type replaces
or adopts, so that the type is grounded in practice.
## 4. What a SecurityCase must define
A case is a file `security-cases/<case-id>.yaml`, in the requesting owner's
repository or in net-kingdom when it has no other owner:
- `type`: `<type-id>@<version>`, which must be `implemented`
- `parameters`: values for the type's parameters
- `owner`: the repository and person accountable for the case
- `acceptance`: who accepted it, when, and where (State Hub decision, or a
record in the owner's repository)
- `status`: `proposed` → `accepted` → `materialized` → `live` → `retired`
Nothing else. Everything a case needs beyond its parameters belongs in its type.
If a case cannot be expressed in its type's parameters, it is not a case of that
type: either change the case or propose a new type version (section 6).
## 5. Type lifecycle
| Status | Meaning | Who moves it |
| --- | --- | --- |
| `draft` | being written; not usable | type author |
| `proposed` | complete per section 3, tests green, Decision Memo prepared | type author |
| `acknowledged` | admitted by informed-decision | the founder, through informed-decision |
| `implemented` | ops-mason can materialize it and ops-warden can follow through; one reference case is live and verified | net-kingdom, with ops-mason and ops-warden |
| `deprecated` | no new cases; existing cases keep running | net-kingdom |
| `retired` | no cases remain | net-kingdom |
Only `implemented` types accept new cases.
## 6. Changing a type
- **Patch** (documentation, tests, a stricter validation): a normal reviewed
change; no decision.
- **Minor** (a new optional parameter, an extra verification step): a
reviewed change, recorded in the type's history; no new acknowledgment unless
the risk class changes.
- **Major** (a changed authentication path, materialization or trust
transition; a looser validation; a higher risk class): a new informed-decision,
as for a new type. Existing cases stay on their version until migrated.
## 7. The light path for known cases
For a case of an `implemented` type:
1. The requester writes the case file and validates it against the type.
2. The accepter records acceptance (section 4). This is the only human step
unless the type's `acceptance` requires an attended login for a specific
step, which the type must justify.
3. ops-mason materializes it from the type's templates. Its executive-summary
gate collapses to the case acceptance, because the shape was decided when the
type was acknowledged.
4. ops-warden follows through on the type's route and runs the type's
verification.
5. The case moves to `live` with the verification receipt.
No case-specific helper script is written. If one seems necessary, the type is
incomplete.
## 8. Roles
| Party | Responsibility |
| --- | --- |
| net-kingdom | owns this standard, the type directory, the schema and the composer; admits and retires types |
| ops-mason | materializes OpenBao structure for cases from type templates; proposes the type's materialization section |
| ops-warden | follows through on cases; owns the routing catalog entries a type defines; proposes the type's follow-through section |
| owning repositories (key-cape, railiance-platform, ...) | declare the playbook capabilities that types compose; own execution |
| informed-decision | presents the type's Decision Memo to the founder and records acknowledgment |
| requesters | write cases, own them, retire them |
## 9. Boundaries
- No secret value in a type, a case, a test or a receipt.
- This standard does not grant execution authority. Each step runs under its
owner's declared entry point and its own authentication.
- Existing hand-built instances keep working. They are adopted as cases when
their type is implemented, not rewritten in place.
## 10. Open questions for v0.1 review
- Where should case files live by default: with the requester, or centrally in
net-kingdom?
- Is the informed-decision Decision Memo for a type rendered from `type.yaml`
and `README.md`, or written separately?
- Which steps of the first types genuinely need an attended human login (for
example key-cape's live client configuration), and how is that minimised?

View file

@ -0,0 +1,184 @@
---
id: NK-WP-0048
type: workplan
title: "Establish SecurityCaseTypes so that known security cases are light"
domain: infotech
repo: net-kingdom
status: ready
flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-08"
updated: "2026-10-08"
depends_on: []
related_repos:
- ops-mason
- ops-warden
- key-cape
- railiance-platform
- informed-decision
---
# NK-WP-0048 - Establish SecurityCaseTypes so that known security cases are light
## Why
The founder's direction (2026-10-08): setting up a security integration of a
kind that has been done before should be easy, meaning accept the case, then
ops-mason arranges it and ops-warden follows through. Setting up a new kind
needs ample documentation and tests and an informed-decision, because its shape
is part of the security architecture.
Today every integration is hand-built: per-client helper scripts, per-lane
custody, founder checklists. The trigger was KEY-WP-0038 (Forgejo as an OIDC
client), whose next step was going to be yet another hand-written rollout
script.
This plan continues the pattern work of NK-WP-0008 (pattern infospace),
NK-WP-0009 (tutorials) and NK-WP-0030 (scenario composition). It turns patterns
into **SecurityCaseTypes** that ops-mason and ops-warden can execute. Canon:
`canon/standards/security-case-types_v0.1.md` (proposed).
Companion plans: ops-mason `MASON-WP-0010` (materialization) and ops-warden
`WARDEN-WP-0044` (follow-through).
## Tasks
```task
id: NK-WP-0048-T01
status: wait
needs_human: true
blocking_reason: "The founder reviews and accepts the security-case-types_v0.1 canon proposal."
priority: high
```
### T01 — Accept the terminology and the canon
Founder review of `canon/standards/security-case-types_v0.1.md`, including its
section 10 open questions. On acceptance the canon status goes from `proposed`
to `accepted`.
```task
id: NK-WP-0048-T02
status: todo
priority: high
```
### T02 — Inventory the de-facto types already built by hand
Read-only. List every security integration built so far and group them by shape.
Known starting points:
- browser OIDC relying parties on key-cape: informed-decision-approver,
coulomb-social, user-engine portal, openbao-admin, and Forgejo (pending)
- confidential service clients with `client_credentials`: secrets-engine
approval, requester and openbao clients, approval-engine operator
- workload KV read lanes on OpenBao: the railiance-platform credential lane
designs and CCRs, for example `railiance-backup-offsite-lane`
- short-lived SSH certificates through ops-warden (`warden sign`)
- tunnelled operator access (ops-bridge)
For each: the repositories involved, the hand-built steps, attended human steps,
custody paths, verification evidence, and rollback (if any). Output
`docs/security-case-type-inventory.md`, ranking candidate types by how often the
shape recurs and how much manual work each instance costs today.
```task
id: NK-WP-0048-T03
status: wait
depends_on: [NK-WP-0048-T01]
blocking_reason: "The schema and template follow the accepted canon."
priority: high
```
### T03 — Schema, template and validator
- `canon/schemas/security-case-type_v0.1.schema.json` and
`security-case_v0.1.schema.json`
- `security-case-types/_template/` with `type.yaml`, `README.md` and tests to copy
- a validator, extending `tools/security-scenario-composer/`, that checks a type,
checks a case against its type, and renders the case into the composer's
deterministic plan (still `execution.permitted: false`)
Acceptance: the validator rejects missing sections, secret-shaped parameter
values, unpinned providers and cases against non-`implemented` types, with tests
for each.
```task
id: NK-WP-0048-T04
status: wait
depends_on: [NK-WP-0048-T02, NK-WP-0048-T03, MASON-WP-0010-T01, WARDEN-WP-0044-T01]
blocking_reason: "The first type needs the inventory, the template, and ops-mason/ops-warden's sections."
priority: high
```
### T04 — Define the first type: browser OIDC relying party
`security-case-types/oidc-browser-relying-party/`, version 1.0:
- parameters: client id, display name, exact redirect URIs, scopes, client type
(confidential or public), MFA pin, the groups the consuming service maps,
custody path for the secret (confidential only), consuming service and its
owner
- composition: key-cape client registration (key-cape declares it as a playbook
capability), secret minting into custody (railiance-platform), LLDAP group
existence and membership (net-kingdom identity-provisioner), handover to the
consuming service
- materialization (ops-mason) and follow-through (ops-warden) sections
- verification: discovery lists the redirect URI; a test sign-in returns the
expected claims for one human; anonymous access to the custody path is denied
- rollback: remove exactly this client and its custody path
- README: threat model, MFA rationale, why redirect URIs are exact, which steps
still need an attended login and how that is minimised
- reference instances: informed-decision-approver, coulomb-social, user-engine
portal, openbao-admin
Acceptance: complete per canon section 3, tests green, status `proposed`.
```task
id: NK-WP-0048-T05
status: wait
depends_on: [NK-WP-0048-T04]
needs_human: true
blocking_reason: "A new SecurityCaseType is acknowledged as an informed-decision by the founder."
priority: high
```
### T05 — Acknowledge the type through informed-decision
Prepare the Decision Memo from the type's README and `type.yaml` and submit it
through informed-decision's production intake. On acknowledgment the type
moves to `acknowledged`.
```task
id: NK-WP-0048-T06
status: wait
depends_on: [NK-WP-0048-T05, MASON-WP-0010-T03, WARDEN-WP-0044-T03]
blocking_reason: "Implementation needs the acknowledged type and both executors' light paths."
priority: high
```
### T06 — First KnownSecurityCase: Forgejo
Write `security-cases/forgejo-netkingdom-oidc.yaml` from the parameters the
founder accepted in KEY-WP-0038-T01 (`key-cape/docs/forgejo-oidc-client-request.yaml`),
so that acceptance carries over as the case acceptance. ops-mason materializes it;
ops-warden follows through and verifies it. The type becomes `implemented` once
this reference case is live.
This replaces the hand-built path proposed for KEY-WP-0038-T02.
```task
id: NK-WP-0048-T07
status: wait
depends_on: [NK-WP-0048-T06]
blocking_reason: "The next types follow once the first one is proven end to end."
priority: medium
```
### T07 — Queue the next types
From the T02 ranking, open the next type drafts (likely the confidential service
client and the workload KV read lane), each to be acknowledged on its own.
Record which existing hand-built instances get adopted as cases, without
rewriting them in place.