generated from coulomb/repo-seed
feat(close): mark KEY-WP-0001 done — all 23 tasks complete, tests passing
Some checks failed
CI / Build and Test (push) Has been cancelled
Some checks failed
CI / Build and Test (push) Has been cancelled
All implementation phases complete: OIDC server (Authorization Code + PKCE), canonical identity model + LDAP validator, backend adapters (Authelia/LLDAP/ privacyIDEA), telemetry, enforcement middleware, migration tooling, and all four replacement test scenarios (A–D). Tests pass with Go 1.23. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,13 +4,13 @@ type: workplan
|
||||
title: "KeyCape Implementation — Lightweight IAM Profile"
|
||||
domain: netkingdom
|
||||
repo: key-cape
|
||||
status: active
|
||||
status: done
|
||||
owner: Bernd
|
||||
topic_slug: netkingdom
|
||||
workstream_id: 2c9caad8-2ced-492d-9d63-376387b4b9b0
|
||||
topic_id: a6c6e745-bf54-4465-9340-1534a2be493e
|
||||
repo_id: 8a99bb74-1ec0-4478-ac70-35a7cddb0e3c
|
||||
created: 2026-03-13
|
||||
updated: 2026-03-13
|
||||
spec_refs:
|
||||
- wiki/KeyCapeSpecification_v0.1.md
|
||||
- wiki/KeyCapeSpecificationPack_v0.1.md
|
||||
@@ -20,6 +20,7 @@ decisions:
|
||||
hub_decision_id: 620beb04-fa3f-4a9d-9806-02890a7a2b0d
|
||||
status: accepted
|
||||
ref: docs/adr/ADR-0001-choose-go-for-keycape.md
|
||||
state_hub_workstream_id: "0d34dfc1-7ccb-4bd5-b872-5c7379b9adce"
|
||||
---
|
||||
|
||||
# KEY-WP-0001 — KeyCape Implementation
|
||||
@@ -95,7 +96,8 @@ T01 (project setup)
|
||||
id: KEY-WP-0001-T01
|
||||
hub_task_id: 25613e3f-2a65-409e-afaa-d23ded0bc256
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
state_hub_task_id: "38822bc0-4189-4909-874e-ea40e5771250"
|
||||
```
|
||||
|
||||
Initialise language module in `src/`. Create directory skeleton per spec §12. Add Makefile
|
||||
@@ -108,8 +110,9 @@ no application code. **Agent must call `record_decision()` with chosen language
|
||||
id: KEY-WP-0001-T02
|
||||
hub_task_id: deee2929-9386-41db-bf91-fbd9ad646c28
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01]
|
||||
state_hub_task_id: "940c118b-c1e6-4dda-bd4c-4fac105822be"
|
||||
```
|
||||
|
||||
Write `spec/canonical-model.yaml`. Six entities: User, Group, Role, Client, Membership,
|
||||
@@ -122,8 +125,9 @@ validation. This file is the **source of truth** — all other code derives from
|
||||
id: KEY-WP-0001-T03
|
||||
hub_task_id: 02592c65-db23-474b-b06b-019e95df8146
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01, T02]
|
||||
state_hub_task_id: "c1715d70-f10f-45e9-b73a-b54a3d360342"
|
||||
```
|
||||
|
||||
Write `spec/ldap-schema.yaml`: tree layout (`ou=users`, `ou=groups`, `ou=clients` under
|
||||
@@ -139,8 +143,9 @@ machine-readable report.
|
||||
id: KEY-WP-0001-T04
|
||||
hub_task_id: 46870fd6-0672-432b-8824-6bc2e24811b3
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01]
|
||||
state_hub_task_id: "6e3b6b97-ac77-44c5-959e-be12751f1b63"
|
||||
```
|
||||
|
||||
Implement four error types (spec §5):
|
||||
@@ -162,8 +167,9 @@ all handler errors. Error type strings are stable and test-assertable.
|
||||
id: KEY-WP-0001-T05
|
||||
hub_task_id: 92eb8916-cb22-4786-9f16-a8a07272f818
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T04]
|
||||
state_hub_task_id: "0dbc08e3-c465-4c37-a219-832a580bedfd"
|
||||
```
|
||||
|
||||
`GET /.well-known/openid-configuration`. Advertise **only** profile-supported features:
|
||||
@@ -176,8 +182,9 @@ implicit flow. Issuer configurable. Cacheable response.
|
||||
id: KEY-WP-0001-T06
|
||||
hub_task_id: c3df620b-9864-4ff1-ba6d-26057c6f4d59
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T04, T11, T12, T13, T14]
|
||||
state_hub_task_id: "cdb4b06d-3d54-49dd-ac05-ca9ed6d7322f"
|
||||
```
|
||||
|
||||
`GET/POST /authorize`. Validate: `client_id` (static config), `redirect_uri` (exact match —
|
||||
@@ -191,8 +198,9 @@ Delegate to Authelia adapter. Store PKCE state server-side. No implicit or hybri
|
||||
id: KEY-WP-0001-T07
|
||||
hub_task_id: d3248f4d-e0e9-4144-9844-c9768dc896d6
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T06, T08, T10]
|
||||
state_hub_task_id: "534d8616-90de-4d32-961c-c2ef719642e4"
|
||||
```
|
||||
|
||||
`POST /token`. Validate PKCE `code_verifier`. Issue RS256 JWT via standard library (no custom
|
||||
@@ -207,8 +215,9 @@ claims: `preferred_username` (LDAP `uid`), `email` (LDAP `mail`), `groups` (grou
|
||||
id: KEY-WP-0001-T08
|
||||
hub_task_id: 58a1d705-b788-4d66-8c0a-33edff63a885
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01]
|
||||
state_hub_task_id: "7e2167be-bcc7-49c2-8681-e518abd5bc0c"
|
||||
```
|
||||
|
||||
`GET /jwks`. RS256 public key in JWK Set format. Key loaded from config. Key rotation: serve
|
||||
@@ -220,8 +229,9 @@ multiple keys during rotation window, keyed by `kid`. Standard library key gener
|
||||
id: KEY-WP-0001-T09
|
||||
hub_task_id: 742d3924-21e9-4304-86e9-0400af0e81ee
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T07, T10]
|
||||
state_hub_task_id: "78094ca5-a831-4443-9ccf-fc476ff87b91"
|
||||
```
|
||||
|
||||
`GET /userinfo`. Optional per spec — implement if any registered client requires it. Validate
|
||||
@@ -239,8 +249,9 @@ identical to ID token for same scopes. If no client needs it: stub returning
|
||||
id: KEY-WP-0001-T10
|
||||
hub_task_id: 2043b10a-6822-45f8-abcc-4e233d918fb0
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T02, T03]
|
||||
state_hub_task_id: "97d19662-f482-4ea5-84fd-9fccb84ff317"
|
||||
```
|
||||
|
||||
`adapters/lldap`. LDAP protocol connection to LLDAP. Interface: `LookupUser(username) → canonical
|
||||
@@ -254,8 +265,9 @@ validator on every read. No LDAP internals exposed to `server/`.
|
||||
id: KEY-WP-0001-T11
|
||||
hub_task_id: ad129a14-1552-4717-b1dd-b529d18ce681
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T04, T13]
|
||||
state_hub_task_id: "6461865b-f57c-4591-9cf3-68c79af22723"
|
||||
```
|
||||
|
||||
`adapters/authelia`. Initiate auth redirect to Authelia, receive callback, extract authenticated
|
||||
@@ -268,8 +280,9 @@ profile layer. Unavailable Authelia → fail closed (`auth_failure` event).
|
||||
id: KEY-WP-0001-T12
|
||||
hub_task_id: 1ef196e6-2304-4cf6-b205-47ac1da879ec
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T02, T13]
|
||||
state_hub_task_id: "e403a783-c856-4d6d-b859-a9cad7545fe1"
|
||||
```
|
||||
|
||||
`adapters/privacyidea`. **KeyCape must NOT implement MFA logic.** Interface:
|
||||
@@ -287,8 +300,9 @@ privacyIDEA remains stable across lightweight → expanded migration.
|
||||
id: KEY-WP-0001-T13
|
||||
hub_task_id: 704146bf-cd60-4922-b18b-3d209cff3ac3
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01]
|
||||
state_hub_task_id: "4df7bda1-5b84-4b4c-9b16-bcb1d3cca096"
|
||||
```
|
||||
|
||||
`server/telemetry`. Event types (spec §6.1): `auth_start`, `auth_success`, `auth_failure`,
|
||||
@@ -303,8 +317,9 @@ metrics endpoint. Every auth and error path emits an event — **no silent paths
|
||||
id: KEY-WP-0001-T14
|
||||
hub_task_id: 71f44886-ab61-4160-a435-72b35af472a0
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T04, T13]
|
||||
state_hub_task_id: "ae16fba9-5bb4-4780-ac77-558e3ed7e1dd"
|
||||
```
|
||||
|
||||
`server/errors` enforcement middleware. Intercept any parameter, grant type, scope, or client
|
||||
@@ -323,8 +338,9 @@ Every registry entry must have a corresponding test in T21.
|
||||
id: KEY-WP-0001-T15
|
||||
hub_task_id: 1bd13f76-2d62-429d-b230-d785ef6a3f2f
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T02, T03, T10]
|
||||
state_hub_task_id: "f7549cd7-33f0-4407-a656-ab8f5a184e64"
|
||||
```
|
||||
|
||||
`migration/lldap-export` tool. Read all users, groups, memberships, attributes from LLDAP. Map
|
||||
@@ -338,8 +354,9 @@ report for unmappable LLDAP data.
|
||||
id: KEY-WP-0001-T16
|
||||
hub_task_id: f3d50e80-f6b5-4c0c-a5f3-08308ea1a95e
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T15]
|
||||
state_hub_task_id: "96486c41-9f33-42a5-b7b6-ad0a9eb2bdee"
|
||||
```
|
||||
|
||||
`migration/keycape-to-keycloak` tool. Read canonical export (T15). Transform to Keycloak realm
|
||||
@@ -353,8 +370,9 @@ Include round-trip validation report.
|
||||
id: KEY-WP-0001-T17
|
||||
hub_task_id: 044d99c8-39cb-4f35-9308-912ae829bd22
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T15]
|
||||
state_hub_task_id: "1ec335a2-80ca-4c34-b08e-211f537e4214"
|
||||
```
|
||||
|
||||
`migration/lldap-to-ldap` tool. Export via T15 canonical export. Generate LDIF for target
|
||||
@@ -372,8 +390,9 @@ migration dimensions are independent (spec §14.1).
|
||||
id: KEY-WP-0001-T18
|
||||
hub_task_id: 76abc3f6-9c4e-4aca-9995-72b728925812
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T05, T06, T07, T08, T09, T22]
|
||||
state_hub_task_id: "1b0e9f26-d441-42b8-b532-1eb713fb355d"
|
||||
```
|
||||
|
||||
`tests/profile`. Provision canonical fixtures into LLDAP + Authelia + KeyCape. Test categories
|
||||
@@ -387,8 +406,9 @@ redirect validation, client config, MFA policy, logout (if implemented). Tests a
|
||||
id: KEY-WP-0001-T19
|
||||
hub_task_id: 56d03e89-934b-4992-bfe4-b32f275882e3
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T18, T16]
|
||||
state_hub_task_id: "a02d24e7-32de-4be6-935c-896c10dde020"
|
||||
```
|
||||
|
||||
Run T18 suite against Keycloak + LLDAP (configured from T16 canonical export). **No test code
|
||||
@@ -401,8 +421,9 @@ without directory migration.
|
||||
id: KEY-WP-0001-T20
|
||||
hub_task_id: ec3cae5c-9942-4be7-acc0-1eb9f02aba45
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T19, T17]
|
||||
state_hub_task_id: "545f319f-053d-48bd-8d94-c8c05cd56736"
|
||||
```
|
||||
|
||||
Apply T17 LLDAP→OpenLDAP migration, then T16 Keycloak import. Run T18 suite. Migration successful
|
||||
@@ -414,8 +435,9 @@ only if all tests pass. privacyIDEA must remain stable (no MFA re-enrollment req
|
||||
id: KEY-WP-0001-T21
|
||||
hub_task_id: a5112b63-121f-4d17-ac1a-fb46d160413e
|
||||
priority: high
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T14]
|
||||
state_hub_task_id: "5856afe0-2a9e-4489-b057-35e59f86c359"
|
||||
```
|
||||
|
||||
`tests/negative`. For every entry in T14 unsupported-feature registry: attempt usage, assert
|
||||
@@ -434,8 +456,9 @@ is complete.
|
||||
id: KEY-WP-0001-T22
|
||||
hub_task_id: e840963f-cd19-4b38-857a-7c40df165d3d
|
||||
priority: medium
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T01]
|
||||
state_hub_task_id: "b98f2671-a20a-4438-99c9-fbe0e5324534"
|
||||
```
|
||||
|
||||
`docker-compose.dev.yml`: KeyCape, LLDAP, Authelia, privacyIDEA (or stub). Pre-seeded with
|
||||
@@ -449,8 +472,9 @@ Test environment for T18 and T21.
|
||||
id: KEY-WP-0001-T23
|
||||
hub_task_id: d5723683-f739-4362-b62e-71213dc5a89e
|
||||
priority: low
|
||||
status: todo
|
||||
status: done
|
||||
depends_on: [T18, T21]
|
||||
state_hub_task_id: "8c1752c2-7fb3-4da5-aab3-6b7acf12ea64"
|
||||
```
|
||||
|
||||
Single stateless binary. Declarative YAML config: profile version, client definitions, backend
|
||||
|
||||
Reference in New Issue
Block a user