Playbook capability (contract PASS, maturity planned) composed by net-kingdom's SecurityCaseType oidc-browser-relying-party. T04 implements tools/keycape-client, generalizing the per-client rollout helpers. 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
171 lines
7.1 KiB
Markdown
171 lines
7.1 KiB
Markdown
---
|
|
id: KEY-WP-0038
|
|
type: workplan
|
|
title: "Forgejo as a NetKingdom OIDC client, so the forge can close"
|
|
domain: infotech
|
|
repo: key-cape
|
|
status: active
|
|
flavor: implementation
|
|
owner: claude-code
|
|
topic_slug: railiance
|
|
created: "2026-10-08"
|
|
updated: "2026-10-08"
|
|
depends_on: []
|
|
related_repos:
|
|
- prj-forgejo-org-refactor
|
|
- railiance-apps
|
|
- railiance-platform
|
|
state_hub_workstream_id: "098e3e2c-a138-560e-b2d3-3a15eb49d8a9"
|
|
---
|
|
|
|
# KEY-WP-0038 - Forgejo as a NetKingdom OIDC client, so the forge can close
|
|
|
|
## Why
|
|
|
|
`forgejo.coulomb.social` is closing: private by default, no anonymous access
|
|
(prj-forgejo-org-refactor ORGREF-WP-0002, decision
|
|
`decisions/forge-visibility-policy.md`). The founder's condition is that Forgejo
|
|
sign-in runs through NetKingdom **before** anything closes, so that every human,
|
|
agent and service reader has a governed identity rather than an ad-hoc local
|
|
account. This plan is ORGREF-WP-0002-T04. Its Forgejo-side counterpart is
|
|
railiance-apps `RAPPS-WP-0016` (ORGREF-WP-0002-T05), which owns the Forgejo
|
|
Helm release.
|
|
|
|
## Boundaries
|
|
|
|
- Registration follows the existing human browser-client pattern
|
|
(`docs/approval-engine-provisioning-request.yaml`, `human_registration`) and the
|
|
client fields validated in KEY-WP-0028. Redirect URIs are exact, never
|
|
wildcards.
|
|
- The client secret goes to OpenBao through railiance-platform custody. No secret
|
|
value in git, State Hub, logs or chat.
|
|
- Founder guardrail for the whole closure: tighten gradually, never lock anyone
|
|
out, never risk assets. Nothing in this plan changes who can read the forge
|
|
today. It only makes the NetKingdom path available.
|
|
|
|
## Tasks
|
|
|
|
```task
|
|
id: KEY-WP-0038-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "5f019d13-1fa3-5b88-a27a-75a3339ca96e"
|
|
```
|
|
|
|
### T01 — Define what Forgejo receives
|
|
|
|
Write the claim contract Forgejo consumes, as a non-secret request packet under
|
|
`docs/`:
|
|
|
|
- issuer `https://kc.coulomb.social`; confidential client `forgejo`; authorization
|
|
code with PKCE; scopes `openid profile email groups`
|
|
- redirect URI
|
|
`https://forgejo.coulomb.social/user/oauth2/netkingdom/callback`. The
|
|
authentication-source name `netkingdom` must match railiance-apps'
|
|
configuration exactly.
|
|
- subject and username: canonical directory subject, plus a stable
|
|
`preferred_username` that Forgejo can match to the existing local accounts
|
|
(founder and agent accounts) for linking
|
|
- `groups` naming the Forgejo organisations and teams to map to (for example
|
|
`forge:coulomb:owners`, `forge:coulomb:readers`), and `principal_type` so that
|
|
human and service principals stay distinguishable
|
|
- MFA: forge administrators and owners require assurance with a fresh second
|
|
factor; plain readers follow the client-aware MFA policy (KEY-WP-0008)
|
|
|
|
Acceptance: the founder accepts the packet. The group names are agreed with
|
|
railiance-apps.
|
|
|
|
2026-10-08: packet drafted at `docs/forgejo-oidc-client-request.yaml`. It covers a
|
|
confidential client `forgejo` with PKCE and `mfaRequired: true`, the exact
|
|
callback, scopes, a custody path, the claims as emitted at this revision, new
|
|
LLDAP groups `forge-admins`, `forge-coulomb-owners` and `forge-coulomb-readers`
|
|
with a required-claim gate, no automatic account creation, and linking of local
|
|
accounts. It also proposes that agents and services use scoped tokens bound to
|
|
service identities, not browser sign-in.
|
|
|
|
2026-10-08: accepted by the founder (in session). railiance-apps' RAPPS-WP-0016
|
|
uses the same authentication-source name `netkingdom` and the same group names,
|
|
so the agreement condition holds. Before T02, the LLDAP groups `forge-admins`,
|
|
`forge-coulomb-owners` and `forge-coulomb-readers` must exist, with the founder
|
|
in the first two.
|
|
|
|
```task
|
|
id: KEY-WP-0038-T02
|
|
status: wait
|
|
depends_on: [KEY-WP-0038-T01, NK-WP-0048-T06]
|
|
blocking_reason: "Registration runs as the first KnownSecurityCase of type oidc-browser-relying-party (NK-WP-0048-T06), not as a hand-built rollout."
|
|
priority: high
|
|
state_hub_task_id: "ddcfb482-8f33-5c81-9ce8-84be8fa5dc30"
|
|
```
|
|
|
|
### T02 — Register the client and hand over its secret
|
|
|
|
**Changed 2026-10-08 (founder direction):** no case-specific helper script.
|
|
Registration is the first case of the SecurityCaseType `oidc-browser-relying-party`
|
|
(net-kingdom NK-WP-0048, canon `security-case-types_v0.1`). The parameters
|
|
accepted in T01 become the case; ops-mason materializes it (MASON-WP-0010) and
|
|
ops-warden follows through (WARDEN-WP-0044). key-cape's part is to declare
|
|
client registration as a playbook capability that the type composes, and to
|
|
review the type's composition.
|
|
|
|
The original intent below still describes what must result.
|
|
|
|
Register `forgejo` from the packet. Mint the client secret straight into custody
|
|
(proposed OpenBao path `platform/workloads/forgejo/netkingdom-oidc-client`,
|
|
custody owner railiance-platform, consumer Forgejo). Record a receipt with no
|
|
secret value.
|
|
|
|
Acceptance: discovery metadata lists the client's redirect URI. The secret is
|
|
readable by Forgejo's custody path only.
|
|
|
|
```task
|
|
id: KEY-WP-0038-T03
|
|
status: wait
|
|
depends_on: [KEY-WP-0038-T02]
|
|
blocking_reason: "Claims are verified against the registered client."
|
|
priority: high
|
|
state_hub_task_id: "40ddaa29-7245-508c-ad48-ddc063e25115"
|
|
```
|
|
|
|
### T03 — Prove the claims for each kind of identity
|
|
|
|
Before Forgejo uses the client, verify the issued ID token and UserInfo for one
|
|
human (the founder, with MFA), one agent identity and one service identity:
|
|
subject, `preferred_username`, `groups`, `principal_type`, assurance. Record the
|
|
claims, minus tokens, as evidence.
|
|
|
|
Decide with railiance-apps whether agents and services sign in to Forgejo at
|
|
all, or receive scoped Forgejo tokens bound to a NetKingdom service identity
|
|
(ORGREF-WP-0002-T06). Record the decision.
|
|
|
|
Acceptance: evidence for all three principals; the agent and service decision is
|
|
recorded. Then hand over to RAPPS-WP-0016.
|
|
|
|
```task
|
|
id: KEY-WP-0038-T04
|
|
status: todo
|
|
priority: high
|
|
```
|
|
|
|
### T04 — Implement the `keycape-client` entry point
|
|
|
|
`capabilities/playbooks/key-cape.oidc-client-registration.yaml` (contract PASS,
|
|
`maturity: planned`) declares client registration as a playbook capability, so
|
|
that the SecurityCaseType `oidc-browser-relying-party` (net-kingdom NK-WP-0048)
|
|
can compose it. Implement the entry point it names, `tools/keycape-client/`:
|
|
|
|
- `keycape-client register --client-file <rendered-client.yaml>` with modes
|
|
`inspect`, `dry-run`, `apply` and `remove`; adds, updates or removes exactly one
|
|
client in the live registry; idempotent; never prints or writes secret values;
|
|
a confidential client's secret is read from its custody reference
|
|
- one implementation replacing the per-client helpers in net-kingdom
|
|
`sso-mfa/k8s/keycape/` (register-coulomb-social, portal-client-rollout,
|
|
vergabe-client-rollout, secrets-engine-openbao-client-rollout), keeping their
|
|
safeguards (byte-preserving merge, compare-and-swap, cluster pin, safe receipts)
|
|
and their tests as regression cases
|
|
- client field validation by the KEY-WP-0028 rules
|
|
- then set the declaration's `maturity` to `implemented`
|
|
|
|
Longer term, loading clients from a non-secret registry with secrets referenced
|
|
from custody would remove the type's only attended step (see the type README,
|
|
"Attended steps").
|