Files
summercms/.planning/phases/07-user-plugin-and-authentication/07-VALIDATION.md
2026-09-22 02:43:29 +02:00

6.0 KiB
Raw Blame History

phase, slug, status, nyquist_compliant, wave_0_complete, created
phase slug status nyquist_compliant wave_0_complete created
7 user-plugin-and-authentication draft false false 2026-09-22

Phase 7 — Validation Strategy

Per-phase validation contract for feedback sampling during execution.


Test Infrastructure

Property Value
Framework Go stdlib testing + testify (assert/require); net/http/httptest for handler, guard, limiter and locale tests; testcontainers-go v0.44.0 (modules/postgres) only where the throttle table, jti blacklist, token CRUD and parity replay need real rows; postcard memory driver for mail assertions
Config file none — plain func TestX(t *testing.T); testing.Short() gates container-backed tests (convention from lagoon/postgres_test.go, postcard/mailpit_test.go, plugins/golem15/user/updates/postgres_test.go); parity TestMain in ../fonoteka.go/parity is reused
Quick run command go vet ./... && go test ./... -short (run in the repo the task writes to: summercms.go or ../fonoteka.go)
Full suite command go test ./... -race in summercms.go and in ../fonoteka.go, plus summer parity:replay --manifest fonoteka.go/parity/manifest.yaml
Estimated runtime ~20 s quick, ~120–180 s full

Sampling Rate

  • After every task commit: Run go vet ./... && go test ./... -short in the repo the task touched
  • After every plan wave: Run go test ./... -race in both modules + summer parity:replay against the fixtures recorded so far
  • Before /gsd:verify-work: Full suite green in both modules, every D-11 fixture recorded and replayed
  • Max feedback latency: 30 s (quick command)

Per-Task Verification Map

Task ID Plan Wave Requirement Threat Ref Secure Behavior Test Type Automated Command File Exists Status
TBD TBD TBD AUTH-01 T-07-xx login/register/logout/fetch/refresh return PHP-identical status+body; tokens never read from URL/body unit + integration go test ./plugins/golem15/user/... -run TestApiController -short ❌ W0 ⬜ pending
TBD TBD TBD AUTH-01 T-07-xx sliding refresh accepts expired-but-within-refresh_ttl, rejects past it; logout blacklists forever; grace window honoured unit `go test ./bouncer/... -run 'TestRefresh TestBlacklist'` ❌ W0
TBD TBD TBD AUTH-01 T-07-xx $2y$ PHP hashes verify; lower-cost hash rehashed on login; per-(user,ip) throttle suspends after 5 unit + integration `go test ./plugins/golem15/user/... -run 'TestPassword TestThrottle' -short` ❌ W0
TBD TBD TBD AUTH-02 — fonoteka getApiArray listener adds organisation fields, must_change_password, preferred_locale; user never imports fonoteka unit (import-direction + payload) go test ./plugins/golem15/... -run TestGetApiArray ❌ W0 ⬜ pending
TBD TBD TBD AUTH-03 T-07-xx mint/list/revoke; MINTABLE_SCOPES allow-list rejects unknown scopes; InvScope 403s out-of-scope; plaintext returned once, sha256 at rest unit + integration go test ./plugins/golem15/fonoteka/... -run TestTokenApi -short ❌ W0 ⬜ pending
TBD TBD TBD AUTH-04 T-07-xx 423 on JWT-authed fonoteka surface while locked; me/locale and change-password reachable; route-table assertion integration go test ./... -run TestMustChangePasswordLock -short ❌ W0 ⬜ pending
TBD TBD TBD I18N-02 — preferred_locale → Accept-Language → app.locale, also while locked unit go test ./surf/... -run TestLocaleFromPrincipal ❌ W0 ⬜ pending
TBD TBD TBD AUTH-01..04 — every new /_user/api/v1, tokens, me/locale fixture replays byte-identical parity replay summer parity:replay --manifest fonoteka.go/parity/manifest.yaml ✅ harness / ❌ fixtures ⬜ pending

Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky. Task IDs are filled in by the planner once PLAN.md files exist.


Wave 0 Requirements

  • fonoteka.go/plugins/golem15/user/controllers/api_controller_test.go — stubs for AUTH-01
  • summercms.go/bouncer/mint_test.go, refresh_test.go, blacklist_test.go — AUTH-01 refresh/blacklist algorithm isolated from HTTP
  • fonoteka.go/plugins/golem15/fonoteka/controllers/api/token_api_controller_test.go — AUTH-03
  • summercms.go/surf/locale_from_principal_test.go — I18N-02
  • fonoteka.go/parity/fixtures/routes/_user-api-v1-*.yaml — recorded via tide against the isolated PHP instance (D-11/D-12)
  • Framework install: none — testcontainers-go and testify already present; only golang.org/x/crypto is promoted from indirect to direct

Manual-Only Verifications

Behavior Requirement Why Manual Test Instructions
Recording the new parity fixtures AUTH-01..04 Needs the isolated PHP instance and a private 0600 vars store; no live JWT in git Run tide record per D-11 against PHP with the DB-reading seed hook (D-12) for reset/activation codes; commit fixtures, not vars
PHP $2y$ hash cross-check (Assumption A1) AUTH-01 One-off cross-language confirmation php -r 'echo password_hash("secret", PASSWORD_BCRYPT);', paste into a Go test that calls bcrypt.CompareHashAndPassword; keep the test afterwards
Throttle path confirmation (Assumption A2) AUTH-01 Confirms JWTAuth::attempt() reaches Winter's Auth\Manager throttle Record one PHP fixture of 6 rapid failed logins and assert the suspended body appears on the 6th

Validation Sign-Off

  • All tasks have <automated> verify or Wave 0 dependencies
  • Sampling continuity: no 3 consecutive tasks without automated verify
  • Wave 0 covers all MISSING references
  • No watch-mode flags
  • Feedback latency < 30s
  • nyquist_compliant: true set in frontmatter

Approval: pending