Files
summercms/.planning/phases/12.1-user-plugin-admin-screens/12.1-05-SUMMARY.md

320 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 12.1-user-plugin-admin-screens
plan: 05
subsystem: testing
tags: [cabana, pact, sm-user-plugin, admin, vitest, check-phase12.1, security-review, coverage, privileged-groups]
requires:
- phase: 12.1-user-plugin-admin-screens
provides: "plans 01 to 04: framework contracts at v0.1.3, the three admin screens, T-12-18 / D-30 guards, smoke tests, validation seed"
provides:
- "TestPhase121Threats in cabana (T-12.1-01 to T-12.1-15) and in sm-user-plugin (T-12.1-18..25, 27..31, 34, 38, 39; T-12-18 cited)"
- "scripts/check-phase12.1.sh fail-closed gate (self-test, go, security, removal, coverage, spa, openapi, dist, docs, hygiene, app, evidence, all)"
- "SPA unit tests including the five UI-SPEC backstops"
- "12.1-SECURITY-REVIEW.md (threats_open 0) and signed-off 12.1-VALIDATION.md (nyquist_compliant true)"
affects: [gsd-verify-work, sm-user-plugin publication, fonoteka.go push]
actuals:
tokens: 141472 # chars/4: framework c076b4c^..93f0171 (101051) + plugin 4693155..2b04cda (40353) + fonoteka.go 35a727f..93b8b75 (68)
tasks: 3
commits: 7
plan_head_before: 52f864ebfc58a488037e60b27a778df8c4158f08
plan_head_after: 93f0171e9c0eb798a61d5d71082873d1b3e8c4c6
plugin_repo: sm-user-plugin (../fonoteka.go/plugins/golem15/user)
plugin_commits: 7
plugin_head_before: 469315510809f703fc315aceaa9ef902794a0237
plugin_head_after: 2b04cda3ff8c4375ca4206f6ae751a6221db0483
app_repo: fonoteka.go (../fonoteka.go)
app_commits: 2
app_head_before: 35a727f1ddfde0a443cf203193bf3705fe3158a1
app_head_after: 93b8b758d540e5edb5095c8ed99998e57d4150d8
tech-stack:
added: []
patterns:
- "Phase gate: go test -json detector refuses fail, skip, zero tests, non-JSON, missing named prefix; removal is anchor-exact mutate / assert-fail / cmp restore"
- "One TestPhase121Threats per repository, subtest named by threat id; high/critical threats also have a removal row"
key-files:
created:
- scripts/check-phase12.1.sh
- modules/cabana/phase121_threats_test.go
- modules/cabana/phase121_bulk_test.go
- modules/cabana/phase121_record_test.go
- modules/cabana/phase121_rowstate_test.go
- modules/cabana/phase121_forbidden_test.go
- modules/cabana/phase121_preview_test.go
- modules/cabana/phase121_fields_test.go
- modules/cabana/phase121_permission_test.go
- modules/cabana/phase121_relation_lock_test.go
- modules/cabana/phase121_list_test.go
- modules/cabana/phase121_schema_boot_test.go
- admin/tests/list/BulkActionsMenu.test.ts
- admin/tests/list/RowStateBadges.test.ts
- admin/tests/form/RecordActions.test.ts
- admin/tests/form/PreviewView.test.ts
- admin/tests/form/PreviewField.test.ts
- admin/tests/form/PermissionEditorField.test.ts
- admin/tests/form/PasswordField.test.ts
- admin/tests/form/FormErrorBanner.test.ts
- ../fonoteka.go/plugins/golem15/user/phase121_security_test.go
- ../fonoteka.go/plugins/golem15/user/admin_users_edge_test.go
- ../fonoteka.go/plugins/golem15/user/admin_groups_edge_test.go
- ../fonoteka.go/plugins/golem15/user/admin_organisations_edge_test.go
- ../fonoteka.go/plugins/golem15/user/admin_registration_test.go
- .planning/phases/12.1-user-plugin-admin-screens/12.1-SECURITY-REVIEW.md
modified:
- modules/pact/capabilities_test.go
- admin/tests/list/ListToolbar.test.ts
- admin/tests/list/DataTable.test.ts
- admin/tests/list/ListView.test.ts
- admin/tests/form/RelationField.test.ts
- admin/tests/form/FormView.test.ts
- admin/tests/form/formState.test.ts
- admin/tests/form/registry.test.ts
- admin/tests/app/winterUrl.test.ts
- admin/tests/app/router.test.ts
- docs/backend/forms.md
- docs/backend/relation-manager.md
- .planning/phases/12.1-user-plugin-admin-screens/12.1-VALIDATION.md
- ../fonoteka.go/plugins/golem15/user/classes/admin_actions.go
- ../fonoteka.go/plugins/golem15/user/classes/privileged.go
- ../fonoteka.go/plugins/golem15/user/models/user.go
key-decisions:
- "Security review was self-performed by the executor (no reviewer agent on this runtime); threats_open 0; five findings_for_decision recorded, not closed silently"
- "pending: push sm-user-plugin — condition (c) failed: git ls-remote --tags origin v0.1.3 is empty. Conditions (a)(b)(d) hold. Nothing was pushed."
- "No follow-up framework tag: git diff --name-only v0.1.3 HEAD -- modules cmd admin/src lists only Go tests and testdata"
- "Two plugin production fixes during tests (FX-1 clean statement, FX-2 group filter value); FX-3 is a test-only strengthening of T-12.1-24"
patterns-established:
- "Last plan of a phase: named threat tests, 80% coverage floor, removal harness, SECURITY-REVIEW, VALIDATION sign-off, then one plugin push point gated on a published framework tag"
requirements-completed: [SC-5]
coverage:
- id: D1
description: "Named threat tests in both repos and a fail-closed --security stage"
requirement: SC-5
verification:
- kind: integration
ref: "modules/cabana/phase121_threats_test.go#TestPhase121Threats"
status: pass
- kind: integration
ref: "../fonoteka.go/plugins/golem15/user/phase121_security_test.go#TestPhase121Threats"
status: pass
- kind: other
ref: "scripts/check-phase12.1.sh --self-test && --security"
status: pass
human_judgment: false
- id: D2
description: "Go unit/integration coverage at or above 80% for pact, cabana, and the user plugin packages root, classes, controllers, models, updates"
requirement: SC-5
verification:
- kind: other
ref: "scripts/check-phase12.1.sh --coverage (pact 100.0, cabana 86.6, plugin root 89.1, classes 89.0, controllers 83.0, models 95.7, updates 90.2)"
status: pass
human_judgment: false
- id: D3
description: "SPA unit tests including the five UI-SPEC backstops; OpenAPI, dist, docs, hygiene"
requirement: SC-5
verification:
- kind: unit
ref: "admin/tests/list/ListView.test.ts#backstop: focus returns to the bulk menu trigger"
status: pass
- kind: unit
ref: "admin/tests/app/winterUrl.test.ts#backstop: mapWinterUrl maps preview/:id"
status: pass
- kind: unit
ref: "admin/tests/list/RowStateBadges.test.ts#backstop: a row state outside the fixed set"
status: pass
- kind: unit
ref: "admin/tests/form/PermissionEditorField.test.ts#backstop: radio/checkbox emission and locked row"
status: pass
- kind: unit
ref: "admin/tests/form/RelationField.test.ts#backstop: a locked option cannot be chosen"
status: pass
- kind: other
ref: "scripts/check-phase12.1.sh --spa --openapi --dist --docs --hygiene"
status: pass
human_judgment: false
- id: D4
description: "Removal harness proves high/critical protections including D-30 FormBeforeUpdate and FormBeforeDelete"
requirement: SC-5
verification:
- kind: other
ref: "scripts/check-phase12.1.sh --removal (27 rows, RC-23 T-12.1-38, RC-24 T-12.1-39)"
status: pass
human_judgment: false
- id: D5
description: "Security review maps T-12.1-01..40 and T-12.1-SC; validation signed off; plugin push pending on origin tag"
requirement: SC-5
verification:
- kind: other
ref: "scripts/check-phase12.1.sh --evidence && --all"
status: pass
human_judgment: true
rationale: "End-of-phase visual walk of the three screens in light and dark mode, and the D-30 email/password/delete feel, cannot be asserted by unit tests (plan 05 Task 3 human-check)."
duration: 103min
completed: 2026-10-05
status: complete
---
# Phase 12.1: User plugin admin screens — Plan 05 Summary
**Fail-closed `scripts/check-phase12.1.sh`, named threat tests in both repos, SPA backstops, 80%+ coverage, security review with zero open threats, and validation signed off. Plugin push is pending because `v0.1.3` is not on origin.**
## Performance
- **Duration:** 103 min (executor 14:30–16:13 local). The previous session finished every production commit and died before this SUMMARY; this file closes that illegal partial-plan state.
- **Started:** 2026-10-05T12:30:31Z
- **Completed:** 2026-10-05T14:13:50Z (production commits); SUMMARY closed out 2026-10-05T15:00:00Z
- **Tasks:** 3 of 3
- **Files modified:** 37 in summercms.go, 17 in sm-user-plugin, 2 pointer bumps in fonoteka.go
## Accomplishments
- One named threat test per repository. Cabana `TestPhase121Threats` covers T-12.1-01 to T-12.1-15. Plugin `TestPhase121Threats` covers T-12.1-18 to T-12.1-25, 27 to 31, 34, 38 and 39, and cites T-12-18 by that id.
- `scripts/check-phase12.1.sh` is executable and fail-closed. `--all` passed in 11 min 47 s. `--removal` passed 27 rows in 6 min 29 s and left both trees clean.
- Statement coverage: `modules/pact` 100.0%, `modules/cabana` 86.6%; plugin root 89.1%, `classes` 89.0%, `controllers` 83.0%, `models` 95.7%, `updates` 90.2%.
- Five UI-SPEC backstops have named vitest cases (bulk-menu focus, preview URL mapping, unknown row state, permission-editor emission, locked relation options).
- `12.1-SECURITY-REVIEW.md`: 41 threat ids match the five plans, `threats_open: 0`, D-30 and T-12-18 sections present. `12.1-VALIDATION.md`: `nyquist_compliant: true`, no TBD row.
## Task Commits
### summercms.go
| Task | Commit | Subject |
|------|--------|---------|
| 1 | `c076b4c` | test(12.1-05): threat test for the Phase 12.1 framework contracts and the first gate stages |
| 2 | `2e94cbf` | test(12.1-05): unit tests for bulk and record actions, row state, forbidden, preview and the form seams |
| 3 | `84efdc0` | test(12.1-05): unit tests for the Phase 12.1 SPA components |
| 3 | `aced6c7` | test(12.1-05): unit tests for the list, form, preview and routing behaviours of Phase 12.1 in the SPA |
| 3 | `3190b1c` | test(12.1-05): complete the Phase 12.1 gate with the removal, coverage, app and evidence stages |
| 3 | `83feeef` | docs(12.1-05): state the limits of relation locks and locked permission codes |
| 3 | `93f0171` | docs(12.1-05): security review and validation sign-off for Phase 12.1 |
Framework head before `52f864e`, after `93f0171`. Tag `v0.1.3` (`df5cace`) is an ancestor. No production Go or SPA source under `modules`, `cmd`, or `admin/src` changed after the tag.
### sm-user-plugin
| Task | Commit | Subject |
|------|--------|---------|
| 1 | `ba43ad9` | test: pin every mitigated Phase 12.1 threat of the admin screens in TestPhase121Threats |
| 2 | `f496959` | fix: read privileged membership and the admin actions through a clean statement (T-12.1-38, T-12.1-39) |
| 2 | `43fabfa` | fix: a group filter value that is not a group id lists nobody (D-23) |
| 2 | `493a3ff` | test: unit tests for the admin class functions, the models and the admin registration |
| 2 | `a848aa1` | test: edge cases of the Users, User Groups and Organisations admin controllers |
| 2 | `7991b53` | test: extend the permission resolver table, the admin migration history and the API token refusals |
| 3 | `2b04cda` | test: T-12.1-24 also marshals a user with last_seen and permissions |
Plugin head before `4693155`, after `2b04cda`. Tree clean. 21 commits ahead of origin `0fe5b91`. Remote head was `0fe5b91` at the start of Task 2 and still `0fe5b91` at close-out: this plan pushed nothing.
### fonoteka.go
| Purpose | Commit | Subject |
|---------|--------|---------|
| Task 2 pointer | `ed78e6e` | build: bump sm-user-plugin (unit tests, the group filter value and the clean-statement fix) |
| Task 3 pointer | `93b8b75` | build: bump sm-user-plugin (T-12.1-24 marshals the user model) |
Application pointer equals plugin HEAD `2b04cda`. fonoteka.go was not pushed.
## Gate output (recorded 2026-10-05)
| Stage | Time | Result |
|-------|------|--------|
| `--self-test` | 2 s | PASS |
| `--go` | 87–130 s | PASS |
| `--security` | 84 s | PASS |
| `--coverage` | 111 s | PASS (numbers above) |
| `--spa` | 52 s | PASS (71 files, 1013 tests with typecheck) |
| `--openapi` | 11 s | PASS |
| `--dist` | 19–22 s | PASS |
| `--docs` | 8 s | PASS |
| `--hygiene` | <1 s | PASS |
| `--app` | 290–325 s | PASS |
| `--evidence` | <1 s | PASS |
| `--all` | 11 min 47 s | PASS |
| `--removal` | 6 min 29 s (27 rows) | PASS; both trees clean afterwards |
Renaming one named plugin test by hand made `--security` exit non-zero with `refuse: missing named test`; the rename was reverted (T-12.1-35).
## Publication (T-12.1-40)
Checked after the review and `--all` on the final heads. Plugin remote head noted at the start of step (5): `0fe5b91b632a0ab784f3cecd2d5cf168528062ac`.
| Condition | Held | Evidence |
|-----------|------|----------|
| (a) gate passed | yes | `--all` PASS |
| (b) threats_open 0 | yes | `12.1-SECURITY-REVIEW.md` |
| (c) `git ls-remote --tags origin v0.1.3` lists the tag | **no** | empty |
| (d) no framework production code after the tag | yes | `git diff --name-only v0.1.3 HEAD -- modules cmd admin/src` is tests and testdata only |
**pending: push sm-user-plugin** because (c) failed. Push framework `master` and annotated tag `v0.1.3` first (pending since plan 02). Then push sm-user-plugin master (never force). Then **push fonoteka.go** (user step). No follow-up framework tag is needed from this plan.
## Decisions Made
- Reviewer line is the executor self-review, matching 08-10 and Phase 12, because this runtime cannot spawn the security-review agent.
- H-01 and H-02 (relation-lock vs manager; locked permission value outside the mode) were documented in `docs/backend/relation-manager.md` and `docs/backend/forms.md` rather than changing tagged production code.
- Five findings left for the owner (FD-1 to FD-5): organisation_role on unlink, lock vs relation manager, boolean permission JSON, host `admin.jwt.secret`, and whether deactivate/ban should follow D-30.
## Deviations from Plan
### Auto-fixed Issues
**1. FX-1 — privileged membership read cloned a dirty statement**
- **Found during:** Task 2 / removal of T-12.1-38
- **Issue:** `classes.fresh` chained `WithContext` onto a lazy `NewDB` session and cloned the caller's conditions; `IsPrivilegedMember` could answer false for a privileged member
- **Fix:** build the empty statement first (`f496959`)
- **Verification:** `TestIsPrivilegedMember`, `TestAdminActions`; removal RC-25
- **Committed in:** `f496959`
**2. FX-2 — group filter 500 on a non-id value**
- **Found during:** Task 2 edge tests (D-23)
- **Issue:** `filter[groups]=abc` made the Users list answer 500
- **Fix:** a value that is not a positive whole number lists nobody (`43fabfa`)
- **Verification:** `TestAdminUsersGroupFilterValue`; removal RC-26
- **Committed in:** `43fabfa`
**3. FX-3 — T-12.1-24 removal survived on API payloads only**
- **Found during:** Task 3 `--removal` RC-18
- **Issue:** the subtest only read field-by-field API payloads, so removing `json:"-"` on `LastSeen` still passed
- **Fix:** also marshal the model (`2b04cda`)
- **Verification:** RC-18 and RC-27 now fail as required
- **Committed in:** `2b04cda`
---
**Total deviations:** 3 auto-fixed (2 production plugin fixes, 1 test strengthening). No framework production code. No scope creep.
## Issues Encountered
The first executor session completed every plan-05 production commit (`93f0171` last) and exhausted context before writing SUMMARY.md. Resume closed that gap instead of re-executing the 250k-token plan.
## User Setup Required
None - no external service configuration required.
Pending owner actions (not setup): push `v0.1.3` to origin, then sm-user-plugin, then fonoteka.go. Human visual UAT of the three screens is `/gsd-verify-work 12.1`.
## Next Phase Readiness
- Automated evidence for SC-5 is in place. Phase stays pending until human verification of the three screens.
- Plugin and application remain local-only until the framework tag is on origin.
- FD-1..FD-5 in the security review are owner decisions, not blockers for this plan.
## Self-Check: PASSED
- [x] All three tasks executed and committed
- [x] Gate `--all` and `--removal` recorded passing
- [x] Coverage floor met
- [x] Threat ids in the review match the five plans (41)
- [x] Publication recorded as pending with the failed condition
- [x] SUMMARY.md created
---
*Phase: 12.1-user-plugin-admin-screens*
*Completed: 2026-10-05*