timmy-talking-turd/tests/rate-limiter.test.js
Timmy 517c8dbac3
Some checks failed
Quality gates / quality (pull_request) Failing after 2m39s
Harden image ingress: pinned runtime, header-bomb rejection, concurrency ceiling, bounded rate limiter, canonical data-URL/polyglot contract, 503-on-unavailable, body-read timeout
Closes the PR 63 hostile-review blockers:
1. Immutable pinned Python/Pillow runtime (TIMMY_PYTHON absolute, --verify-pin),
   deployment/runtime re-encode smoke gate in build_release + deploy_staging.
2. Header-only width/height/total-pixel/bomb rejection before full decode; proves
   6000x6000 and 12000x12000 stay resource bounded (RSS + address-space caps).
3. Fail-fast decoder concurrency ceiling; tests count actual spawned children.
4. Rate-limiter key cardinality hard-bounded under 20k+ unexpired identities,
   trusted-loopback-proxy identity, no spoofable forwarded headers, fixed-window
   boundary burst smoothed by two-window sliding count.
5. build_release explicitly syntax/gates every new JS module + Python re-encoder +
   production-runtime smoke; CI runs reencode-image test and the runtime pin smoke.
6. Robust polyglot contract via canonical container parsing; rejects uppercase/mixed
   script, appended HTML, ZIP local/EOCD and archive tails, data after canonical
   JPEG/PNG/WebP end; no naive compressed-byte scans (false-positive controls pass).
7. Canonical base64 data-URL grammar with byte-exact round trip; rejects missing/excess
   padding, whitespace/CRLF, malformed and noncanonical encodings; exact MIME policy.
8. Missing Pillow / runtime-unavailable maps to sanitized 503 + manual fallback.
9. Inbound body-read timeout and stop-on-oversize; preserves sanitized 413, base path,
   provider suppression, and temp cleanup; socket torn down on rejection.

Audited prior partial edits: reused the sound source modules, re-wired new tests into
the unit/syntax gates, fixed a non-canonical readJson that destroyed the socket before
delivering 413/408, and hardened test flakiness (port reuse, EPIPE, startup races).
2026-08-22 23:22:42 +00:00

32 lines
1.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { createRateLimiter } from '../src/rate-limiter.js';
test('rate limiter blocks after the configured burst and recovers once the window drains', () => {
const limiter = createRateLimiter({ windowMs: 1000, maxRequests: 3 });
const t0 = 1_000_000;
assert.equal(limiter.take('k', t0).allowed, true);
assert.equal(limiter.take('k', t0 + 1).allowed, true);
assert.equal(limiter.take('k', t0 + 2).allowed, true);
const blocked = limiter.take('k', t0 + 3);
assert.equal(blocked.allowed, false);
assert.ok(blocked.retryAfterMs > 0 && blocked.retryAfterMs <= 1000);
// Crossing the window boundary must NOT immediately grant a fresh full
// budget: that is the boundary-doubling burst. The trailing count decays, so
// capacity returns only once the earlier requests have actually aged out.
assert.equal(limiter.take('k', t0 + 1001).allowed, false,
'a 1ms boundary straddle must not reset the budget');
assert.equal(limiter.take('k', t0 + 2001).allowed, true,
'capacity must return once the window has genuinely drained');
});
test('rate limiter keys are isolated and never expose payload data', () => {
const limiter = createRateLimiter({ windowMs: 60_000, maxRequests: 1 });
assert.equal(limiter.take('a').allowed, true);
assert.equal(limiter.take('b').allowed, true);
const blocked = limiter.take('a');
assert.equal(blocked.allowed, false);
assert.doesNotMatch(blocked.reason, /image|base64|byte/i);
});