docs(phase-6): add validation strategy
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
---
|
||||
phase: 6
|
||||
slug: http-routing-auth-groups-and-rate-limiting
|
||||
status: draft
|
||||
nyquist_compliant: false
|
||||
wave_0_complete: false
|
||||
created: 2026-09-19
|
||||
---
|
||||
|
||||
# Phase 6 — 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 router, limiter, CORS and fetch-helper tests; `testcontainers-go` Postgres only where the `inv_token` guard and parity harness need real rows |
|
||||
| **Config file** | none — plain `func TestX(t *testing.T)`; parity `TestMain` in `../fonoteka.go/parity` is reused |
|
||||
| **Quick run command** | `go vet ./... && go test ./... -short` (run in the repo the task writes to) |
|
||||
| **Full suite command** | `go test ./... -race` in `summercms.go` and in `../fonoteka.go` |
|
||||
| **Estimated runtime** | ~20 s quick, ~120-180 s full |
|
||||
|
||||
---
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `go vet ./... && go test ./... -short`
|
||||
- **After every plan wave:** Run `go test ./...` in both repos
|
||||
- **Before `/gsd:verify-work`:** Full suite green in both repos with `-race`, parity harness green on genres under both auth groups, swag + `openapi-typescript` gate green
|
||||
- **Max feedback latency:** 120 seconds
|
||||
|
||||
---
|
||||
|
||||
## Per-Task Verification Map
|
||||
|
||||
Task IDs are filled in by the planner once PLAN.md files exist. Requirement-level map from 06-RESEARCH.md §Validation Architecture:
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
|
||||
| TBD | TBD | TBD | HTTP-03 | TBD | Same handler serves JWT `/_fonoteka/api/v1/genres` and personal-token `/api/v1/fonoteka/genres`; unknown and malformed ids both 404; groups mutually exclusive in the route table | integration | `go test ./... -run 'TestGenresSharedHandler|TestGroupsMutuallyExclusive'` (fonoteka.go) | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-04 | TBD | Five named buckets, inline `throttle:N,M`, stacked limiters; fixed-window Laravel semantics and headers; client IP only via trusted-proxy rule | unit + integration | `go test ./surf/... -run 'TestLimiter|TestClientIP'` | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-05 | TBD | Guard registry: `jwt` and `inv_token` resolve to one `bouncer.User(ctx)`; duplicate/unknown guard name fails boot; `inv.scope` 401/403 bodies exact | unit + integration | `go test ./bouncer/... -run TestGuardRegistry` | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-06 | TBD | `[]`, `+00:00`, tri-state `null`, omitted keys; raw OAuth group refuses house envelope/error middleware at registration, verified over the route table | unit + route-table | `go test ./surf/... -run 'TestResponseTypes|TestRawGroupExemption'` | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-07 | TBD | Fetch helper rejects non-allow-listed host and private/loopback IPs at dial time, https only, no redirects, byte cap while streaming, timeout | unit (httptest) | `go test ./... -run TestFetch` | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-08 | — | swag generates OpenAPI from handler annotations; `openapi-typescript` yields valid TS; drift check | build gate | phase gate script (exact command set at plan time) | ❌ W0 | ⬜ pending |
|
||||
| TBD | TBD | TBD | HTTP-09 | TBD | Path-scoped CORS equals `config/cors.php` (JWT group gets no CORS headers); `http.MaxBytesReader` body limits per group | integration | `go test ./surf/... -run 'TestCORS|TestBodyLimit'` | ❌ W0 | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
---
|
||||
|
||||
## Wave 0 Requirements
|
||||
|
||||
- [ ] `surf/limiter_test.go` — fixed-window Store semantics, named-bucket resolution, inline throttle keys, stacking
|
||||
- [ ] `bouncer/registry_test.go` — guard register / duplicate-fail / resolve-by-name
|
||||
- [ ] Fetch-helper package `fetch_test.go` — httptest servers for each typed failure reason
|
||||
- [ ] `surf/routetable_test.go` — raw-group middleware refusal at registration, route table contents
|
||||
- [ ] Existing infra reused: `surf` router tests, `../fonoteka.go/parity` TestMain and `seedHooks` (token insertion for the `inv_token` guard)
|
||||
- [ ] No new test framework
|
||||
|
||||
---
|
||||
|
||||
## Manual-Only Verifications
|
||||
|
||||
| Behavior | Requirement | Why Manual | Test Instructions |
|
||||
|----------|-------------|------------|-------------------|
|
||||
| Production `client_max_body_size` / `post_max_size` / `upload_max_filesize` values | HTTP-09 | The production nginx vhost and php.ini are operator-managed and not in any repo (06-RESEARCH.md A2) | Operator reads the values from the production host; they are recorded in config defaults and the test asserts the recorded numbers |
|
||||
|
||||
---
|
||||
|
||||
## 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 < 120s
|
||||
- [ ] `nyquist_compliant: true` set in frontmatter
|
||||
|
||||
**Approval:** pending
|
||||
Reference in New Issue
Block a user