Files
summercms/.planning/phases/14.1-oauth-identities-and-fonoteka-me-routes/14.1-02-SUMMARY.md
2026-10-05 21:38:34 +02:00

10 KiB

phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, plugin_repo_head_after, app_repo_head_after, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects actuals plan_head_before plugin_repo_head_after app_repo_head_after tech-stack key-files key-decisions patterns-established requirements-completed coverage duration completed status
14.1-oauth-identities-and-fonoteka-me-routes 02 testing
oauth-identities
sm-user-plugin
me-token
parity
gormigrate
lagoon.Encrypted
winter-404
phrasebook
throttle
phase provides
14.1-oauth-identities-and-fonoteka-me-routes Host-mounted OAuthIdentitiesIndex/Destroy, migration 202610050001, D-09 MeToken collection_ids JSON null, three manifest routes ported, expectedPortedRoutes 175
phase provides
07-user-plugin-and-authentication sessionApp/insertUser, jwt.auth JSON 401, lang YAML, dedicatedDB
OAuthIdentityApiTest.php port: 204 sibling remains, last-method 409 EN/PL, Winter HTML 404 byte-identical for missing/foreign/unknown, 401 on GET and DELETE /google
gormigrate up/down for golem15_user_oauth_identities (jsonb profile_data, both unique indexes, CASCADE FK)
MeToken nil CollectionIDs serializes as JSON null; scopes stay []
Encrypted token/profile_data secret-leak assertions on GET list
TestParityCorpus recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0
15-cutover (zero pending routes)
verify-work 14.1
tokens tasks commits
4200 3 3
0d1b5caf3d f0d3b8b21d3d11bcf5cbf288f715bc1ec94f9ebe fbe346950ae2715939c2bac209a51ca43fa75883
added patterns
409 locale tests call phrasebook.Activate because sessionApp Boots the plugin without activating catalogs
oauth_identities_provider_identity_unique is global (provider, provider_id), not per-user — locale cases must use distinct provider_ids
Secret-leak Index assertions refuse plaintext, Encrypted JSON keys, and the [redacted] marshal literal
created modified
../fonoteka.go/plugins/golem15/user/updates/oauth_identities_test.go
../fonoteka.go/plugins/golem15/user/oauth_identities_test.go
../fonoteka.go/plugins/golem15/fonoteka/controllers/api/me_token_controller_test.go
sessionApp does not phrasebook.Activate; EN/PL 409 tests activate catalogs and set locale with towel.WithLocale
Unique (provider, provider_id) is table-global; EN/PL 409 seeds use provider_id fb-only-<locale>
Task 3 needed no parity_test.go change: 14.1-01 already set expectedPortedRoutes 175 and rewrote assertPortedMismatch
Destroy tests inject WriteNotFound that copies Winter HTML 404 bytes so missing, foreign, and unknown providers stay indistinguishable
DATA-07 list tests seed lagoon.NewEncrypted after PublishEncryptionKeys and assert the Index body never names token columns
API-09
QA-05
HTTP-01
HTTP-03
DATA-02
DATA-07
I18N-01
id description requirement verification human_judgment
D1 Unlink 204 keeps the sibling row; last remaining identity returns 409 EN and PL last_method_blocked texts, including when the account has a password I18N-01
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesDestroyNoContentKeepsSibling pass
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesDestroyLastMethodBlockedENAndPL pass
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesDestroyLastMethodBlockedWithPassword pass
false
id description requirement verification human_judgment
D2 Missing, foreign, and unknown-provider DELETE return byte-identical Winter HTML 404; unauthenticated GET and DELETE /google return 401 HTTP-01
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesDestroyWinter404BodiesAreByteIdentical pass
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesUnauthorizedOnGoogle pass
false
id description requirement verification human_judgment
D3 Identity routes exist on the JWT group only; DELETE middleware includes throttle:10,1; token group never lists oauth-identities HTTP-03
kind ref status
unit plugins/golem15/fonoteka#TestOAuthTokenSurfaceIsolationCoverage/test_oauth_identity_routes_exist_on_jwt_surface_only pass
false
id description requirement verification human_judgment
D4 oauth-identities migration migrates up and rolls back: table, jsonb profile_data, both unique indexes, cascade FK present after up and absent after down DATA-02
kind ref status
unit plugins/golem15/user/updates#TestOAuthIdentitiesMigration pass
false
id description requirement verification human_judgment
D5 GET list with seeded Encrypted tokens never contains plaintext, access_token/refresh_token/profile_data keys, or [redacted] DATA-07
kind ref status
unit plugins/golem15/user#TestOAuthIdentitiesIndexDoesNotLeakEncryptedTokensOrProfileData pass
false
id description requirement verification human_judgment
D6 Unrestricted /me emits collection_ids as JSON null and scopes as []; TestParityCorpus is recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0 API-09
kind ref status
unit plugins/golem15/fonoteka/controllers/api#TestMeTokenHandlerNilScopesSerializeAsEmptyArrayAndCollectionIDsAsJSONNull pass
kind ref status
e2e parity#TestParityCorpus recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0 pass
false
id description requirement verification human_judgment rationale
D7 QA-05 consumers stay frozen: Nuxt Settings → Connected accounts list/unlink and fonoteka-mcp me() against Go QA-05
true Plan human-check is a live Nuxt and MCP session against the Go backend; the corpus and unit tests cannot sign that consumers are unchanged
8min 2026-10-05 complete

Phase 14.1 Plan 02: OAuth identities unit tests Summary

OAuthIdentityApiTest.php ported (204, EN/PL 409, Winter 404s, 401 /google), migration up/down, /me collection_ids JSON null, Encrypted secret-leak, corpus 175/175/0

Performance

  • Duration: 8 min
  • Started: 2026-10-05T19:28:51Z
  • Completed: 2026-10-05T19:37:04Z
  • Tasks: 3
  • Files modified: 3

Accomplishments

  • Plugin tests prove unlink 204 keeps the sibling row, last-method 409 EN and PL match golem15.user::lang.oauth.last_method_blocked (including when the account has a password), missing/foreign/unknown Winter HTML 404 bodies are byte-identical, and both identity routes return 401 without a JWT on /google.
  • updates/oauth_identities_test.go migrates golem15_user_oauth_identities up and down on real Postgres: jsonb profile_data, both unique indexes, CASCADE FK.
  • Rewritten MeToken nil test requires "collection_ids":null and treats "scopes":null as failure.
  • GET list with lagoon.NewEncrypted tokens never leaks plaintext, Encrypted JSON keys, or [redacted].
  • TestParityCorpus prints recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0.

Task Commits

Each task was committed atomically:

  1. Task 1: Port OAuthIdentityApiTest.php — 204, EN/PL 409, Winter 404s, 401 /google, jwt-only surfaces — 026848f (sm-user-plugin test). phase08 jwt-only + throttle:10,1 already shipped in 14.1-01; no fonoteka.go commit.
  2. Task 2: Migration up/down, MeToken null collection_ids, secret-leak — f0d3b8b (sm-user-plugin test), fbe3469 (fonoteka.go test + gitlink)
  3. Task 3: TestParityCorpus 175/175/0 — no code commit (expectedPortedRoutes = 175 and rewritten assertPortedMismatch already on disk from 14.1-01)

Plan metadata: this SUMMARY commit

Note: TDD was not applicable for this plan.

Files Created/Modified

  • plugins/golem15/user/oauth_identities_test.go — D-11 matrix plus DATA-07 secret-leak
  • plugins/golem15/user/updates/oauth_identities_test.go — dedicatedDB gormigrate up/down
  • plugins/golem15/fonoteka/controllers/api/me_token_controller_test.go — D-09 "collection_ids":null

Decisions Made

  • phrasebook.Activate in 409 tests: sessionApp Boots the plugin only; catalogs must be activated for EN/PL last_method_blocked lookup.
  • Global unique (provider, provider_id): locale cases seed fb-only-<locale> so they do not collide on oauth_identities_provider_identity_unique.
  • Task 3 verification-only: corpus constants and mismatch helper were already 175/ported after 14.1-01.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking] EN/PL 409 seed collided on provider_identity unique

  • Found during: Task 1 (EN/PL 409)
  • Issue: Both locales used provider_id fb-only; the second insert failed oauth_identities_provider_identity_unique.
  • Fix: Seed fb-only- plus locale. Unique is global, not per-user.
  • Files modified: ../fonoteka.go/plugins/golem15/user/oauth_identities_test.go
  • Verification: TestOAuthIdentitiesDestroyLastMethodBlockedENAndPL PASS
  • Committed in: 026848f (Task 1)

2. [Rule 2 - Missing Critical] 409 tests must activate phrasebook

  • Found during: Task 1 (EN/PL 409)
  • Issue: sessionApp does not call phrasebook.Activate; Get returned the raw key.
  • Fix: phrasebook.Activate(app, []*Plugin{{}}) plus towel.WithLocale.
  • Files modified: ../fonoteka.go/plugins/golem15/user/oauth_identities_test.go
  • Verification: EN and PL bodies equal the lang YAML strings
  • Committed in: 026848f (Task 1)

Total deviations: 2 auto-fixed (1 blocking, 1 missing critical) Impact on plan: Both needed so 409 tests fail when lang YAML or locale wiring break. No scope creep.

Issues Encountered

  • First EN/PL 409 run failed on the unique index (deviation 1). GORM "record not found" logs on Winter 404 branches are expected First() misses.
  • Task 3 ran go vet then TestParityCorpus; verbose coverage line recorded 175/175 passing 175 failing 0 unrecorded 0 pending 0. No fixture re-record.

User Setup Required

None - no external service configuration required.

Next Phase Readiness

  • Phase 14.1 plans are both summarized; ready for /gsd-verify-work 14.1. Human-check D7 (Nuxt Connected accounts, fonoteka-mcp me()) remains for that step.
  • Do not push sm-user-plugin or fonoteka.go. Plugin HEAD f0d3b8b and app HEAD fbe3469 are local-only.
  • scripts/check-phase14.sh EXPECTED_PENDING=3 stays historical.

Phase: 14.1-oauth-identities-and-fonoteka-me-routes Completed: 2026-10-05