20 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, plan_head_before, plan_head_after, fonoteka_head_before, fonoteka_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 | plan_head_after | fonoteka_head_before | fonoteka_head_after | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10.1-runtime-admin-extension-point | 04 | testing |
|
|
|
|
|
c3c547c394 |
bbceeb957f |
9868a0a26957d4657e7084755655dd3a6f6c8f11 | c72c10662fb22517dbda6b72c1b8eb4837358764 |
|
|
|
|
|
|
42min | 2026-09-29 | complete |
Phase 10.1 Plan 04: Unit tests, gate and security evidence Summary
The Phase 10.1 extension point now has full test coverage. Eight named Go tests run on an acme fixture plugin and on PostgreSQL, one assembled Albums acceptance test runs in fonoteka.go, and ten Vitest suites cover the SPA side. One fail-closed check-phase10.1.sh --all gate passes, and a security review records 23 removal checks. Along the way the review found and fixed a percent-encoded .. bypass of the plugin asset URL check.
Performance
- Duration: 42 min
- Started: 2026-09-29T00:30:57Z
- Completed: 2026-09-29T01:13:27Z
- Tasks: 3
- Files modified: 31 in summercms.go (plus the rebuilt dist), 1 in fonoteka.go
Accomplishments
- Schema, sanitizer, asset and action tests on the
testdata/extensionfixture. The boot-error tables cover 20 widget rules, 12 partial rules and 6 toolbar rules, and each one asserts the plugin, controller and file named in the error. The sanitizer covers 19 dropped tags, the attribute table, 16 URL cases, per-requesttransin en and pl on one compiled template, all three caps at and just past their limit, and the view-model guard both directly and through the route. TestPhase101Actionsruns on PostgreSQL through the assembled router. It covers the scoped record, the fill filter in both directions, 8 malformed bodies, the action permission on top of the controller's, ValidationError versus plain error mapping, the CSRF header on both routes, and the toolbar and partial 404/422 rules.TestPhase101AlbumsExtensioncovers these cases:- An empty admin collection shows
All albums 0while a second collection holds four albums. - "No shelf" appears only when its count is above zero.
- The widget fill of 1977/LP is saved and reloads.
- The sync toast appears in en and pl.
- A Genres-only admin gets 403 on all three routes, and each action declares its own permission.
- The assets are served with the right headers.
- Every called route template appears in admin.json.
- An empty admin collection shows
- The Vitest suites for WidgetField (fake-timer 5000 ms timeout,
whenDefined, attributes only, one POST while busy, fill-key-only patch), PartialHost and partialNodes (exhaustive tag and attribute tables includingjavascript:, depth and node caps, busy refetch), pluginAssets (18 refused URL shapes, retry after error, per-controller links), plus ListToolbar, ListView, registry, formState, FormField and FormView extensions. 677 tests pass offline. scripts/check-phase10.1.sh: the detector with 14 synthetic cases, plushygiene_101with three named rules proven by eight plants and one clean look-alike.--evidencerequires a removal-check row for every high threat. Bothcheck-phase10.1.sh --all("phase10.1 all passed") andcheck-phase10.sh --all("phase10 all passed") pass.10.1-SECURITY-REVIEW.mdhas 23 threat rows and 23 removal checks (RC-01 to RC-23), all failing as required.10.1-VALIDATION.mdis validated withnyquist_compliant: true.
Task Commits
summercms.go:
- Task 1: Go coverage and fixture tree -
7eed4ac(test) - Task 2 (security fix found by the new suite): percent-encoded dot segments -
6b0ac15(fix) - Task 2: SPA Vitest suites -
11c4e54(test) - Task 3 (blocking fix): stale parity allow-list in the Phase 10 gate -
9aeb0e1(fix) - Task 3: Phase 10.1 gate -
02df0a8(feat) - Task 3: security review and validation map -
bbceeb9(docs)
fonoteka.go:
- Task 1: Albums acceptance test -
c72c106(test)
Commit count: git rev-list --count c3c547c..bbceeb9 is 6 in summercms.go, plus 1 in fonoteka.go, for 7 plan commits.
Files Created/Modified
modules/cabana/testdata/extension/**: the acme fixture plugin, with the gadgets controller, stats and summary partials, lookup widget, JS, CSS and lang filesmodules/cabana/phase101_schema_test.go: form extension, partial schema and toolbar tests, plus the shared fixture helpersmodules/cabana/phase101_render_test.go: sanitizer, escaping, caps and view-model guard testsmodules/cabana/phase101_assets_test.go: tests of the asset route through a mux that mirrorsservice.mount, backed by the real SPA handlermodules/cabana/phase101_actions_test.go: the PostgreSQL action and partial route tests (external package)modules/boardwalk/boardwalk_test.go:TestPhase101BoardwalkExports../fonoteka.go/plugins/golem15/fonoteka/admin_phase101_albums_test.go:TestPhase101AlbumsExtensionadmin/src/app/pluginAssets.ts: rejects percent-encoded dot segments;modules/boardwalk/distrebuiltadmin/tests/{app,form,list}/*.test.ts: the new and extended suitesscripts/check-phase10.1.sh: the gate.scripts/check-phase10.sh: allow-list emptied10.1-SECURITY-REVIEW.md,10.1-VALIDATION.md, and the Phase 10deferred-items.mdentry marked resolved
Decisions Made
- The client asset check treats a segment as a dot segment after decoding
%2e, whatever its case. Browsers resolve%2e%2elike... - The gates allow-list nothing. Keeping the two parity names made
check-phase10.sh --gofail with exit 6, because both tests now pass. - Removal-check rows are
| RC-NN | T-10.1-XX | … |. The acceptance grep then counts exactly 23 threat rows, and--evidencecan still tie every high threat to a removal check. hygiene_101refusessendBeacon,WebSocketandEventSourcealongside the planned network, cookie and storage patterns. These are the other ways plugin JS could reach the network.- Action registration errors name the plugin and controller only. They come from Go code, not a YAML file, so the tests do not expect a file name there.
Deviations from Plan
Auto-fixed Issues
1. [Rule 2 - Security] Percent-encoded dot segments bypassed assetAllowed (T-10.1-13)
- Found during: Task 2 (the pluginAssets suite)
- Issue:
/admin-test/assets/%2e%2e/api/v1/x.jspassed the check, butnew URL()resolves it to/admin-test/api/v1/x.js, outside the asset prefix. - Fix: A segment counts as
.or..after lowercasing and replacing%2e. Test cases were added for the encoded, mixed-case and single-dot forms. The dist was rebuilt, andcheck-admin-dist.shpasses. - Files modified: admin/src/app/pluginAssets.ts, modules/boardwalk/dist/index.html, modules/boardwalk/dist/assets/index-*.js
- Verification: RED first (3 URL cases and the loadScript refusal failed), then 30/30 green. Full Vitest run: 677 pass.
- Committed in:
6b0ac15
2. [Rule 3 - Blocking] Stale parity allow-list made the Phase 10 gate fail
- Found during: Task 3 (
--gostage, detector exit 6) - Issue:
TestMigrateSeedsCanonicalGenresandTestSchemaMatchesPHPSnapshotpass since fonoteka.go21c0f12. The plan said to reuse the same allow-list, andcheck-phase10.sh --all, which the plan requires to pass, refused. - Fix:
KNOWN_APP_FAILURES=""in both gates, with the header comment rewritten. The Phase 10 deferred item is markedstatus: resolved. - Files modified: scripts/check-phase10.sh, scripts/check-phase10.1.sh, .planning/phases/10-admin-vue-spa/deferred-items.md
- Verification:
check-phase10.sh --allprints "phase10 all passed";check-phase10.1.sh --allprints "phase10.1 all passed" - Committed in:
9aeb0e1,02df0a8,bbceeb9
3. [Rule 1 - Test bug] Two removal checks initially survived
- Found during: Task 1 removal checks
- Issue: Disabling the model-type guard still returned 500, because the header template failed on the model. Removing the Discogs action permission went unnoticed, because the controller permission already refused the Genres-only admin.
- Fix: The guard test now renders the form partial, whose template reads
.Data.Name, a field the model also has. The acceptance test now asserts each Discogs action's ownPermissions. - Files modified: modules/cabana/phase101_render_test.go, ../fonoteka.go/.../admin_phase101_albums_test.go
- Verification: RC-11 and RC-18 now fail as required
- Committed in:
7eed4ac, c72c106
Total deviations: 3 auto-fixed (1 security, 1 blocking, 1 test bug) Impact on plan: The asset fix touches admin/src and the dist, which are outside the plan's file list. It is a one-function hardening of an existing mitigation with its own test. The allow-list change was needed for the plan's own acceptance command. No scope creep beyond that.
TDD Notes
This plan is test coverage for code that plans 10.1-01 to 10.1-03 had already shipped, so most suites passed on their first run by design. Their failing-when-broken evidence comes from the 23 removal checks in the security review, not from RED commits. The one behaviour change, the encoded dot segment, followed RED then GREEN: the new cases failed on their assertions before the fix. It shipped as a single fix commit, because a failing test commit would have broken the green-at-every-commit rule.
Issues Encountered
pluginAssetskeeps loaded script URLs and owned links for the lifetime of a test file. Two new ListView and FormView tests got cached promises until they switched to fresh URLs.- The admin cookie is only set by a login that sends
X-Requested-With. The external cabana test uses the Bearer JWT as thesummer_adminvalue, which is what that login stores. admin/src/api/schema.d.tschanged in Phase 10.1, but no app/form/list suite imports it. It is generated and type-only, and the Phase 10 hygiene rule exempts it too.tests/fixtures/typed.tsimports it.
Known Stubs
None added. The Discogs stubs from 10.1-03 are unchanged and still tracked in .planning/WINDOWS.md (Phase 14).
User Setup Required
None. No external service configuration required.
Next Phase Readiness
- Phase 10.1 is complete in code and evidence.
/gsd-verify-work 10.1should collect the real-browser human checks from 10.1-02 Task 3 and 10.1-03 Task 3. These are D6 above: CSP module loading, element upgrade, the 768px layout, and the Vite/assetsproxy. scripts/check-phase10.1.sh --allis the phase acceptance command. It runsnpm ciand every PostgreSQL suite in both repositories, and takes several minutes.
Self-Check: PASSED
- FOUND: modules/cabana/phase101_{schema,render,assets,actions}_test.go, modules/cabana/testdata/extension/assets/js/lookup.js, modules/cabana/testdata/extension/controllers/gadgets/_stats.htm, ../fonoteka.go/plugins/golem15/fonoteka/admin_phase101_albums_test.go, admin/tests/app/pluginAssets.test.ts, admin/tests/form/WidgetField.test.ts, admin/tests/form/PartialField.test.ts, admin/tests/list/PartialHost.test.ts, scripts/check-phase10.1.sh (mode 100755), 10.1-SECURITY-REVIEW.md
- FOUND commits:
7eed4ac,6b0ac15,11c4e54,9aeb0e1,02df0a8,bbceeb9(summercms.go); c72c106 (fonoteka.go) - Acceptance: review threat rows 23;
nyquist_compliant: true1; pending table rows 0; ADMIN-07 mentions 25;whenDefined|5000in WidgetField.test.ts 3;javascript:in PartialHost.test.ts 3; admin/package.json and package-lock.json unchanged sinceb2845e0 - Plan verification:
scripts/check-phase10.1.sh --all("phase10.1 all passed") andscripts/check-phase10.sh --all("phase10 all passed")
Phase: 10.1-runtime-admin-extension-point Completed: 2026-09-29