diff --git a/.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-10-SUMMARY.md b/.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-10-SUMMARY.md new file mode 100644 index 0000000..430e195 --- /dev/null +++ b/.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-10-SUMMARY.md @@ -0,0 +1,126 @@ +--- +phase: 06-http-routing-auth-groups-and-rate-limiting +plan: 10 +subsystem: auth +tags: [inv-scope, wire-json, php-parity, regression-tests] + +requires: + - phase: 06-http-routing-auth-groups-and-rate-limiting + provides: bouncer user/credential context, InvScope middleware, and shared wire.WriteJSON response conventions +provides: + - Byte-exact no-newline InvScope 401 and 403 denial responses + - Raw-byte regression assertions for missing-user, missing-scope, and wrong-credential denial paths +affects: [phase-06-verification, personal-token-routes, php-parity] + +tech-stack: + added: [] + patterns: + - Security denial middleware delegates JSON serialization to the shared PHP-compatible wire writer + - Wire-contract tests compare recorder bytes before decoding response shape + +key-files: + created: [] + modified: + - fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope.go + - fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope_test.go + +key-decisions: + - "Use wire.WriteJSON for both InvScope denial branches so authentication and scope errors share the established PHP-compatible no-newline serialization path" + - "Assert exact response bytes before secondary JSON shape checks; denial tests must never normalize whitespace" + +patterns-established: + - "TokenScope parity: status, Content-Type, and raw body bytes are one indivisible HTTP contract" + +requirements-completed: [HTTP-05, HTTP-06] + +duration: 3h 15m +completed: 2026-09-20 +--- + +# Phase 6 Plan 10: Exact InvScope Denial Bodies Summary + +**Personal-token scope denials now use `wire.WriteJSON`, producing PHP-byte-identical 401/403 bodies with raw-byte tests that fail on any newline or carriage return** + +## Performance + +- **Duration:** 3h 15m elapsed (including sandbox approval wait) +- **Started:** 2026-09-20T19:10:39Z +- **Completed:** 2026-09-20T22:26:07Z +- **Tasks:** 1 TDD task +- **Files modified:** 2 + +## Accomplishments + +- Replaced InvScope's local `json.Encoder` response helper with the framework's PHP-compatible `wire.WriteJSON` for both denial branches. +- Added exact raw-body assertions for the 401 missing-user and 403 missing-scope cases, including explicit final-`}` and no-CR/LF checks. +- Kept JSON decoding as a secondary envelope check and preserved the valid-scope next-handler and wrong-credential fail-closed behavior. + +## Task Commits + +Each TDD stage was committed atomically in the `fonoteka.go` repository: + +1. **RED: Assert exact InvScope denial bytes** - `bf3f8a0` (test) +2. **GREEN: Emit exact InvScope denial bodies** - `d43cc76` (fix) + +**Plan metadata:** (this commit) + +_No refactor commit was needed; the production change is the minimal shared-writer delegation._ + +## Files Created/Modified + +- `fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope.go` - delegates 401/403 serialization to `wire.WriteJSON` and removes the local encoder helper. +- `fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope_test.go` - compares exact recorder bodies, asserts JSON content type, forbids CR/LF bytes, and retains decoded shape checks. + +## Decisions Made + +- Both denial branches use the existing framework writer rather than duplicating newline trimming in app middleware. +- Exact bytes are asserted before JSON decoding so semantically valid but wire-incompatible whitespace cannot pass. + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +- The first sandboxed Go verification could not write to the shared Go build cache; rerunning the same bounded command with approved cache access passed. This was an execution-environment constraint, not a code defect. + +## User Setup Required + +None - no external service configuration required. + +## TDD Gate Compliance + +- RED: `bf3f8a0` demonstrated all three denial bodies carried the unwanted trailing newline. +- GREEN: `d43cc76` switched both branches to `wire.WriteJSON`; the exact tests passed under `-race`. +- REFACTOR: omitted because the minimal implementation already removed the redundant helper. + +## Verification + +- `go test ./plugins/golem15/fonoteka/middleware -run 'TestInvScope' -count=1 -race -short` - pass +- `go vet ./plugins/golem15/fonoteka/middleware` - pass +- `go test ./plugins/golem15/fonoteka/... -count=1 -short` - pass +- Acceptance greps - two `wire.WriteJSON` calls present; no `json.NewEncoder`, local `writeJSON`, `TrimSpace`, or normalized denial-body comparison. + +## Known Stubs + +None. + +## Threat Flags + +None. The change narrows an existing authentication response serialization path and introduces no new endpoint, trust boundary, file access, or schema surface. + +## Next Phase Readiness + +- The fourth authoritative Phase 6 verification gap is closed; Plan 06-11 can perform final coverage and phase closeout. +- No blockers. + +## Self-Check: PASSED + +- FOUND: both modified middleware files. +- FOUND: `bf3f8a0` and `d43cc76` in the `fonoteka.go` history. +- PASS: exact InvScope tests, middleware vet, and full Fonoteka plugin suite. +- PASS: no generated or untracked files in `fonoteka.go`; the pre-existing main-repo `go.work.sum` remains untouched. + +--- +*Phase: 06-http-routing-auth-groups-and-rate-limiting* +*Completed: 2026-09-20*