Skip to content

fix(rate-limit): enforce bounded sliding-window quotas - #553

Open
greatest0fallt1me wants to merge 1 commit into
Agentpay-Org:mainfrom
greatest0fallt1me:fix/543-sliding-window-rate-limit
Open

fix(rate-limit): enforce bounded sliding-window quotas#553
greatest0fallt1me wants to merge 1 commit into
Agentpay-Org:mainfrom
greatest0fallt1me:fix/543-sliding-window-rate-limit

Conversation

@greatest0fallt1me

Copy link
Copy Markdown

Summary

  • Replace unbounded per-request timestamp arrays with bounded current/previous counter windows and a weighted rolling estimate.
  • Preserve per-tenant/API-key isolation for authenticated keys and trusted-IP fallback for anonymous traffic.
  • Reject unknown API-key values from becoming attacker-controlled identities, preventing bucket minting through header rotation.
  • Keep atomic same-process check-and-increment behavior, lazy expiry, live limits, and the existing 429/header/error contract.
  • Add focused boundary, rollover, expiry, isolation, legacy-state normalization, and bounded-memory tests.
  • Add the rate-limit security and operations note covering compatibility, proxy identity, rollout, and multi-process limitations.

Acceptance criteria

  • Requests are smoothed across a rolling window instead of reset at a fixed boundary.
  • Counters are isolated by authenticated API key/tenant or trusted client IP.
  • Atomic synchronous decisions prevent same-process overshoot; rejected requests do not increment.
  • 429, Retry-After, RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset remain structured and configurable.
  • Boundary bursts, independent tenants, expiry, forwarded-IP handling, and dependency-free in-memory operation are covered by tests.

Compatibility

The public response contract and configuration names remain unchanged. The internal in-memory value is normalized from legacy timestamp arrays once, so a rolling restart does not make old state fatal. This remains intentionally process-local; a horizontally scaled deployment needs a shared atomic edge/store implementation for a global quota.

Validation

  • npm run build — passed.
  • npm run lint — passed.
  • Focused limiter suites (ratelimit-sliding-window, ratelimit-prune, ratelimit-key, ratelimit-headers, ratelimit-config, middleware) — passed.
  • Changed-file Prettier checks — passed.
  • npm test — 444 tests passed; the repository-wide process-isolated run remains non-clean because of 9 pending event-loop cancellations plus unrelated pre-existing failures in services.test.ts (404 !== 200) and stats-breakdown.test.ts (400 !== 200). No limiter test failed.
  • npm run format — the repository baseline reports 39 pre-existing formatting violations; all changed files pass the equivalent targeted Prettier check.

Closes #543

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sliding-window rate limiter scoped per tenant/API key

1 participant