docs(19.4-02): complete sm-oauthserver-plugin plan
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
---
|
||||
phase: 19.4-oidc-provider-on-wristband
|
||||
plan: 02
|
||||
subsystem: auth
|
||||
tags: [oidc, oauth, wristband, plugin, gorm, postgres, keyring, rs256, es256, consent, branding, throttle, mcp, go-oidc]
|
||||
|
||||
requires:
|
||||
- phase: 19.4-01
|
||||
provides: wristband OIDC flavour (NewOIDCServer, SetOIDCBackend, OIDCBackend/OIDCTx, KeyStore, OIDCHost, ConsentRequest/DecideConsent, kinds)
|
||||
- phase: 19.3
|
||||
provides: bouncer cookie transport (LoadCookieConfig, ForgetTokenCookie) used by EndRequestSession
|
||||
provides:
|
||||
- new repository sm-oauthserver-plugin (module git.golem15.com/golem15/sm-oauthserver-plugin, plugin golem15.oauthserver, requires golem15.user)
|
||||
- golem15_oauthserver_* tables (PHP names and columns) plus _keys, _refresh_tokens, _settings, _mcp_codes
|
||||
- classes.Store (wristband.OIDCBackend) and classes.MCPStore (wristband.Backend) over the same tables, filtered by kind in SQL
|
||||
- classes.KeyRing (wristband.KeyStore) with encrypted private keys, lazy race-safe first key, Rotate and Prune for plan 03's commands
|
||||
- branded consent and error pages, redirect consent mode with JSON endpoints, PHP claims, PHP throttles
|
||||
- authorized-apps API (list, revoke), user.Deleting / user.Deactivating cascade
|
||||
- MCP routes behind golem15.oauthserver.mcp.enabled (default false)
|
||||
- sm-user-plugin additive exports RequestUser, EndRequestSession, AvatarURL, DeactivatingEvent, FireDeactivatingEvent
|
||||
- TestRelyingPartyInterop with go-oidc v3.21.0 and x/oauth2 v0.37.0 (test-only) on RS256 and ES256 rings
|
||||
affects: [19.4-03, 19.4-04, 19.7, fonoteka, sm-user-plugin consumers]
|
||||
|
||||
actuals:
|
||||
tokens: 59000 # chars/4: sm-oauthserver-plugin tracked files without go.sum (225159 chars) + sm-user-plugin added lines (10671 chars)
|
||||
tasks: 5 # 4 executed tasks + the Task 4 checkpoint
|
||||
commits: 7 # measured: sm-user-plugin c077029..80b436d = 3, sm-oauthserver-plugin rev-list --count HEAD = 4 (root commit is the plan's first)
|
||||
plan_head_before: "sm-user-plugin c077029; sm-oauthserver-plugin (new repository, no commits); summercms.go 1c0d22a216d074e77c1809740bcf6f8af9481a7d"
|
||||
plan_head_after: "sm-user-plugin 80b436d; sm-oauthserver-plugin f1cc3b9; summercms.go: this SUMMARY commit"
|
||||
|
||||
tech-stack:
|
||||
added:
|
||||
- "github.com/coreos/go-oidc/v3 v3.21.0 (test-only, sm-oauthserver-plugin)"
|
||||
- "golang.org/x/oauth2 v0.37.0 (test-only, sm-oauthserver-plugin; was already v0.36.0 indirect)"
|
||||
- "github.com/go-jose/go-jose/v4 v4.1.4 (indirect, via go-oidc)"
|
||||
patterns:
|
||||
- "Shared plugin publishes one *oauthserver.Servers wrapper (OIDC, MCP, KeyRing), never a bare *wristband.Server"
|
||||
- "Lazy stores resolve *gorm.DB at request time and fail closed"
|
||||
- "Key material read and written with a silent GORM logger; first key via INSERT ... ON CONFLICT (active) WHERE active DO NOTHING"
|
||||
- "Plugin-owned body-limit middleware factory for GroupRaw routes (surf body.limit ignores raw groups)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- ../sm-oauthserver-plugin/plugin.go
|
||||
- ../sm-oauthserver-plugin/servers.go
|
||||
- ../sm-oauthserver-plugin/routes.go
|
||||
- ../sm-oauthserver-plugin/buckets.go
|
||||
- ../sm-oauthserver-plugin/middleware.go
|
||||
- ../sm-oauthserver-plugin/classes/oidc_store.go
|
||||
- ../sm-oauthserver-plugin/classes/mcp_store.go
|
||||
- ../sm-oauthserver-plugin/classes/keyring.go
|
||||
- ../sm-oauthserver-plugin/classes/claims.go
|
||||
- ../sm-oauthserver-plugin/classes/host.go
|
||||
- ../sm-oauthserver-plugin/classes/branding.go
|
||||
- ../sm-oauthserver-plugin/classes/cascade.go
|
||||
- ../sm-oauthserver-plugin/classes/lazy.go
|
||||
- ../sm-oauthserver-plugin/controllers/authorizations.go
|
||||
- ../sm-oauthserver-plugin/controllers/consent_api.go
|
||||
- ../sm-oauthserver-plugin/updates/202610190001_create_golem15_oauthserver_tables.go
|
||||
- ../sm-oauthserver-plugin/updates/202610190002_create_golem15_oauthserver_settings.go
|
||||
- ../sm-oauthserver-plugin/updates/202610190003_create_golem15_oauthserver_mcp_codes.go
|
||||
- ../sm-oauthserver-plugin/views/consent.html.tmpl
|
||||
- ../sm-oauthserver-plugin/views/error.html.tmpl
|
||||
- ../sm-oauthserver-plugin/interop_test.go
|
||||
- ../fonoteka.go/plugins/golem15/user/classes/session_user.go
|
||||
- ../fonoteka.go/plugins/golem15/user/classes/avatar.go
|
||||
modified:
|
||||
- ../fonoteka.go/plugins/golem15/user/classes/events.go
|
||||
- ../fonoteka.go/plugins/golem15/user/controllers/api_controller.go
|
||||
- ../fonoteka.go/plugins/golem15/user/controllers/registration.go
|
||||
- ../fonoteka.go/plugins/golem15/user/controllers/users_admin_controller.go
|
||||
- ../fonoteka.go/plugins/golem15/user/README.md
|
||||
|
||||
key-decisions:
|
||||
- "Task 4 package check answered \"approved\": go-oidc v3.21.0 and x/oauth2 v0.37.0 are test-only requirements of sm-oauthserver-plugin; only interop_test.go imports them; the framework go.mod is untouched"
|
||||
- "Lazy first signing key uses INSERT ... ON CONFLICT (active) WHERE active DO NOTHING and key reads/writes run with a silent GORM logger, so a losing insert never prints private-key ciphertext (T-19.4-15)"
|
||||
- "The plugin registers its own middleware factory oauthserver.body.limit:<bytes> before throttle:oauth-token, because surf ignores body.limit on GroupRaw routes"
|
||||
- "SanitizeCustomCSS repeats tag-opener removal until stable; the PHP single pass rebuilds </style from <<<//style (the PHP plugin keeps this weakness)"
|
||||
- "FKs follow PHP: ON DELETE CASCADE on subjects, consents, auth codes, refresh_tokens and mcp_codes; access_tokens has no FK (as PHP) and the cascade listener deletes those rows"
|
||||
- "Lang copy is verbatim from PHP (en, pl), overridable"
|
||||
|
||||
patterns-established:
|
||||
- "Shared OAuth plugin: tables keep PHP names so plan 03's import is a straight copy"
|
||||
- "sm-user-plugin changes for OAuth are additive exports and a new event only"
|
||||
|
||||
requirements-completed: [SC-2, SC-3, D-01, D-02, D-03, D-04, D-05, D-06, D-08, D-10, D-12, D-15, D-16, D-17, D-18, D-19]
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
description: "A signed-in user authorizes a relying party at the PHP paths on Postgres; the id_token verifies against the database key ring's JWKS; userinfo returns the same sub; the stored private key is ciphertext"
|
||||
requirement: D-01
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/oidc_flow_smoke_test.go#TestOIDCFlowSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D2
|
||||
description: "Eight instances racing the first key end with one active key and one kid"
|
||||
requirement: D-10
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/oidc_flow_smoke_test.go#TestKeyRingFirstKeyRaceSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Consent page branding from settings row 1, sanitised CSS, escaped client name, framing headers"
|
||||
requirement: D-03
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/pages_smoke_test.go#TestConsentPageBrandingSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "Consent and inactive-client error pages look like the PHP pages (structure, copy, branding, danger-coloured error heading)"
|
||||
requirement: D-03
|
||||
verification: []
|
||||
human_judgment: true
|
||||
rationale: "Visual side-by-side comparison with the PHP pages in a browser; no test asserts visual parity"
|
||||
- id: D5
|
||||
description: "Login handoff with only redirect=, switch account blacklists the JWT and forgets the cookie, redirect consent mode with the JSON endpoints"
|
||||
requirement: D-04
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/pages_smoke_test.go#TestLoginHandoffAndSwitchSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D6
|
||||
description: "PHP throttle bucket keys (userinfo key never contains the bearer); /oauth/{provider} routes neither shadow nor are shadowed"
|
||||
requirement: D-18
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/pages_smoke_test.go#TestBucketKeysSmoke"
|
||||
status: pass
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/pages_smoke_test.go#TestRouteGuardSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D7
|
||||
description: "Authorized apps list newest first and revoke; another user's or unknown client 404 not_found"
|
||||
requirement: SC-3
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/authorizations_smoke_test.go#TestAuthorizationsSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D8
|
||||
description: "user.Deleting removes all grant rows including subjects; user.Deactivating keeps subjects; other users untouched"
|
||||
requirement: D-05
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/authorizations_smoke_test.go#TestUserCascadeSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D9
|
||||
description: "MCP flow on the plugin's stores behind mcp.enabled; MCP clients refused by the OIDC flow; MCP paths 404 when disabled"
|
||||
requirement: D-06
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/mcp_store_smoke_test.go#TestMCPStoreSmoke"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D10
|
||||
description: "Stock relying party (go-oidc + x/oauth2) signs in against RS256 and ES256 rings: discovery, PKCE, nonce, id_token, at_hash, userinfo sub, silent second sign-in"
|
||||
requirement: SC-2
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "../sm-oauthserver-plugin/interop_test.go#TestRelyingPartyInterop (RS256, ES256)"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D11
|
||||
description: "sm-user-plugin changes additive; DeactivateUsers signature unchanged; its vet and short tests green"
|
||||
requirement: D-05
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "go -C ../fonoteka.go vet ./plugins/golem15/user/... && go -C ../fonoteka.go test -count=1 -short ./plugins/golem15/user/...; git diff c077029 -- classes/admin_actions.go | grep -c '^[-+]func DeactivateUsers' = 0"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
|
||||
duration: 50min
|
||||
completed: 2026-10-19
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Phase 19.4 Plan 02: sm-oauthserver-plugin Summary
|
||||
|
||||
**New shared plugin sm-oauthserver-plugin turns wristband's OIDC flavour into a working provider at the PHP paths: GORM stores for OIDC and MCP over the PHP tables, an encrypted database key ring (RS256 or ES256, race-safe first key), branded server-rendered consent and error pages with a redirect consent mode, PHP claims and throttles, the authorized-apps API and the user cascade, verified end to end on Postgres and by a stock go-oidc + x/oauth2 relying party.**
|
||||
|
||||
## Task 4: package legitimacy check (recorded before any go.mod change)
|
||||
|
||||
Recorded at 2026-10-19T17:21:39Z, before Task 5 touched `../sm-oauthserver-plugin/go.mod` (at that moment `grep -cE 'coreos/go-oidc|golang.org/x/oauth2' go.mod` printed 0). This section was written to disk first; `go get` ran afterwards.
|
||||
|
||||
Modules: `github.com/coreos/go-oidc/v3 v3.21.0` and `golang.org/x/oauth2 v0.37.0`, test-only requirements of `sm-oauthserver-plugin`.
|
||||
|
||||
Proxy facts the previous executor gathered (read-only `GOWORK=off go list -m -json`):
|
||||
- `github.com/coreos/go-oidc/v3 v3.21.0`, published 2026-09-01T23:03:42Z, origin https://github.com/coreos/go-oidc refs/tags/v3.21.0, hash c914bd380327a5a3a81403774d1a5d5b73772ce7 (pulls go-jose v4, x/oauth2 v0.36.0)
|
||||
- `golang.org/x/oauth2 v0.37.0`, published 2026-08-25T21:41:43Z, origin https://go.googlesource.com/oauth2 refs/tags/v0.37.0, hash c624b89dadc3221560b7345c090bbe69e90808ee
|
||||
|
||||
Human reply (verbatim): "approved"
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** about 50 min over two executor contexts (Tasks 1-3, then Task 5 after the checkpoint)
|
||||
- **Started:** about 2026-10-19T16:36Z (after the 19.4-01 state commit)
|
||||
- **Completed:** 2026-10-19T17:27Z
|
||||
- **Tasks:** 5 (4 executed, 1 human checkpoint)
|
||||
- **Files:** 47 tracked in the new plugin repository, 7 in sm-user-plugin
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- New repository `../sm-oauthserver-plugin` (`git init -b master`, origin `git@git.golem15.com:golem15/sm-oauthserver-plugin.git`, never pushed) with plugin `golem15.oauthserver` requiring `golem15.user`.
|
||||
- Tables `golem15_oauthserver_*` with PHP names, columns and `oas_*` index names, plus `_keys` (partial unique index `oas_keys_one_active ... WHERE active`, private PEM as `lagoon.Encrypted`), `_refresh_tokens`, `_settings`, `_mcp_codes`; raw SQL migrations only.
|
||||
- `classes.Store` implements `wristband.OIDCBackend`; `classes.MCPStore` implements `wristband.Backend`; clients filtered by kind in SQL; `LazyStore`/`LazyMCPStore` fail closed.
|
||||
- `classes.KeyRing`: active kid read per signing, signers cached per kid, JWKS with retired keys inside the grace window, `Rotate` and `Prune` ready for plan 03.
|
||||
- Branded consent and error pages (PHP layout, class names and copy, en and pl), redirect consent mode with `GET`/`POST /oauth/authorize/requests/{request}`.
|
||||
- Claims: name, picture (absolute), groups, communities (read-only userfriends SQL when the tables exist), email, email_verified.
|
||||
- PHP throttles `oauth-authorize`, `oauth-token`, `oauth-userinfo`, `oauth-authorizations` (and the two MCP buckets); discovery and JWKS unthrottled.
|
||||
- Authorized-apps list and revoke; cascade on `user.Deleting` and the new `user.Deactivating`.
|
||||
- MCP routes behind `mcp.enabled` (default false).
|
||||
- `TestRelyingPartyInterop`: go-oidc + x/oauth2 discover, authorize with PKCE and nonce, exchange with client_secret_basic, verify id_token and at_hash, read userinfo with the same sub, on RS256 and ES256 rings; the second sign-in is silent.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Commits per repository, in order (user plugin first, as the plan requires).
|
||||
|
||||
sm-user-plugin (`../fonoteka.go/plugins/golem15/user`, its own repository):
|
||||
1. **Task 1:** `b82d85f` feat: export RequestUser and EndRequestSession for OAuth providers
|
||||
2. **Task 2:** `ee47440` feat: export AvatarURL for the display picture at any size
|
||||
3. **Task 3:** `80b436d` feat: fire user.Deactivating from the admin deactivate action
|
||||
|
||||
sm-oauthserver-plugin (`../sm-oauthserver-plugin`):
|
||||
1. **Task 1 (tracer):** `459e389` feat: OpenID Connect provider plugin on wristband with a database key ring (root commit)
|
||||
2. **Task 2:** `b9cd399` feat: branded consent pages, redirect consent mode, full claims and PHP throttles
|
||||
3. **Task 3:** `a90ce4f` feat: authorized apps API, user cascade and MCP stores behind a switch
|
||||
4. **Task 4:** checkpoint, no commit (reply "approved")
|
||||
5. **Task 5:** `f1cc3b9` test: relying-party interop with go-oidc and x/oauth2 on RS256 and ES256 rings
|
||||
|
||||
summercms.go: read-only in this plan apart from this SUMMARY and the state updates (docs(19.4-02) commit).
|
||||
|
||||
## sm-user-plugin divergence
|
||||
|
||||
After `git fetch origin`, `master...origin/master` was `[ahead 3, behind 1]` at the start of the plan (origin has 24b16b1, not merged). It is now `[ahead 6, behind 1]`. Nothing was merged, rebased or pushed; reconciling belongs to the push step, which waits for the user.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `../sm-oauthserver-plugin/{plugin,servers,routes,buckets,middleware}.go`: plugin, config, servers wrapper, routes at the PHP paths, buckets, body-limit middleware factory
|
||||
- `../sm-oauthserver-plugin/classes/*.go`: stores, key ring, claims, host, branding, cascade, lazy stores
|
||||
- `../sm-oauthserver-plugin/controllers/*.go`: authorized apps, consent JSON
|
||||
- `../sm-oauthserver-plugin/models/*.go`, `updates/*.go`: models and raw SQL migrations
|
||||
- `../sm-oauthserver-plugin/views/*.html.tmpl`, `lang/{en,pl}/lang.yaml`, `config/config.yaml`: pages, copy, configuration
|
||||
- `../sm-oauthserver-plugin/*_test.go`: testmain, harness, ten Postgres smokes including the interop test
|
||||
- `../sm-oauthserver-plugin/README.md`, `go.mod`, `go.sum`, `go.work`, `.gitignore`
|
||||
- `../fonoteka.go/plugins/golem15/user/classes/{session_user,avatar,events}.go`, `controllers/{api_controller,registration,users_admin_controller}.go`, `README.md`: additive exports and the new event
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See `key-decisions` in the frontmatter.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 2 - Missing critical] Key material could reach the log (T-19.4-15)**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** GORM's error logger printed the losing first-key inserts, including the private-key ciphertext.
|
||||
- **Fix:** The lazy first key uses `INSERT ... ON CONFLICT (active) WHERE active DO NOTHING`; key reads and writes run with a silent logger.
|
||||
- **Verification:** TestKeyRingFirstKeyRaceSmoke green with no key material in the output.
|
||||
- **Committed in:** 459e389
|
||||
|
||||
**2. [Rule 3 - Blocking] surf ignores body.limit on GroupRaw routes**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** The planned `body.limit` on `POST /oauth/token` had no effect on a raw group.
|
||||
- **Fix:** The plugin registers its own middleware factory `oauthserver.body.limit:<bytes>` (`BodyLimitMiddleware`, `DefaultTokenBodyLimit`, new file `middleware.go`), placed before `throttle:oauth-token`; the MCP token route uses it too.
|
||||
- **Verification:** Task 2 acceptance grep (`throttle:oauth-token` line carries `body.limit`) and the smokes.
|
||||
- **Committed in:** b9cd399
|
||||
|
||||
**3. [Rule 1/2 - Bug, security] PHP custom-CSS sanitiser bypass**
|
||||
- **Found during:** Task 2
|
||||
- **Issue:** A single removal pass turns `<<<//style` into `</style`.
|
||||
- **Fix:** `SanitizeCustomCSS` repeats the removal until the value is stable; TestConsentPageBrandingSmoke covers that vector. The PHP plugin still has the weakness.
|
||||
- **Committed in:** b9cd399
|
||||
|
||||
**4. [Scope note] Cascade smoke does not go through the admin HTTP path**
|
||||
- **Found during:** Task 3
|
||||
- **Issue:** cabana has no exported way to put a transaction into the request context, so the plan's "through the bulk action path" could not be driven over HTTP.
|
||||
- **Fix:** TestUserCascadeSmoke runs `DeactivateUsers` then `FireDeactivatingEvent` in one transaction (what the bulk action does). Plan 04 can cover the admin path.
|
||||
- **Committed in:** a90ce4f
|
||||
|
||||
**5. [Plan detail] Foreign keys follow PHP**
|
||||
- ON DELETE CASCADE on subjects, consents and auth codes (as PHP) and on the new refresh_tokens and mcp_codes; access_tokens has no FK (as PHP), so the cascade listener deletes those rows.
|
||||
- **Committed in:** 459e389, a90ce4f
|
||||
|
||||
**6. [Names] Additive names beyond the plan's list**
|
||||
- classes: `HostOptions`, `ConsentModePage`/`ConsentModeRedirect`, `ClientLogoURL`, `Branding`/`DefaultBranding`/`BrandingCSS`, `AbsoluteURL`, `Community`, `DefaultPictureSize`, `DisplayName`, `MCPAccessTokenPrefix`, `KeyRing.Config`; `NewHost(app, views, opts)` takes a third argument; `Servers.KeyRing` field.
|
||||
- root package: `Config`, `LoadConfig`, `NewServers`, `BodyLimitMiddleware`, `DefaultTokenBodyLimit`.
|
||||
- models: `Strings`/`Uints` helpers, `ClientLogoField`, `SettingsLogoField`.
|
||||
- per-bucket key prefixes for the buckets the plan did not spell out (`oauth-authorize:`, `oauth-authorize-ip:`, `oauth-authorizations:`, `oauth-authorizations-ip:`, `oauth-mcp-*`).
|
||||
|
||||
**7. [Copy] Lang strings verbatim from PHP**
|
||||
- Including the "can't read your diary" line (en, pl); overridable through the lang files.
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 3 auto-fixed (1 missing critical, 1 blocking, 1 security bug) plus 4 recorded plan-detail notes (cascade test path, FKs, additive names, copy). **Impact:** no scope change; every name in the plan's Artifacts exists.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- **Docker-backed tests run:** all ten plugin Postgres smokes ran on real Docker (testcontainers, no sudo needed) and pass together in one run: TestOIDCFlowSmoke, TestKeyRingFirstKeyRaceSmoke, TestConsentPageBrandingSmoke, TestLoginHandoffAndSwitchSmoke, TestBucketKeysSmoke, TestRouteGuardSmoke, TestAuthorizationsSmoke, TestUserCascadeSmoke, TestMCPStoreSmoke, TestRelyingPartyInterop (RS256, ES256).
|
||||
- **NOT RUN:** the full fonoteka.go Docker suite (not part of this plan's verify; `go -C ../fonoteka.go vet` of the user plugin and its `-short` tests are green). The known unrelated fonoteka failure stays in `deferred-items.md`.
|
||||
- The fonoteka.go superproject pointer `plugins/golem15/user` shows as modified because of the new sm-user-plugin commits. It was left alone on purpose (another session also has fonoteka pointers modified); no app pointer was bumped.
|
||||
- The plugin builds only through its `go.work`, which points sm-user-plugin at the fonoteka checkout. Against the tagged sm-user-plugin v0.1.1 it would not build; a new sm-user-plugin tag must come before the plugin is consumed by tag.
|
||||
- **g15office:** not updated by the executors (tools not available); the orchestrator handles it.
|
||||
|
||||
## Human-check item for the end-of-phase UAT
|
||||
|
||||
From Task 2: with the plugin running in a local application (or the harness server kept alive), set a site name, a logo and an accent colour in row 1 of `golem15_oauthserver_settings`, open an authorize URL for a test client, and compare the consent page and the inactive-client error page side by side with the PHP pages in a browser: same structure and copy, branding applied from settings row 1, error heading in the fixed danger colour.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- Plan 03 can add the admin screens, the rotate and prune commands (on `KeyRing.Rotate`/`Prune`), the Winter import (straight copy into the PHP-named tables), tide parity and the security review.
|
||||
- Open for plan 03: `OPTIONS /oauth/authorizations` is not routed without `cors_profile` (PHP answered 204), an accepted parity deviation; the redirect `Cache-Control` and id_token header order notes from plan 01.
|
||||
- Nothing is pushed, tagged or deployed. sm-user-plugin is `[ahead 6, behind 1]` of origin and needs reconciling before the push.
|
||||
|
||||
---
|
||||
*Phase: 19.4-oidc-provider-on-wristband*
|
||||
*Completed: 2026-10-19*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
All key files exist; commits b82d85f, ee47440, 80b436d (sm-user-plugin) and 459e389, b9cd399, a90ce4f, f1cc3b9 (sm-oauthserver-plugin) exist. Key-link patterns found (`SetOIDCBackend` sits in `servers.go`, which Boot calls through `NewServers`; `RequestUser` in host.go, `DeactivatingEvent` in cascade.go, `throttle:oauth-token` in routes.go, `PublishedKeys`, `WithinOIDCTx`, `consent_token`). Task 5 verify passed (vet, short suite, three `--- PASS: TestRelyingPartyInterop` lines); full plugin Docker suite green (ten tests); sm-user-plugin vet and short tests green; framework go.mod has no go-oidc or x/oauth2.
|
||||
Reference in New Issue
Block a user