diff --git a/.planning/notes/2026-10-22-external-user-plugin-escalations.md b/.planning/notes/2026-10-22-external-user-plugin-escalations.md index 9eddbbb3..2fd3beec 100644 --- a/.planning/notes/2026-10-22-external-user-plugin-escalations.md +++ b/.planning/notes/2026-10-22-external-user-plugin-escalations.md @@ -9,7 +9,9 @@ g15office: bhoyg8z4 Reviewed 2026-10-22. The list is `golem15.user` (sm-user-plugin), not cabana admin auth. Phase 19.6 (2FA) is not mid-flight. -**How to use this file.** Each quick fills its row in the tracker and the matching paragraph under [Reply to send](#reply-to-send). When all six are done, send that section as-is. Do not send until then. +**Release hold (2026-10-22):** nothing is pushed or tagged until the **SummerCMS v0.5.0** wave is finished. That wave is these six user-plugin quicks, admin keyboard shortcuts (`261022-k9k`), and the MCP feature (phase 19.7). Plugin commits stay local; the plugin tag and app pointer bumps go out with v0.5.0, not as a v0.1.9-shaped mid-wave release. Changelog post the same day as the framework tag. + +**How to use this file.** Each quick fills its row in the tracker and the matching paragraph under [Reply to send](#reply-to-send). When all six are done **and** v0.5.0 is tagged, send that section as-is. Do not send, push or tag before then. **Do not run the six quicks in parallel on one working tree.** They share `sm-user-plugin` (`api_controller.go`, `plugin.go`, `routes.go`, README). Sequential fresh sessions. @@ -17,7 +19,7 @@ Reviewed 2026-10-22. The list is `golem15.user` (sm-user-plugin), not cabana adm | # | Their label | Verdict | Quick / todo | g15office | Status | Shipped | |---|---|---|---|---|---|---| -| 1 | G2 login ignores `is_activated` | Fix | [261022-tb4](../quick/261022-tb4-password-login-must-refuse-is-activated-/) · [todo](../todos/pending/2026-10-22-user-login-ignores-is-activated.md) | 3r4or1ex | done (unreleased) | `15ff979` (next tag v0.1.9) | +| 1 | G2 login ignores `is_activated` | Fix | [261022-tb4](../quick/261022-tb4-password-login-must-refuse-is-activated-/) · [todo](../todos/pending/2026-10-22-user-login-ignores-is-activated.md) | 3r4or1ex | done (unreleased) | `15ff979` → v0.5.0 | | 2 | G3 cookie-only 401 | Fix remaining four; logout already done | [2026-10-22-user-session-routes-ignore-cookie.md](../todos/pending/2026-10-22-user-session-routes-ignore-cookie.md) | kkknstxl | open | | | 3 | G4 logout blacklist under `serve` | Fix | [2026-10-22-user-logout-blacklist-missing-under-serve.md](../todos/pending/2026-10-22-user-logout-blacklist-missing-under-serve.md) | ud0gficu | open | | | 4 | G6 `/update` email without proof | Decline | — | — | declined | n/a | @@ -28,7 +30,7 @@ Reviewed 2026-10-22. The list is `golem15.user` (sm-user-plugin), not cabana adm | 9 | Lockout keyed on `RemoteAddr` | Fix | with 10: [2026-10-22-user-login-lockout-and-same-second-cutoff.md](../todos/pending/2026-10-22-user-login-lockout-and-same-second-cutoff.md) | sniewiif | open | | | 10 | Same-second token refusal | Fix | with 9, same todo | sniewiif | open | | -Status values: `open` · `done` · `declined`. Shipped: plugin version (and framework tag if needed). +Status values: `open` · `done` · `declined`. Shipped: local commit now; replace with the v0.5.0 plugin/framework tags at release. Do not write a mid-wave plugin tag. ## Six invocations (fresh session each, sequential) @@ -70,15 +72,15 @@ Thanks for the escalation list. We reviewed the current golem15.user plugin (and G2 — login ignores is_activated Agreed. require_activation defaults to true and /register already withholds a token in admin mode; /login did not check is_activated. That is not the same as deactivation (deleted_at), which stays self-service: a later password login still restores the account. -Shipped as sm-user-plugin 15ff979 (unreleased; next tag v0.1.9 unless this batch is tagged together): with require_activation on (the default), /login answers an account that is not activated with the same opaque invalid-login response as a bad password (counted as a failed attempt); deactivation stays self-service. /activate still serves a not-activated session so the mailed-code flow works. +Ships in SummerCMS v0.5.0 (sm-user-plugin 15ff979, tagged with that wave): with require_activation on (the default), /login answers an account that is not activated with the same opaque invalid-login response as a bad password (counted as a failed attempt); deactivation stays self-service. /activate still serves a not-activated session so the mailed-code flow works. G3 — some routes ignore the cookie Partly already fixed, rest agreed. POST /logout already accepts the token/auth_token cookies (and blacklists every JWT the request carries). GET /fetch, POST /refresh, POST /update and POST /change-password still required the Authorization header. -TODO: shipped in sm-user-plugin vX.Y.Z — those four accept the same cookies as jwt.auth. +TODO: ships in SummerCMS v0.5.0 — those four accept the same cookies as jwt.auth. G4 — logout does not blacklist under serve Agreed. Plugin Boot runs before serve publishes the database, so the in-process blacklist store was never wired in production (the jwt_blacklist table exists; nothing wrote to it). Tests hid this because they publish the DB before Boot. -TODO: shipped in sm-user-plugin vX.Y.Z — logout under serve blacklists the jti; the next jwt.auth request with that token is 401. +TODO: ships in SummerCMS v0.5.0 — logout under serve blacklists the jti; the next jwt.auth request with that token is 401. G6 — /update changes email without proof As designed, not a bug. A new address clears email_verified_at and stays unproven until the owner completes an activation code or a reset-password. We are not adding a “confirm the new inbox before the change sticks” flow in this round. Say if you need that as a later feature. @@ -91,17 +93,17 @@ As designed. Personal API tokens are revoked through revoked_at, not the JWT cut Cookie on /login Agreed as an opt-in. Sociallogin already has token_cookie for OAuth complete; password /login will grow the same kind of flag (default off, so body-token clients stay unchanged). -TODO: shipped in sm-user-plugin vX.Y.Z — config key , HttpOnly cookie via bouncer.LoadCookieConfig. +TODO: ships in SummerCMS v0.5.0 — config key , HttpOnly cookie via bouncer.LoadCookieConfig. Password-routes switch Agreed, in the user plugin, not as a framework “wrap another plugin’s routes” seam. A config key will stop registering /login, /forgot-password and /reset-password so they 404. -TODO: shipped in sm-user-plugin vX.Y.Z — config key . +TODO: ships in SummerCMS v0.5.0 — config key . Login lockout keyed on RemoteAddr Agreed. /login used RemoteAddr; /register already uses the trusted-proxy client address. Behind a reverse proxy five failures locked everyone. -TODO: shipped in sm-user-plugin vX.Y.Z — /login throttle uses surf.ClientIP. +TODO: ships in SummerCMS v0.5.0 — /login throttle uses surf.ClientIP. Same-second token refusal Agreed. JWT iat is whole seconds; some tokens_valid_after writers stamped sub-second time. RevokeUserAccess already truncates. Reset-password and the admin password set will too. -TODO: shipped in sm-user-plugin vX.Y.Z — a token minted in the same second as a reset is accepted. +TODO: ships in SummerCMS v0.5.0 — a token minted in the same second as a reset is accepted. ``` diff --git a/.planning/todos/pending/2026-10-22-user-login-ignores-is-activated.md b/.planning/todos/pending/2026-10-22-user-login-ignores-is-activated.md index 2f8cdad0..bf6d69d3 100644 --- a/.planning/todos/pending/2026-10-22-user-login-ignores-is-activated.md +++ b/.planning/todos/pending/2026-10-22-user-login-ignores-is-activated.md @@ -30,7 +30,7 @@ After the commit, fill G2 in `.planning/notes/2026-10-22-external-user-plugin-es ## Outcome (2026-10-22) -Quick `261022-tb4`. Fix commit `15ff979` on sm-user-plugin master (base v0.1.8 / `930b158`). Gate runs after bcrypt and before the `deleted_at` restore; the refusal is the same opaque 401 and counts as a failed attempt. Reply note G2 filled. Not tagged, not pushed; Task 3 (release / bump) still waits. +Quick `261022-tb4`. Fix commit `15ff979` on sm-user-plugin master (base v0.1.8 / `930b158`). Gate runs after bcrypt and before the `deleted_at` restore; the refusal is the same opaque 401 and counts as a failed attempt. Reply note G2 filled. Not tagged, not pushed: the v0.5.0 wave (these six quicks + admin keyboard shortcuts + MCP) is the first release. ## Invoke