Skip to content

feat(core): standalone checkRateLimitByIp primitive (matrix gap 12) - #112

Merged
rennf93 merged 1 commit into
masterfrom
feat/check-rate-limit-by-ip
Oct 7, 2026
Merged

rennf93 merged 1 commit into
masterfrom
feat/check-rate-limit-by-ip

Conversation

@rennf93

@rennf93 rennf93 commented Oct 7, 2026

Copy link
Copy Markdown
Member

Summary

Closes matrix gap 12 (A8 check_rate_limit_by_ip) - the TRAILING flag comes off. The full subsystem is ported, not a wrapper over the tiered check:

  • handlers/rate-limit-by-ip.ts: the dedicated LRU-capped sliding-window stores (byIpRequestTimestamps, byIpAutobanCounts exported like the reference module globals, evict-oldest with touch-refresh), the _lru_pop_or_create twin, _hash_identity_segment (sha256 hex endpoint suffix so raw path text never reaches Redis and distinct budgets cannot collide), the _redis_request_count twin (sha-less pipeline path: zadd/zremrangebyscore/zcard/expire), the _resolve_redis_rate_limit_failure twin (fail-closed raises GuardRedisError(503, 'Redis rate limiting unavailable'); fail-open warns once and falls back to the in-memory window), and _feed_rate_limit_autoban (dedicated counter, never merged with the pipeline's suspicious counts; resolved through the same pure resolveThresholdBan helper the middleware path uses; passive-mode suppression; already-banned short-circuit before the counter increments; rate_limit_exceeded reason; threatBanConfig rate_limit first, then the flat threshold).
  • Validation before any side effect: a rejected ip or an endpointPath containing : records no hit and feeds no ban; the rejection message redacts the path. To make the reference redaction contract real, the URL splitter now parses scheme-without-// inputs as scheme + path (the urlsplit semantics) and the path gets the pair-redaction pass (_redact_sensitive_path twin) - redactEndpointForDisplay('a:password=x') now answers a:password=[REDACTED] like the reference.
  • The default empty endpoint path shares the pipeline's global bucket bidirectionally (corpus-verified against live Redis); a non-empty path is a disjoint budget. Exported from the package root like the reference guard_core.utils surface.

Matrix rows flipped

  • A8 check_rate_limit_by_ip: MISSING -> FULL

Tests

38 tests in tests/test-handlers/rate-limit-by-ip.test.ts mirroring tests/test_core/test_check_rate_limit_by_ip.py and test_check_rate_limit_by_ip_autoban.py (live-Redis window enforcement, bidirectional bucket sharing, hashed-key isolation, redacted rejection message, LRU eviction arms, all autoban knob arms, counter isolation from the middleware, eviction arms).

Gates

  • turbo lint/build/test 10/10; coverage gates hold (100% statements/functions/lines, 97.04% branches); pnpm audit 0 unignored

Stacked on #111 (#109 -> #110 -> #111 -> this); merge in order.

@rennf93 rennf93 added area: handlers Touches packages/core/src/handlers/ area: utils Touches packages/core/src/utils.ts package: core Changes inside @guardcore/core tests Test suite changes (vitest) no-issue labels Oct 7, 2026
@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: b1519a44-c9d3-4d87-b787-6606cce11034
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added documentation Docs, README, CHANGELOG, governance files area: protocols Touches packages/core/src/protocols/ area: detection-engine Touches packages/core/src/detection-engine/ area: models Touches packages/core/src/models/ area: middleware-support Touches packages/core/src/middleware-support.ts or index.ts build Makefile / Docker / turbo / tsup / vitest / tsconfig area: core-subsystems and removed area: utils Touches packages/core/src/utils.ts labels Oct 7, 2026
Comment thread packages/core/tests/test-detection-engine/validation-cache.test.ts Fixed
Comment thread packages/core/tests/test-detection-engine/validation-cache.test.ts Fixed
@rennf93
rennf93 force-pushed the feat/check-rate-limit-by-ip branch 2 times, most recently from ecb6876 to d605a06 Compare October 7, 2026 18:46
The full request-free rate-limit subsystem ported from
check_rate_limit_by_ip (handlers/ratelimit_handler.py): dedicated
LRU-capped sliding-window counters, the sha256 _hash_identity_segment
endpoint suffix (raw path text never reaches Redis), fail-open/fail-closed
Redis resolution with GuardRedisError and the once-per-process in-memory
fallback warning, and the dedicated auto-ban feed resolved through the same
pure threshold helper the middleware path uses (threatBanConfig rate_limit
first, then the flat threshold; passive-mode suppression; no counting and no
re-ban once the ip is already banned; reason rate_limit_exceeded).

Input validation runs before any side effect: a rejected ip or an endpoint
path containing ':' records no hit and feeds no ban, with the rejection
message redacted. The default empty endpoint path shares the pipeline's
global bucket by design. Exported from the package root like the reference
guard_core.utils surface.

Also fixes the redaction module's URL splitter: a scheme without //
('a:password=x') now parses as scheme + path (the urlsplit semantics the
reference redactor relies on), and the path itself gets the pair redaction
pass (_redact_sensitive_path twin).
@rennf93
rennf93 force-pushed the feat/check-rate-limit-by-ip branch from d605a06 to 73df43a Compare October 7, 2026 19:04
@github-actions github-actions Bot removed area: protocols Touches packages/core/src/protocols/ area: detection-engine Touches packages/core/src/detection-engine/ area: models Touches packages/core/src/models/ build Makefile / Docker / turbo / tsup / vitest / tsconfig area: core-subsystems labels Oct 7, 2026
@rennf93
rennf93 merged commit 609dbce into master Oct 7, 2026
18 checks passed
@rennf93
rennf93 deleted the feat/check-rate-limit-by-ip branch October 7, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: handlers Touches packages/core/src/handlers/ area: middleware-support Touches packages/core/src/middleware-support.ts or index.ts documentation Docs, README, CHANGELOG, governance files no-issue package: core Changes inside @guardcore/core tests Test suite changes (vitest)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants