docs(06-06): complete personal-token rate-limit gap plan
This commit is contained in:
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
phase: 06-http-routing-auth-groups-and-rate-limiting
|
||||||
|
plan: 06
|
||||||
|
subsystem: api-security
|
||||||
|
tags: [rate-limiting, middleware-order, personal-token, security-review, httptest]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 06-http-routing-auth-groups-and-rate-limiting
|
||||||
|
provides: inv_token guard, InvScope, FixedWindowLimiter, fonoteka-api-token bucket, assembled route tests
|
||||||
|
provides:
|
||||||
|
- personal-token route order that rate-limits unauthenticated deny traffic before InvScope
|
||||||
|
- assembled-router proof of 401 through request 60 and exact 429 on request 61
|
||||||
|
- T-06-21 and T-06-22 security evidence with 21 threats closed and zero open
|
||||||
|
affects: [phase-07-user-plugin, phase-08-oauth, personal-token-routes, security-review]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- personal-token middleware order is inv_token -> throttle:<bucket> -> inv.scope:<scope>
|
||||||
|
- deny-path limiter regressions use one fresh surf.Assemble handler and stable RemoteAddr
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created: []
|
||||||
|
modified:
|
||||||
|
- plugins/golem15/fonoteka/routes.go
|
||||||
|
- plugins/golem15/fonoteka/routes_isolation_test.go
|
||||||
|
- .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Keep inv_token outermost so valid credentials populate bouncer.Credential before the limiter selects tok:<id>"
|
||||||
|
- "Place throttle before InvScope so missing and invalid credentials consume the per-IP deny-path budget"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Any live route combining inv_token, a named throttle, and inv.scope declares them in that exact source order"
|
||||||
|
- "Rate-limit exhaustion tests exercise the real plugin set and production route rather than hand-composed middleware"
|
||||||
|
|
||||||
|
requirements-completed: [HTTP-04]
|
||||||
|
|
||||||
|
duration: 1h 29m
|
||||||
|
completed: 2026-09-20
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 6 Plan 06: Personal-token deny-path rate-limit gap closure Summary
|
||||||
|
|
||||||
|
**Personal-token genres now preserves per-token keying while bounding unauthenticated 401 traffic at 60 requests per minute, with assembled-route and security-review evidence**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 1h 29m
|
||||||
|
- **Started:** 2026-09-20T10:01:25Z
|
||||||
|
- **Completed:** 2026-09-20T11:30:57Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 3
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Reordered the live personal-token genres middleware to `inv_token`, `throttle:fonoteka-api-token`, `inv.scope:read`, preserving valid-token `tok:<id>` keys while limiting unauthenticated fallback traffic by client IP.
|
||||||
|
- Added `TestPersonalTokenGenresUnauthenticatedRequestsAreRateLimited`, which drives 61 same-IP requests through one fresh handler returned by `surf.Assemble`: requests 1-60 retain the PHP-compatible 401 body and request 61 receives the exact 429 body and exhausted-limit headers.
|
||||||
|
- Extended `06-SECURITY-REVIEW.md` through Plan 06-06 with T-06-21/T-06-22, 21 closed threats, zero open, and no new accepted risk.
|
||||||
|
- Passed the targeted regression, `go vet ./...`, and repository-wide `go test ./... -short` in `fonoteka.go`.
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: Repair personal-token middleware order and prove deny-path throttling** - `33f721d` (fix, fonoteka.go)
|
||||||
|
2. **Task 2: Extend the Phase 6 security review through gap closure** - `3423da2` (docs, summercms.go)
|
||||||
|
|
||||||
|
**Plan metadata:** (this commit)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `plugins/golem15/fonoteka/routes.go` - Declares the live personal-token middleware in credential, limiter, then scope order.
|
||||||
|
- `plugins/golem15/fonoteka/routes_isolation_test.go` - Proves the assembled production route returns 401 through request 60 and exact 429 on request 61.
|
||||||
|
- `.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md` - Maps T-06-21/T-06-22 to the runtime-order invariant and regression evidence.
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- `inv_token` remains before the limiter so valid credentials populate `bouncer.Credential` before the bucket closure resolves `tok:<id>`.
|
||||||
|
- `throttle:fonoteka-api-token` remains before `inv.scope:read` so missing and invalid credentials consume the per-IP fallback bucket before the scope gate returns 401.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
- The delegated executor stopped returning progress after partially editing the sibling `fonoteka.go` repository. After the configured stall threshold and user-approved recovery, execution switched inline; the partial diff was inspected, retained, validated, and committed without duplication.
|
||||||
|
- The sandboxed full test run could not access the Docker daemon used by the parity harness. The same required command passed after rerunning with approved Docker access.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- HTTP-04's verification blocker and code-review CR-01 are directly closed.
|
||||||
|
- Phase 6 is ready for re-verification; no Plan 06-06 implementation blockers remain.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- FOUND: `../fonoteka.go/plugins/golem15/fonoteka/routes.go`
|
||||||
|
- FOUND: `../fonoteka.go/plugins/golem15/fonoteka/routes_isolation_test.go`
|
||||||
|
- FOUND: `.planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-SECURITY-REVIEW.md`
|
||||||
|
- FOUND: `33f721d` in `fonoteka.go`
|
||||||
|
- FOUND: `3423da2` in `summercms.go`
|
||||||
|
- PASS: targeted assembled-router regression
|
||||||
|
- PASS: `go vet ./...` in `fonoteka.go`
|
||||||
|
- PASS: `go test ./... -short` in `fonoteka.go`
|
||||||
|
- PASS: T-06-21/T-06-22 evidence and audit total 21 closed / 0 open
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 06-http-routing-auth-groups-and-rate-limiting*
|
||||||
|
*Completed: 2026-09-20*
|
||||||
Reference in New Issue
Block a user