docs(19.6-03): release and adoption up to the sm-demo-app checkpoint
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
phase: 19.6-two-factor-auth-and-device-flow-in-sm-user-plugin
|
||||
plan: 03
|
||||
subsystem: auth
|
||||
tags: [sm-mfa-plugin, webauthn, go-webauthn, passkeys, passwordless, sm-sociallogin-plugin, login-gate, vue-demo-app, totp-ui, draft]
|
||||
tags: [sm-mfa-plugin, webauthn, go-webauthn, passkeys, passwordless, sm-sociallogin-plugin, login-gate, vue-demo-app, totp-ui, release, draft]
|
||||
|
||||
requires:
|
||||
- phase: 19.6-01
|
||||
@@ -13,33 +13,45 @@ provides:
|
||||
- WebAuthn security keys as a second factor in sm-mfa-plugin (go-webauthn v0.18.2, standard base64url shapes, D-08)
|
||||
- golem15_user_webauthn_credentials (migration 202610220006) with credential_data and passwordless
|
||||
- Passwordless passkey sign-in behind two_factor_passwordless_login (D-14)
|
||||
- D-09 social-login gate in sm-sociallogin-plugin, prepared as commit a0161d7 in a scratch clone (not yet in the real checkout, see Blockers)
|
||||
- Demo two-factor UI in vue-demo-app (TOTP setup, recovery codes, disable, login challenge; D-20)
|
||||
- D-09 social-login gate in sm-sociallogin-plugin v0.1.4
|
||||
- Demo two-factor UI in vue-demo-app (TOTP setup, recovery codes, disable, login challenge; D-20), pushed
|
||||
- Releases: sm-user-plugin v0.1.12, sm-mfa-plugin v0.1.0 (new private repository), sm-sociallogin-plugin v0.1.4
|
||||
- sm-bm-app mounts golem15.mfa (API only) at user v0.1.12 and sociallogin v0.1.4, pushed
|
||||
- fonoteka.go at sm-user-plugin v0.1.12 with its guard tests updated (local commit)
|
||||
affects: [19.6-04, sm-demo-app, sm-bm-app, fonoteka.go, vue-demo-app, sm-sociallogin-plugin]
|
||||
|
||||
actuals:
|
||||
tokens: 35354 # chars/4 over the added lines of this plan's diffs in the three repositories (go.sum and go.work.sum excluded)
|
||||
tasks: 3 # Tasks 1-3 of 6; Task 4 is the open checkpoint
|
||||
commits: 0 # MEASURED in summercms.go before this draft's commit: git rev-list --count 5d78f53..HEAD (code lives in other repositories)
|
||||
sm_mfa_plugin_commits: 2 # MEASURED: git -C ../sm-mfa-plugin rev-list --count 8a63f6f..HEAD
|
||||
vue_demo_app_commits: 1 # MEASURED: git -C ../sm-demo-app/vue-demo-app rev-list --count 9c247ab..HEAD
|
||||
sm_sociallogin_plugin_commits: 0 # the real checkout is unchanged; 1 commit (a0161d7) in the scratch clone
|
||||
tokens: 37360 # MEASURED chars/4 over added lines: Tasks 1-3 35354, plus 33ad164, b752177, sm-bm-app aafbcce..ebb2266, fonoteka.go 06bc9d0..95fd58a (go.sum and go.work.sum excluded)
|
||||
tasks: 5 # Tasks 1-5 done; Task 6 parts (2) and (3) done, part (1) sm-demo-app open at a checkpoint
|
||||
commits: 0 # MEASURED in summercms.go before this draft's commit: git rev-list --count 5a64611..HEAD (code lives in other repositories)
|
||||
sm_mfa_plugin_commits: 3 # MEASURED: git -C ../sm-mfa-plugin rev-list --count 8a63f6f..HEAD
|
||||
sm_sociallogin_plugin_commits: 2 # MEASURED: git -C ../sm-sociallogin-plugin rev-list --count 4d3b2dd..HEAD
|
||||
vue_demo_app_commits: 1 # MEASURED: git -C ../sm-demo-app/vue-demo-app rev-list --count 9c247ab..HEAD
|
||||
sm_bm_app_commits: 3 # MEASURED: git -C ../sm-bm-app rev-list --count aafbcce..HEAD
|
||||
fonoteka_go_commits: 1 # MEASURED: git -C ../fonoteka.go rev-list --count 06bc9d0..HEAD
|
||||
sm_demo_app_commits: 0 # Task 6 part (1) not started (checkpoint)
|
||||
plan_head_before: 5d78f53ddc890ef53fe52da1828f3f88d9923270
|
||||
plan_head_after: 5d78f53ddc890ef53fe52da1828f3f88d9923270
|
||||
plan_head_after: 5a64611
|
||||
sm_mfa_plugin_head_before: 8a63f6f
|
||||
sm_mfa_plugin_head_after: 6c8916f
|
||||
sm_mfa_plugin_head_after: 33ad164
|
||||
sm_sociallogin_plugin_head_before: 4d3b2dd
|
||||
sm_sociallogin_plugin_head_after: b752177
|
||||
vue_demo_app_head_before: 9c247ab
|
||||
vue_demo_app_head_after: 44a5229
|
||||
sm_sociallogin_plugin_head: 4d3b2dd # unchanged (v0.1.3 = origin/master); patch prepared on top of it
|
||||
sm_user_plugin_head: 3b22134 # unchanged, untagged, 5 commits ahead of origin (v0.1.11 = 50da92c)
|
||||
sm_bm_app_head_before: aafbcce
|
||||
sm_bm_app_head_after: ebb2266
|
||||
fonoteka_go_head_before: 06bc9d0
|
||||
fonoteka_go_head_after: 95fd58a
|
||||
sm_user_plugin_head: 3b22134 # tagged v0.1.12 and pushed
|
||||
|
||||
tech-stack:
|
||||
added:
|
||||
- "github.com/go-webauthn/webauthn v0.18.2 (packages webauthn, protocol), sm-mfa-plugin only (approved 2026-10-26); brings fxamacker/cbor/v2, go-webauthn/x, google/go-tpm, tinylib/msgp as indirect modules"
|
||||
- "github.com/go-webauthn/webauthn v0.18.2 (packages webauthn, protocol), sm-mfa-plugin only (approved 2026-10-26); brings fxamacker/cbor/v2, go-webauthn/x, google/go-tpm, tinylib/msgp as indirect modules (also indirect in sm-bm-app through the mount)"
|
||||
patterns:
|
||||
- "WebAuthn ceremony state server-side: registration and passkey state in cooler consumed with Pull; login state on the challenge row"
|
||||
- "Pure verification helpers (VerifyRegistration, VerifyAssertion) shared by handlers and a no-database smoke test"
|
||||
- "Virtual authenticator test helper (ECDSA P-256, attestation none, CBOR through go-webauthn's webauthncbor)"
|
||||
- "Application mount test without a database: route table entry with the owning plugin, a compiled handler, and an anonymous request refused by jwt.auth (sm-bm-app TestMFAMounted)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
@@ -53,18 +65,23 @@ key-files:
|
||||
- ../sm-mfa-plugin/webauthn_smoke_test.go
|
||||
- ../sm-mfa-plugin/passwordless_smoke_test.go
|
||||
- ../sm-mfa-plugin/go.work.sum
|
||||
- ../sm-sociallogin-plugin/social_gate_smoke_test.go
|
||||
- ../sm-demo-app/vue-demo-app/app/lib/twoFactor.ts
|
||||
- ../sm-demo-app/vue-demo-app/app/lib/twoFactor.test.ts
|
||||
- ../sm-demo-app/vue-demo-app/app/composables/useTwoFactor.ts
|
||||
- ../sm-demo-app/vue-demo-app/app/pages/account/security.vue
|
||||
- ../sm-bm-app/mfa_test.go
|
||||
- ../sm-bm-app/plugins/golem15/mfa (submodule)
|
||||
- .planning/phases/19.6-two-factor-auth-and-device-flow-in-sm-user-plugin/19.6-03-sociallogin-gate.patch
|
||||
- .planning/phases/19.6-two-factor-auth-and-device-flow-in-sm-user-plugin/deferred-items.md
|
||||
modified:
|
||||
- ../sm-mfa-plugin/{go.mod,go.sum,routes.go,plugin.go,README.md,config/config.yaml,lang/en/lang.yaml,lang/pl/lang.yaml}
|
||||
- ../sm-mfa-plugin/classes/{config.go,methods.go,admin.go,events.go,login.go}
|
||||
- ../sm-sociallogin-plugin/{classes/flow.go,classes/codes.go,controllers/callback.go,controllers/complete.go,controllers/register_complete.go,lang/en/lang.yaml,lang/pl/lang.yaml,README.md,go.mod,go.sum}
|
||||
- ../sm-demo-app/vue-demo-app/app/{composables/useDemoAuth.ts,pages/login.vue,components/SiteHeader.vue}
|
||||
- ../sm-demo-app/vue-demo-app/i18n/locales/{en.json,pl.json}
|
||||
- "(patch only) ../sm-sociallogin-plugin/{classes/flow.go,classes/codes.go,controllers/callback.go,controllers/complete.go,controllers/register_complete.go,lang/en/lang.yaml,lang/pl/lang.yaml,README.md}, new social_gate_smoke_test.go"
|
||||
- ../sm-bm-app/{.gitmodules,go.mod,go.sum,go.work,summer.yaml,plugins.gen.go,scripts/build.sh,README.md,plugins/golem15/user,plugins/golem15/sociallogin}
|
||||
- ../fonoteka.go/{plugins/golem15/user,parity/migrate_test.go,parity/schema_diff_test.go,plugins/golem15/fonoteka/classes/hidden_marshal_test.go,plugins/golem15/fonoteka/phase07_coverage_test.go,plugins/golem15/fonoteka/routes_isolation_test.go}
|
||||
|
||||
key-decisions:
|
||||
- "WebAuthn RP from golem15.mfa.webauthn.rp_id / rp_name / origins (defaults: app.url host, app.name, app.url and golem15.user.frontend_url origins); an IP host or no origin makes WebAuthnFor answer ErrWebAuthnUnavailable, and the routes answer 403 'WebAuthn is not available.'"
|
||||
@@ -73,12 +90,14 @@ key-decisions:
|
||||
- "Passkey routes also answer 403 while two_factor_mode is disabled (fail closed), not only while two_factor_passwordless_login is off"
|
||||
- "Passkey sign-in refuses a ban or suspension from any address (ThrottleStates) and from the request's address (RejectIfThrottled)"
|
||||
- "A challenged social sign-in does not fire SignedInEvent and does not restore a deactivated account; the identity is stored before the gate"
|
||||
- "No framework tag needed: sm-mfa-plugin (with the user plugin at 3b22134) and the sociallogin change pass their full suites against the framework's v0.5.0 tag"
|
||||
- "No framework tag: sm-mfa-plugin and sm-sociallogin-plugin pass against the framework's v0.5.0 tag; sociallogin's require rose from v0.3.1 to v0.5.0 through go mod tidy"
|
||||
- "Release tags: sm-user-plugin v0.1.12, sm-mfa-plugin v0.1.0, sm-sociallogin-plugin v0.1.4 (the plan's v0.1.6 and v0.1.3 were stale)"
|
||||
- "fonoteka.go guard tests follow the user plugin across every version the bump crosses (v0.1.10 to v0.1.12), not only this phase's additions, because they were already red at the committed v0.1.10 pointer"
|
||||
|
||||
patterns-established:
|
||||
- "Plugin work in a checkout the executor cannot write: implement and test in a scratch clone with a GOWORK file, export git format-patch, keep the patch in the phase directory"
|
||||
- "Plugin work in a checkout the executor cannot write: implement and test in a scratch clone with a GOWORK file, export git format-patch, keep the patch in the phase directory, apply with git am once access is granted and verify the tree hash matches"
|
||||
|
||||
requirements-completed: [] # draft; the plan's requirements are copied when the plan completes after Task 6
|
||||
requirements-completed: [] # draft; the plan's requirements are copied when the plan completes after Task 6 part (1)
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
@@ -101,14 +120,13 @@ coverage:
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Social sign-in through the login gate (prepared, not yet in the real sm-sociallogin-plugin checkout)"
|
||||
description: "Social sign-in through the login gate (sm-sociallogin-plugin a8e3e78, released as v0.1.4)"
|
||||
requirement: "D-09"
|
||||
verification:
|
||||
- kind: integration
|
||||
ref: "scratch clone a0161d7: social_gate_smoke_test.go#TestSocialGateSmoke (5 subtests) and TestTracerSmoke"
|
||||
ref: "../sm-sociallogin-plugin/social_gate_smoke_test.go#TestSocialGateSmoke (5 subtests) and TestTracerSmoke, in the real checkout"
|
||||
status: pass
|
||||
human_judgment: true
|
||||
rationale: "The change is not committed in ../sm-sociallogin-plugin yet (owned by jin); it must be applied and the tests re-run there."
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "Demo two-factor UI: TOTP setup with the QR image, recovery codes shown once, turn off, login challenge with TOTP or recovery code"
|
||||
requirement: "D-20"
|
||||
@@ -120,76 +138,166 @@ coverage:
|
||||
ref: "pnpm build; server render of /account/security and /login on the built output (200)"
|
||||
status: pass
|
||||
human_judgment: true
|
||||
rationale: "Look and flow in a browser against a running demo with golem15.mfa mounted (Task 6) are a visual judgement; WebAuthn is not part of the demo UI."
|
||||
rationale: "Look and flow in a browser against a running demo with golem15.mfa mounted are a visual judgement; the demo mount (Task 6 part 1) is open at the checkpoint."
|
||||
- id: D5
|
||||
description: "D-17 adoption: plugins published in order; bm mounts mfa; fonoteka.go green at the new pointer without mfa; demo mount pending"
|
||||
requirement: "D-17"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "ls-remote of v0.1.12, v0.1.0, v0.1.4 and the pushed branches; sm-bm-app TestMFAMounted; fonoteka.go vet, -short suites and build"
|
||||
status: pass
|
||||
human_judgment: true
|
||||
rationale: "sm-demo-app part is waiting on the user's decision about another session's uncommitted user pointer."
|
||||
|
||||
duration: 40min
|
||||
duration: 75min
|
||||
completed: 2026-10-26
|
||||
status: draft
|
||||
---
|
||||
|
||||
# Phase 19.6 Plan 03: WebAuthn and adoption Summary (draft)
|
||||
|
||||
**Status:** draft (checkpoint Task 4). Tasks 1-3 are done. Task 4 waits for the user's release decision. Tasks 5 and 6 run in a continuation.
|
||||
**Status:** draft at a second checkpoint, during Task 6 part (1).
|
||||
- **Done:**
|
||||
- Tasks 1-5.
|
||||
- Task 6 part (2), sm-bm-app: committed and pushed.
|
||||
- Task 6 part (3), fonoteka.go: committed locally, not pushed.
|
||||
- **Not started:** Task 6 part (1), sm-demo-app. Another session's uncommitted edit moved its `plugins/golem15/user` pointer to v0.1.11, and the plan says to stop when another session's edits touch a Task 6 file. See "Open checkpoint".
|
||||
|
||||
**Results so far:**
|
||||
- **sm-mfa-plugin:** WebAuthn security keys as a second factor, using go-webauthn v0.18.2 with server-side ceremony state, and passwordless passkey sign-in behind its setting. Two local commits.
|
||||
- **sm-sociallogin-plugin:** the social-login gate (D-09) is written and tested in a scratch clone. It is not in the real checkout yet, because that checkout belongs to the user `jin`.
|
||||
- **vue-demo-app:** the demo's TOTP setup, recovery-code and login-challenge screens. One local commit.
|
||||
- **Remote:** nothing was pushed, tagged or created.
|
||||
**Results:**
|
||||
- **sm-mfa-plugin v0.1.0:** WebAuthn security keys as a second factor (go-webauthn v0.18.2, ceremony state server-side) and passwordless passkey sign-in behind its setting. The new private repository is https://git.golem15.com/golem15/sm-mfa-plugin.
|
||||
- **sm-sociallogin-plugin v0.1.4:** social sign-in goes through the login gate (D-09).
|
||||
- **sm-user-plugin v0.1.12:** plan 01's login gates and device authorization, published.
|
||||
- **vue-demo-app:** the TOTP setup, recovery-code and login-challenge screens are pushed.
|
||||
- **sm-bm-app:** mounts golem15.mfa (API only), with user v0.1.12 and sociallogin v0.1.4. Pushed.
|
||||
- **fonoteka.go:** at user v0.1.12, guard tests updated. Local commit only.
|
||||
|
||||
## Performance
|
||||
|
||||
- **Started:** about 2026-10-26T11:08Z
|
||||
- **Checkpoint:** 2026-10-26T11:48Z (about 40 min)
|
||||
- **Tasks:** 3 of 6 (Task 4 is the open checkpoint)
|
||||
- **Files:**
|
||||
- sm-mfa-plugin: 23 files, +2358/-37
|
||||
- vue-demo-app: 9 files, +549/-13
|
||||
- sociallogin patch: 9 files, +266/-16
|
||||
- **First checkpoint:** 2026-10-26T11:48Z
|
||||
- **Continuation:** about 11:55Z to 12:25Z
|
||||
- **Tasks:** 5 of 6, with Task 6 partly done.
|
||||
|
||||
## Task 4 reply
|
||||
|
||||
Verbatim: "1. release 2. push demo 3. you can sudo chown golem:golem sm-sociallogin-plugin if needed."
|
||||
|
||||
The orchestrator's interpretation, recorded as given:
|
||||
1. **release**, with the proposed tags:
|
||||
- sm-user-plugin v0.1.12
|
||||
- sm-mfa-plugin v0.1.0, in a new private repository golem15/sm-mfa-plugin created with `tea repos create --owner golem15 --name sm-mfa-plugin`
|
||||
- sm-sociallogin-plugin v0.1.4
|
||||
2. **"push demo"**:
|
||||
- Pushing vue-demo-app is authorised, including the 4 unpushed Phase 19.7 commits (`0125e29`, `b973a76`, `3c53182`, `9c247ab`) under `44a5229`.
|
||||
- Pushing sm-demo-app after Task 6's commits is authorised, including its 19 unpushed commits from other phases.
|
||||
- sm-bm-app may be pushed after Task 6 only if its unpushed range is this phase's commits.
|
||||
- Never stage another session's uncommitted edits. sm-demo-app has another session's uncommitted journal, oauthserver and user pointer moves; leave them. sm-bm-app has dirty planning files; leave them too.
|
||||
3. **Ownership:** the orchestrator ran `sudo chown -R golem:golem` on `sm-sociallogin-plugin`. It is now golem-owned, clean, at `4d3b2dd` (v0.1.3). No other sudo.
|
||||
|
||||
Further limits:
|
||||
- **Plan 04 patch tags:** not authorised. Plan 04 must ask again before any tag.
|
||||
- Nothing is force-pushed or deployed.
|
||||
- fonoteka.go is never pushed.
|
||||
- No framework tag and no changelog post.
|
||||
|
||||
## Commits per repository
|
||||
|
||||
| Task | Repository | Commit | Message |
|
||||
|---|---|---|---|
|
||||
| 1 (tracer) | sm-mfa-plugin (`../sm-mfa-plugin`, no remote) | `2662252` | feat: WebAuthn security keys as a second factor |
|
||||
| 1 (tracer) | sm-mfa-plugin | `2662252` | feat: WebAuthn security keys as a second factor |
|
||||
| 2 | sm-mfa-plugin | `6c8916f` | feat: passwordless passkey login |
|
||||
| 2 | sm-sociallogin-plugin, **scratch clone only** | `a0161d7` (patch `19.6-03-sociallogin-gate.patch`, sha256 `bc0228df…5db72`) | feat: social sign-in through the login gate |
|
||||
| 3 | vue-demo-app (`../sm-demo-app/vue-demo-app`) | `44a5229` | feat: two-factor setup and the login challenge |
|
||||
| 2 | sm-sociallogin-plugin | `a8e3e78` | feat: social sign-in through the login gate (patch applied with `git am`; tree `c5f28f3` identical to the scratch clone's `a0161d7`) |
|
||||
| 3 | vue-demo-app | `44a5229` | feat: two-factor setup and the login challenge |
|
||||
| 5 | sm-mfa-plugin | `33ad164` | chore: require sm-user-plugin v0.1.12 |
|
||||
| 5 | sm-sociallogin-plugin | `b752177` | chore: require sm-user-plugin v0.1.12 |
|
||||
| 6 (2) | sm-bm-app | `aad6004` | chore: bump sm-user-plugin to v0.1.12 |
|
||||
| 6 (2) | sm-bm-app | `376cff4` | chore: bump sm-sociallogin-plugin to v0.1.4 |
|
||||
| 6 (2) | sm-bm-app | `ebb2266` | feat: mount golem15.mfa |
|
||||
| 6 (3) | fonoteka.go (local only) | `95fd58a` | chore: bump sm-user-plugin to v0.1.12 |
|
||||
| draft | summercms.go | `5a64611` | docs(19.6-03): draft summary at the Task 4 release checkpoint |
|
||||
|
||||
- The real `../sm-sociallogin-plugin` is unchanged: `4d3b2dd` = v0.1.3 = origin/master.
|
||||
- The patch is at `.planning/phases/19.6-two-factor-auth-and-device-flow-in-sm-user-plugin/19.6-03-sociallogin-gate.patch` and applies on `4d3b2dd` with `git am`.
|
||||
- The scratch clone is at `/tmp/claude-1002/-media-nvme-dev-golem15-summercms-io-summercms-summercms-go/c0ca11bb-a138-4d09-8120-38eddba1c3cf/scratchpad/sociallogin-clone`.
|
||||
- Tracer feedback gate (interactive, end-of-phase, verify fully automated): both Task 1 verify commands ran green on the committed code before Task 2 started.
|
||||
## Remote operations (in order)
|
||||
|
||||
## Task 4 reply
|
||||
Before every push I ran `git fetch` and checked that `origin/master..master` held only the authorised commits. Nothing was force-pushed or deployed.
|
||||
|
||||
(pending: awaiting the user's reply to the checkpoint)
|
||||
1. **sm-user-plugin** (`git@git.golem15.com:golem15/sm-user-plugin.git`):
|
||||
- Pushed master `50da92c..3b22134`: `8501f34`, `7900f47`, `3d4c8d2`, `4e3e5b0`, `3b22134`.
|
||||
- Annotated tag **v0.1.12** on `3b22134` (tag object `c0e0e85`), pushed.
|
||||
2. **sm-mfa-plugin:**
|
||||
- Created the private repository **https://git.golem15.com/golem15/sm-mfa-plugin** with `tea repos create --login git.golem15.com --owner golem15 --name sm-mfa-plugin --private`. The API confirms `"private":true`.
|
||||
- Remote `origin` = `git@git.golem15.com:golem15/sm-mfa-plugin.git`.
|
||||
- `git push -u origin master` pushed the new branch at `33ad164`, 6 commits.
|
||||
- Annotated tag **v0.1.0** on `33ad164` (tag object `b84dcbe`), pushed.
|
||||
3. **sm-sociallogin-plugin:**
|
||||
- Pushed master `4d3b2dd..b752177`: `a8e3e78`, `b752177`.
|
||||
- Annotated tag **v0.1.4** on `b752177` (tag object `18af090`), pushed.
|
||||
4. **vue-demo-app:** pushed master `21a22b6..44a5229`. That is the 4 named Phase 19.7 commits plus `44a5229`. No tag.
|
||||
5. **sm-bm-app** (Task 6 part 2): pushed master `aafbcce..ebb2266`, this phase's 3 commits only.
|
||||
|
||||
The acceptance checks pass:
|
||||
- `ls-remote --exit-code --tags` for v0.1.12, v0.1.0 and v0.1.4.
|
||||
- `grep -c 'sm-user-plugin v0.1.12' ../sm-mfa-plugin/go.mod` = 1.
|
||||
- `origin/master..master` is empty for sm-user-plugin, vue-demo-app and sm-bm-app.
|
||||
|
||||
## Open checkpoint: sm-demo-app (Task 6 part 1)
|
||||
|
||||
`git -C ../sm-demo-app status --porcelain` shows:
|
||||
- `M plugins/golem15/journal`, `M plugins/golem15/oauthserver`, `M plugins/golem15/user`: another session's uncommitted moves.
|
||||
- Its user submodule clone is checked out at `50da92c` (v0.1.11). It made v0.1.11's last commit there on 2026-10-24.
|
||||
- The committed gitlink is `bfcfea4` (v0.1.10), and go.mod requires v0.1.10.
|
||||
- `M vue-demo-app`: this plan's `44a5229`.
|
||||
|
||||
Commit A, the user bump, must move that same `plugins/golem15/user` pointer. Commits B and C cannot go first: sociallogin v0.1.4 and mfa v0.1.0 need v0.1.12's login gates, and the demo's go.work replaces the user module with that checkout.
|
||||
|
||||
The plan says to stop when another session's edits touch a Task 6 file, and the Task 4 interpretation says to leave the user pointer move alone. So part (1) did not start, and nothing in sm-demo-app was changed.
|
||||
|
||||
Proposed resolution:
|
||||
- Move only the user checkout from v0.1.11 to v0.1.12. That is a superset, `50da92c` stays on origin, and the submodule's working tree is clean, so nothing is lost.
|
||||
- Leave the journal and oauthserver moves unstaged.
|
||||
- Then run commits A-D, the tests, and the push of the 19 prior commits plus A-D.
|
||||
|
||||
## Tests
|
||||
|
||||
All Docker-backed tests ran against testcontainers Postgres (Docker reachable as golem).
|
||||
|
||||
- **sm-mfa-plugin:**
|
||||
- `go vet ./...` and `go test -count=1 -short ./...`: green at both commits.
|
||||
- `TestWebAuthnCeremonySmoke` (short): pass.
|
||||
- `TestWebAuthnSmoke`, `TestTracerSmoke`, `TestChallengeSmoke`, `TestTrustedSettingsSmoke`: 4 of 4 pass.
|
||||
- `TestPasswordlessSmoke` (7 subtests) and `TestWebAuthnSmoke`: 2 of 2 pass.
|
||||
- Full `go test ./...`: ok. It was also run against the framework's v0.5.0 tag (exported with `git archive` into the scratchpad): ok.
|
||||
- **sm-sociallogin-plugin (scratch clone, GOWORK pointing at the real summercms.go and user-plugin checkouts):**
|
||||
- `go vet`: green.
|
||||
- `-short` suite: ok.
|
||||
- `TestSocialGateSmoke` (5 subtests) and `TestTracerSmoke`: 2 of 2 pass.
|
||||
- Full suite: ok, against both the local framework and v0.5.0.
|
||||
- **NOT RUN in the real checkout**, which cannot be written.
|
||||
- **vue-demo-app:**
|
||||
- `pnpm test`: 17 files, 202 tests pass, including `twoFactor.test.ts` with 14 tests.
|
||||
- **Tasks 1-2:** `go vet ./...` and `-short`: green at every commit.
|
||||
- `TestWebAuthnCeremonySmoke`: pass.
|
||||
- `TestWebAuthnSmoke`, `TestTracerSmoke`, `TestChallengeSmoke`, `TestTrustedSettingsSmoke`: pass.
|
||||
- `TestPasswordlessSmoke` (7 subtests): pass.
|
||||
- Full suite: ok, also against the framework's v0.5.0 tag.
|
||||
- **Task 5, after the require bump:**
|
||||
- Vet and `-short` in workspace mode: green.
|
||||
- With `GOWORK=off` (module mode, sm-user-plugin v0.1.12 downloaded from git.golem15.com): vet, `-short` and the full suite are green.
|
||||
- `go list -deps` has no `gopkg.in/yaml.v3`.
|
||||
- **sm-sociallogin-plugin (real checkout):**
|
||||
- **After `git am`:** vet, `-short` and the full suite are green, including `TestSocialGateSmoke` (5 subtests) and `TestTracerSmoke`.
|
||||
- **After the require bump:** vet and `-short` green in workspace mode. Vet and the full suite green with `GOWORK=off`.
|
||||
- **sm-user-plugin** (before the push): vet from fonoteka.go and in the plugin, then `-short`: ok for all four packages.
|
||||
- **vue-demo-app (Task 3):**
|
||||
- `pnpm test`: 202 tests pass, including `twoFactor.test.ts` (14).
|
||||
- `pnpm build`: ok.
|
||||
- Server render of `/account/security` and `/login` on `.output`: 200.
|
||||
- **NOT RUN:**
|
||||
- Type check: no vue-tsc or `nuxi typecheck` is set up (deferred-items.md).
|
||||
- A browser run against a demo with golem15.mfa mounted: that needs Task 6.
|
||||
- Server render of `/account/security` and `/login`: 200.
|
||||
- **sm-bm-app:**
|
||||
- Build, vet and `-short` green after each of the 3 commits. The full suite is green too.
|
||||
- The plan's verify passes: `--- PASS: TestMFAMounted`.
|
||||
- **fonoteka.go:**
|
||||
- The plan's verify passes: root `vet ./...`, `test -short ./...` and `build ./...`.
|
||||
- Root `./...` covers only the root module, so I also ran vet and `-short` in every workspace module (`plugins/golem15/{feedback,fonoteka,golem,user}`). All green.
|
||||
- Without `-short`:
|
||||
- `parity` passes after the fix; it was red at v0.1.10 as well.
|
||||
- Five Docker-backed tests in `plugins/golem15/fonoteka` fail at v0.1.12. They fail identically at the committed v0.1.10 pointer (baseline run), so they predate this plan. They are listed in deferred-items.md.
|
||||
- Acceptance checks:
|
||||
- `grep -c '"/devices"'` = 0 and `grep -c '"2fa"'` = 1.
|
||||
- `summer.yaml` has no golem15.mfa.
|
||||
- `go list -m all` has no go-webauthn.
|
||||
- The pointer moved in the bump commit.
|
||||
- **NOT RUN:**
|
||||
- The demo verify (`TestMFAMounted`, `TestBootAllPlugins`, `TestGoModRequiresTags`): part (1) is open.
|
||||
- A vue-demo-app type check: no tooling for it.
|
||||
- A browser run of the demo screens.
|
||||
|
||||
## Exported identifiers (for plan 04 and the continuation)
|
||||
## Exported identifiers (for plan 04)
|
||||
|
||||
**sm-mfa-plugin `classes`:**
|
||||
- **Relying party and handles:**
|
||||
@@ -233,11 +341,13 @@ All Docker-backed tests ran against testcontainers Postgres (Docker reachable as
|
||||
- `POST …/webauthn/register/options`, `POST …/webauthn/register`
|
||||
- `DELETE …/webauthn/{id}` (digits)
|
||||
|
||||
**sm-sociallogin-plugin (patch):**
|
||||
**sm-sociallogin-plugin v0.1.4:**
|
||||
- `classes.Outcome.Challenge` and `classes.CompletionPayload.Challenge` (JSON `challenge,omitempty`).
|
||||
- Lang key `golem15.sociallogin::lang.oauth.two_factor_unavailable`.
|
||||
- Test `TestSocialGateSmoke`.
|
||||
- go.mod still requires sm-user-plugin v0.1.5, with go.work replacing it until Task 5.
|
||||
- go.mod requires sm-user-plugin v0.1.12 and SummerCMS v0.5.0.
|
||||
|
||||
**sm-bm-app:** `TestMFAMounted` (`mfa_test.go`).
|
||||
|
||||
**vue-demo-app:**
|
||||
- **`app/lib/twoFactor.ts`:**
|
||||
@@ -250,7 +360,7 @@ All Docker-backed tests ran against testcontainers Postgres (Docker reachable as
|
||||
- **UI:**
|
||||
- Page `/account/security`.
|
||||
- Header link to it.
|
||||
- i18n `auth.twoFactor.*`, `security.*`, `header.security` (en, pl).
|
||||
- i18n `auth.twoFactor.*`, `security.*`, `header.security`.
|
||||
|
||||
## Decisions Made
|
||||
|
||||
@@ -258,107 +368,93 @@ See key-decisions in the frontmatter.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed and drift
|
||||
**1. [Environment, resolved] sm-sociallogin-plugin write access**
|
||||
- **Problem:** the checkout was owned by `jin` (first run). The scratch-clone patch is described in the first draft.
|
||||
- **Fix:** at the user's instruction ("you can sudo chown golem:golem sm-sociallogin-plugin"), the orchestrator ran `sudo chown -R golem:golem`. I used no sudo.
|
||||
- **Result:** `git am` gave `a8e3e78`, whose tree `c5f28f3` is identical to the scratch clone's `a0161d7`. Vet, `-short` and the full suite were green there.
|
||||
|
||||
**1. [Blocking: environment, unresolved] sm-sociallogin-plugin cannot be written**
|
||||
- **Found during:** Task 2.
|
||||
- **Issue:** `../sm-sociallogin-plugin` is owned by `jin` (`drwxrwxr-x jin jin`); golem is not in the jin group, and git refuses the checkout as "dubious ownership". As instructed, I did not use sudo and did not write into it.
|
||||
- **What I did instead:**
|
||||
- Implemented D-09 in a scratch clone of `4d3b2dd`.
|
||||
- Tested it there with a GOWORK file pointing at the real summercms.go and user-plugin checkouts. `../fonoteka.go` and `../summercms.go` are symlinked next to the clone so the relative paths in its tests resolve.
|
||||
- Committed it there as `a0161d7` with the plan's message and exported it as `19.6-03-sociallogin-gate.patch` in this phase directory.
|
||||
- **Remaining:** `git am` in the real checkout (by jin, or after the user grants golem write access), then rerun its suite there. Task 5 step 3 (require the new user tag, push, tag) needs the same access.
|
||||
**2. [Drift, corrected] Release numbers**
|
||||
- The plan proposed sm-user-plugin v0.1.6 and sm-sociallogin-plugin v0.1.3. Both were stale.
|
||||
- Published as v0.1.12 and v0.1.4, the next free patches, as the reply confirmed.
|
||||
- sm-mfa-plugin is v0.1.0 as planned.
|
||||
- sm-mfa-plugin requires framework v0.5.0, not the plan's v0.3.1. Plan 02 already needed v0.5.0.
|
||||
- sociallogin's require rose from v0.3.1 to v0.5.0 through `go mod tidy`. Its README Dependencies now names v0.5.0 and user v0.1.12, in the same commit.
|
||||
|
||||
**2. [Drift] Release numbers**
|
||||
- **sm-user-plugin:** origin's newest tag is v0.1.11 (`50da92c`). Local master `3b22134` is 5 commits ahead: `8501f34`, `7900f47`, `3d4c8d2`, `4e3e5b0`, `3b22134`. The plan's "v0.1.6" is stale; the next free patch is **v0.1.12**.
|
||||
- **sm-sociallogin-plugin:** origin's newest tag is v0.1.3 (`4d3b2dd`, Phase 19.8's SignedInEvent). The plan's "v0.1.3" is taken; the next free patch is **v0.1.4**.
|
||||
- **Framework:** the newest tag is v0.5.0. sm-mfa-plugin and sm-user-plugin require it. sociallogin requires v0.3.1, and after its require bump to user v0.1.12, `go mod tidy` will raise that to v0.5.0.
|
||||
- **No framework tag is needed.** Both plugins pass against the v0.5.0 tag.
|
||||
**3. [Drift] vue-demo-app pushed with another phase's commits**
|
||||
- The push included Phase 19.7's `0125e29`, `b973a76`, `3c53182` and `9c247ab`.
|
||||
- The Task 4 reply authorised them by name.
|
||||
|
||||
**3. [Drift] vue-demo-app carries another phase's unpushed commits**
|
||||
- The plan expected `5a8d544`. The checkout is at `9c247ab`, 4 commits ahead of origin/master `21a22b6`: Phase 19.7's `0125e29`, `b973a76`, `3c53182`, `9c247ab` (MCP consent and link-admin pages, 2026-10-23).
|
||||
- Task 3 committed on top (`44a5229`). Pushing vue-demo-app also pushes those four, so the Task 5 pre-push rule requires the reply to name them.
|
||||
**4. [Checkpoint] sm-demo-app part (1) not started**
|
||||
- Another session's uncommitted `plugins/golem15/user` move touches a Task 6 file (see "Open checkpoint").
|
||||
|
||||
**4. [Drift] sm-demo-app state for Task 6**
|
||||
- master is 19 commits ahead of origin (other phases).
|
||||
- Its working tree has another session's uncommitted submodule pointer moves for `plugins/golem15/journal`, `plugins/golem15/oauthserver` and `plugins/golem15/user` (user checked out at v0.1.11 while go.mod still requires v0.1.10).
|
||||
- The `vue-demo-app` gitlink now shows as modified because of `44a5229`.
|
||||
- Task 6 must not stage the other sessions' pointers. A push needs the reply to name the 19 commits.
|
||||
**5. [Rule 3, scope] fonoteka.go guard tests cover every user version the bump crosses**
|
||||
- **Problem:** the committed pointer was v0.1.10, but the guards had not followed it. `TestHiddenNeverMarshals` expected 8 models with 10 present. The parity migration count expected 11 with 14 present, and the account-link tables had no allowance. So the plan's "+1 for DeviceAuthSession" would have left them red.
|
||||
- **What `95fd58a` changes:**
|
||||
- `expectedUserModels` 8 → 11, with a comment naming BackendLink, BackendLinkRequest and DeviceAuthSession.
|
||||
- New `wantUserMigrations = 15` in parity.
|
||||
- Allowances for `golem15_user_backend_links`, `golem15_user_backend_link_requests` and `golem15_user_device_auth_sessions`.
|
||||
- `TestRequirePasswordChangeExemptSet` allows jwt.auth on `POST /_user/api/v1/backend-link/confirm`, which comes from v0.1.11.
|
||||
- The deferred-routes guard drops the devices fragment and keeps 2fa. Its comment avoids the quoted `"/devices"` so the acceptance grep stays at 0.
|
||||
- **Untouched:** five other Docker-backed fonoteka failures fail identically at v0.1.10 and do not inventory the user plugin, so they were left alone (deferred-items.md).
|
||||
|
||||
**5. [Rule 2 - Security] Availability check on webauthn/register too**
|
||||
- PHP checked availability only on register/options.
|
||||
- `register` also answers 403 while webauthn is not an available method, as `totp/confirm` does since plan 02.
|
||||
- **Commit:** `2662252`.
|
||||
**6. [Scope] sm-bm-app `scripts/build.sh`**
|
||||
- It is not in the plan's file list.
|
||||
- The 117ef8f precedent adds each mounted plugin to `PLUGINS`, which drives the release go.work and the dirty check. mfa was added there.
|
||||
|
||||
**6. [Rule 2 - Correctness] Assertion write-back is guarded**
|
||||
- The credential record is written back with `WHERE sign_count = <read value> AND is_enabled`, inside the completing transaction.
|
||||
- A concurrent write or a disabled key refuses the login instead of losing the counter.
|
||||
- **Commit:** `2662252`.
|
||||
**7. [Scope] fonoteka.go root go.mod still requires sm-user-plugin v0.1.10**
|
||||
- The plan limits staging to the pointer and the tests.
|
||||
- The replace makes the build use v0.1.12.
|
||||
- A follow-up is in deferred-items.md.
|
||||
|
||||
**7. [Discretion] Function split**
|
||||
- The plan named `FinishAssertion(ctx, app, tx, …)` as the one step that verifies and writes.
|
||||
- It is now `FinishAssertion` (verify, no write, outside the transaction, like the TOTP path), followed by `RecordAssertion` (guarded write in the transaction).
|
||||
- `VerifyRegistration` and `VerifyAssertion` are exported pure helpers, so the no-database smoke test exercises the handlers' exact code.
|
||||
- `CompleteLoginAs` was added for the passkey source.
|
||||
**8. [Cosmetic] sm-mfa-plugin v0.1.0 tag message**
|
||||
- It says the mode is "optional, required or disabled"; the actual values are `disabled`, `optional` and `enforced`.
|
||||
- The tag is pushed and is not rewritten, since that would need a force-push (deferred-items.md).
|
||||
|
||||
**8. [Rule 2 - Security, fail closed] Passkey routes 403 while two_factor_mode is disabled**
|
||||
- This is not only tied to `two_factor_passwordless_login`.
|
||||
- **Commit:** `6c8916f`.
|
||||
|
||||
**9. [Rule 2 - Security] Passkey ban check across addresses**
|
||||
- `ThrottleStates` (a ban or active suspension on any row) runs in addition to `RejectIfThrottled` with the request's address.
|
||||
- An unactivated account is refused too (tested).
|
||||
- **Commit:** `6c8916f`.
|
||||
|
||||
**10. [Scope] Extra test coverage**
|
||||
- `TestWebAuthnSmoke` also checks the admin reset deleting keys and the 403 while webauthn is unavailable.
|
||||
- `TestPasswordlessSmoke` adds `wrong_handle_refused` and an unactivated user.
|
||||
- `TestSocialGateSmoke` also covers `oauth-register-complete` answering the challenge.
|
||||
|
||||
**11. [Scope] Demo UI extras**
|
||||
- Additional i18n keys beyond the plan's list:
|
||||
- `auth.twoFactor.busy`, `auth.twoFactor.recoveryPrompt`
|
||||
- `security.eyebrow`, `security.qrAlt`, `security.cancel`, `security.codeInvalid`, `security.unavailable`
|
||||
- `header.security`
|
||||
- The setup form has a cancel link.
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 11 (1 unresolved blocker, 3 drifts, 4 Rule 2 fixes, 1 discretion, 2 scope).
|
||||
**Impact on plan:** Every must-have truth of Tasks 1 and 3 holds in committed code. D-09 holds in the prepared patch, but not yet in the real repository. No locked CONTEXT decision changed.
|
||||
**9-15 (from the first run):**
|
||||
- Rule 2: availability check on `webauthn/register`.
|
||||
- Rule 2: guarded assertion write-back.
|
||||
- Discretion: `FinishAssertion` / `RecordAssertion` split, exported `VerifyRegistration` / `VerifyAssertion`, and `CompleteLoginAs`.
|
||||
- Rule 2: passkey routes 403 while `two_factor_mode` is disabled.
|
||||
- Rule 2: passkey ban check across addresses (ThrottleStates) and refusal of unactivated accounts.
|
||||
- Extra test coverage in `TestWebAuthnSmoke`, `TestPasswordlessSmoke` and `TestSocialGateSmoke`.
|
||||
- Demo UI extras: i18n keys and a cancel link. The commits and details are unchanged from the first draft (`2662252`, `6c8916f`, `44a5229`).
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None. Plan 02's two stubs are closed:
|
||||
None.
|
||||
- `status.webauthn_credentials` lists the enabled keys.
|
||||
- `Admin.Reset` deletes WebAuthn credentials, and `HasTwoFactor` counts them.
|
||||
- `Admin.Reset` deletes WebAuthn credentials.
|
||||
- sm-bm-app mounts the two-factor API without frontend screens, which is intended and documented in its README row. Users cannot enable a second factor there, so sign-in is unchanged.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None beyond the plan's register. T-19.6-26..31 and T-19.6-33 are mitigated in code and covered by the tests above. T-19.6-32 (remote operations) is the open Task 4 decision.
|
||||
None beyond the plan's register.
|
||||
- T-19.6-26..31 and T-19.6-33 are mitigated in code and tests.
|
||||
- T-19.6-32: each push followed a fetch and a range check against the authorised commits. Nothing was force-pushed or deployed, and fonoteka.go was not pushed.
|
||||
|
||||
## Blockers
|
||||
|
||||
- **sm-sociallogin-plugin write access** (Deviation 1). It blocks applying `a0161d7` and the sociallogin half of Task 5.
|
||||
- **Task 4 release decision.**
|
||||
- **sm-demo-app user pointer** (another session's uncommitted move). The decision is needed before Task 6 part (1).
|
||||
|
||||
## Next
|
||||
|
||||
The continuation agent reads this draft and the Task 4 reply, then:
|
||||
- (if the reply resolves the sociallogin access) applies the patch;
|
||||
- runs Task 5 in D-17 order and Task 6;
|
||||
- finalises this SUMMARY: requirements-completed, status complete, final commits;
|
||||
- updates STATE and ROADMAP.
|
||||
After the decision, the continuation agent:
|
||||
- runs Task 6 part (1) in sm-demo-app: commits A-D, the demo verify, then the push of the 19 prior commits plus A-D;
|
||||
- finalises this SUMMARY: requirements-completed and status complete;
|
||||
- updates ROADMAP progress.
|
||||
|
||||
g15office: this executor has no g15office tool, so the orchestrator should post the plan 03 update on `avoroeb4`.
|
||||
g15office: this executor has no g15office tool. The orchestrator posts the plan 03 update on `avoroeb4`.
|
||||
|
||||
## Self-Check: PASSED (draft)
|
||||
|
||||
- Commits exist:
|
||||
- sm-mfa-plugin: 2662252, 6c8916f
|
||||
- vue-demo-app: 44a5229
|
||||
- scratch clone: a0161d7
|
||||
- Working trees of sm-mfa-plugin and vue-demo-app are clean.
|
||||
- ../sm-sociallogin-plugin is untouched (4d3b2dd, clean).
|
||||
- sm-mfa-plugin has no remote, and the sm-user-plugin HEAD is untagged.
|
||||
- No remote operation was performed; only read-only ls-remote calls.
|
||||
- **Commits exist:**
|
||||
- sm-mfa-plugin: `2662252`, `6c8916f`, `33ad164`
|
||||
- sm-sociallogin-plugin: `a8e3e78`, `b752177`
|
||||
- vue-demo-app: `44a5229`
|
||||
- sm-bm-app: `aad6004`, `376cff4`, `ebb2266`
|
||||
- fonoteka.go: `95fd58a`
|
||||
- **Tags and branches are on origin:** v0.1.12, v0.1.0 and v0.1.4 via `ls-remote`, and sm-mfa-plugin master.
|
||||
- **Working trees:**
|
||||
- The working trees of sm-mfa-plugin, sm-sociallogin-plugin and fonoteka.go are clean.
|
||||
- sm-bm-app keeps only the other session's planning edits and untracked paths.
|
||||
- sm-demo-app is unchanged by this run.
|
||||
|
||||
@@ -6,3 +6,17 @@
|
||||
- vue-demo-app has no type-check tooling
|
||||
status: open
|
||||
**What:** the Nuxt build does not type-check, and `vue-tsc` is not a dependency, so 19.6-03 Task 3 checked the new page, composables and header with vitest and `pnpm build` only. The user decides whether to add `nuxi typecheck`.
|
||||
- fonoteka.go: five Docker-backed tests in `plugins/golem15/fonoteka` fail without `-short`, at the committed user pointer v0.1.10 as well as at v0.1.12
|
||||
status: open
|
||||
**What:** found by 19.6-03 Task 6 (baseline run with the user submodule at `bfcfea4`; the failures are identical):
|
||||
- `TestPhase09SecurityRoutes`: unexpected cabana admin routes (account/contributions, account/preferences, reorder, singleton) from the framework working tree.
|
||||
- `TestPhase8RedMCPMe`, `TestOAuthToolsMeRouteIsolation`: `GET /_user/api/v1/token/me` counts as a `/me`-suffixed route on another surface.
|
||||
- `TestMustChangePasswordLock`: login answers 401 "Invalid email or password".
|
||||
- `TestPhase14Edges/prune-cutoff-90-days-then-one-second-older`: prune leaves the "past" row.
|
||||
None of these tests inventories user-plugin tables, routes or models, so 19.6-03 did not change them. The `-short` suites are green. The parity inventories (`parity/migrate_test.go`, `parity/schema_diff_test.go`) were also red at v0.1.10; `95fd58a` fixed them along with the bump.
|
||||
- fonoteka.go: root `go.mod` still requires `sm-user-plugin v0.1.10`
|
||||
status: open
|
||||
**What:** the module resolves through `replace => ./plugins/golem15/user`, so builds and tests use the v0.1.12 checkout. 19.6-03 Task 6 staged only the paths the plan names. Precedent `06bc9d0` raised the require together with the pointer. Raise it to v0.1.12 (and tidy) in a follow-up `chore:` commit.
|
||||
- sm-mfa-plugin: the v0.1.0 tag message says the two-factor mode is "optional, required or disabled"
|
||||
status: open
|
||||
**What:** the config values are `disabled`, `optional` and `enforced`. The tag is pushed and is not rewritten (that would need a force-push). The README and `config/config.yaml` are correct. The next release's tag message should name the right values.
|
||||
|
||||
Reference in New Issue
Block a user