key-cape/workplans/KEY-WP-0038-forgejo-oidc-client.md
tegwick 213b98feb1 KEY-WP-0038-T04 cancelled: entry point moved to net-kingdom NK-WP-0048-T09
Remove the draft key-cape.oidc-client-registration declaration; net-kingdom
declares net-kingdom.keycape-client-registration beside the live deployment
machinery.

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
2026-10-08 23:03:58 +02:00

7.7 KiB

id type title domain repo status flavor owner topic_slug created updated depends_on related_repos state_hub_workstream_id
KEY-WP-0038 workplan Forgejo as a NetKingdom OIDC client, so the forge can close infotech key-cape active implementation claude-code railiance 2026-10-08 2026-10-08
prj-forgejo-org-refactor
railiance-apps
railiance-platform
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

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.

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). The registration capability is net-kingdom's (net-kingdom.keycape-client-registration); key-cape's part is its field rules and reviewing 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.

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.

id: KEY-WP-0038-T04
status: cancel
priority: high
state_hub_task_id: "583cf1f1-16dc-515f-83bc-1efc45024a89"

T04 — Implement the keycape-client entry point

Cancelled 2026-10-08: moved to net-kingdom NK-WP-0048-T09 (done). The live registration machinery (contained kubectl, cluster and issuer pins) already lives in net-kingdom sso-mfa/k8s/keycape/, where KeyCape is deployed; a copy here would drift. The entry point is net-kingdom/sso-mfa/k8s/keycape/keycape-client.py and the declaration is net-kingdom.keycape-client-registration; key-cape's draft declaration is removed. key-cape still owns the client field rules (canonical model) and their enforcement at authorization time.

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").