Tasks completed: 1/1 - Make fixed-window admission atomic and inline keys server-controlled SUMMARY: .planning/phases/06-http-routing-auth-groups-and-rate-limiting/06-07-SUMMARY.md
119 lines
5.5 KiB
Markdown
119 lines
5.5 KiB
Markdown
---
|
|
phase: 06-http-routing-auth-groups-and-rate-limiting
|
|
plan: 07
|
|
subsystem: api-security
|
|
tags: [rate-limiting, concurrency, middleware, trusted-proxy, tdd]
|
|
|
|
requires:
|
|
- phase: 06-http-routing-auth-groups-and-rate-limiting
|
|
provides: FixedWindowLimiter, MemoryStore, trusted-proxy ClientIP, named and inline throttle tests
|
|
provides:
|
|
- atomic fixed-window admission under concurrent HTTP traffic
|
|
- server-controlled domainless anonymous inline-throttle keys
|
|
- coordinated race regressions for store and middleware Max=1 contention
|
|
affects: [phase-07-user-plugin, phase-08-oauth, public-routes, personal-token-routes]
|
|
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- Store.Attempt owns expiry, threshold comparison, admitted increment, and retry duration under one lock
|
|
- anonymous inline throttles share inline:domainless|<trusted client IP> independently of Host and policy text
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- surf/limiter_store.go
|
|
- surf/limiter.go
|
|
- surf/limiter_test.go
|
|
- surf/limiter_coverage_test.go
|
|
|
|
key-decisions:
|
|
- "Replace the split Hit/TooManyAttempts/AvailableIn protocol with one atomic Store.Attempt operation"
|
|
- "Use one inline:domainless namespace plus trusted-proxy ClientIP for every anonymous inline throttle"
|
|
|
|
patterns-established:
|
|
- "Rate-limit admission returns allowed, post-admission attempts, and remaining window from one store operation"
|
|
- "Concurrency regressions coordinate 32 workers behind ready/start barriers and assert exact admissions"
|
|
|
|
requirements-completed: [HTTP-04]
|
|
|
|
duration: 12 min
|
|
completed: 2026-09-20
|
|
---
|
|
|
|
# Phase 6 Plan 07: Atomic limiter admission and stable inline keys Summary
|
|
|
|
**Atomic fixed-window admission now permits exactly one Max=1 contender while anonymous inline throttles share a server-controlled domainless/IP budget across Host and policy changes**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 12 min
|
|
- **Started:** 2026-09-20T14:57:45Z
|
|
- **Completed:** 2026-09-20T15:10:02Z
|
|
- **Tasks:** 1
|
|
- **Files modified:** 4
|
|
|
|
## Accomplishments
|
|
|
|
- Replaced the raceable check-then-increment store protocol with `Attempt`, which performs lazy expiry, threshold comparison, admitted increment, and retry calculation within one mutex critical section.
|
|
- Changed anonymous inline-throttle identity to `inline:domainless|<ClientIP>`, preventing Host rotation and inline parameter changes from creating fresh budgets while retaining per-principal `u:<id>` isolation.
|
|
- Added coordinated 32-worker store and middleware regressions proving one Max=1 admission, one protected-handler invocation, and 31 exact 429 responses under the race detector.
|
|
- Preserved first-hit-wins expiry, sweep cleanup, named-bucket stacking, headers, exact 429 body, and authenticated-user behavior.
|
|
|
|
## TDD Cycle
|
|
|
|
- **RED:** `5bcd7ba` added the atomic `Attempt` contract, coordinated concurrency tests, Host-rotation regression, and cross-inline-policy regression; the targeted suite failed because `MemoryStore.Attempt` did not exist.
|
|
- **GREEN:** `6852a8f` implemented atomic admission, wired middleware to one `Attempt` call, established the domainless key, and adapted legacy window/sweep coverage; all targeted and package tests passed under `-race`.
|
|
- **REFACTOR:** No separate refactor commit was needed; the GREEN implementation is the minimal store and middleware change required by the tests.
|
|
|
|
## Task Commits
|
|
|
|
Each TDD gate was committed atomically:
|
|
|
|
1. **RED: Add failing atomic limiter regressions** - `5bcd7ba` (test)
|
|
2. **GREEN: Make limiter admission atomic** - `6852a8f` (fix)
|
|
|
|
**Plan metadata:** (this commit)
|
|
|
|
## Files Created/Modified
|
|
|
|
- `surf/limiter_store.go` - Defines and implements the atomic `Store.Attempt` admission contract.
|
|
- `surf/limiter.go` - Uses one atomic admission result and domainless trusted-client inline keys.
|
|
- `surf/limiter_test.go` - Covers concurrent admission, exact middleware outcomes, Host rotation, cross-policy sharing, headers, stacking, and principal isolation.
|
|
- `surf/limiter_coverage_test.go` - Preserves sweep, retry-duration, and lazy-expiry coverage through the new API.
|
|
|
|
## Decisions Made
|
|
|
|
- The Store exposes only `Attempt`; no split check, increment, or availability operations remain available to production middleware.
|
|
- Every anonymous inline throttle shares the router-controlled `inline:domainless` namespace for a client IP, while authenticated requests continue to use `u:<principal id>`.
|
|
|
|
## Deviations from Plan
|
|
|
|
None - plan executed exactly as written.
|
|
|
|
## Issues Encountered
|
|
|
|
- The first repository-wide test run was sandbox-blocked from opening loopback listeners and reading VCS metadata in temporary build fixtures. The identical `go test ./... -short` command passed with the required sandbox permissions; targeted `surf` race tests were unaffected.
|
|
|
|
## User Setup Required
|
|
|
|
None - no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
|
|
- HTTP-04's concurrent-admission and attacker-controlled inline-key blockers are closed.
|
|
- Plan 06-08 can proceed with the remaining SSRF transition-address gap.
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- FOUND: `surf/limiter_store.go`, `surf/limiter.go`, `surf/limiter_test.go`, and `surf/limiter_coverage_test.go`
|
|
- FOUND: RED commit `5bcd7ba` and GREEN commit `6852a8f`
|
|
- PASS: targeted atomic/concurrent/inline/named limiter regressions under `-race`
|
|
- PASS: `go vet ./surf` and complete `go test ./surf -race -short`
|
|
- PASS: repository-wide `go vet ./...` and `go test ./... -short`
|
|
- PASS: production limiter contains one `Attempt(key, b.Max, b.Decay)` call and no split admission path or request Host input
|
|
|
|
---
|
|
*Phase: 06-http-routing-auth-groups-and-rate-limiting*
|
|
*Completed: 2026-09-20*
|