fix(telegram): bound the per-user API key cache - #13166
Merged
diegosouzapw merged 1 commit intoSep 11, 2026
Merged
diegosouzapw merged 1 commit into
diegosouzapw merged 1 commit into
Conversation
resolveUserApiKey() cached a plaintext API key per Telegram user id in a module-level Map with no cap, no TTL and no eviction. The webhook path of POST /api/telegram/update passes a caller-supplied chat id, so the key space is not bounded by the real user population and the map grew for the lifetime of the process (measured 254 bytes per distinct id, zero evictions). Route every write through a small LRU helper capped at 1000 entries. A cache hit re-inserts the id so an active user is not evicted by a burst of new ids. Refs diegosouzapw#13165
This was referenced Sep 10, 2026
Closed
diegosouzapw
merged commit Sep 11, 2026
30c96d4
into
diegosouzapw:release/v3.8.51
8 of 16 checks passed
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
`resolveUserApiKey()` keyed an uncapped Map on an id taken straight from the webhook body. The LRU's recency test is what keeps this from regressing into a clear-when-full cache. --- Validated in one consolidated worktree cut from `release/v3.8.51`, boarded together with the other 13 PRs of this batch — zero merge conflicts between them. - `typecheck:core` clean - complexity 2799 / baseline 3218 and cognitive-complexity 1265 / baseline 1437 — both under baseline - 71 focused assertions green across the 13 test files this batch adds or touches⚠️ base-red inherited: diegosouzapw#12732 — `Docs Gates (fast-path)`, `Merge integrity`, `No new ESLint warnings`, `Unit Tests fast-path` and `Fast Quality Gates` all reproduce on the pure `release/v3.8.51` tip (provider count 356 vs the 358 the modules define, SKILL.md drift, and `open-sse/utils/stream.ts` at 3115 > frozen 3098). None of them touch this diff. Thanks @anhtahaylove — the root-cause write-up, the measured before/after numbers and the red-before-green proof on every one of these made the batch reviewable as a unit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13165.
Problem
resolveUserApiKey()cached a plaintext OmniRoute API key per Telegram user id in a module-levelMapwith no cap, no TTL and no eviction path. Every distinct id ever seen was retained for the lifetime of the process.The id is not bounded by the real user population:
POST /api/telegram/updatereachesproxyChat(chat.chatId, ...)on the webhook path with the id taken straight from the request body, gated only byisTelegramEnabled().Measurement
Driving the real module with
getApiKeys/createApiKeystubbed (no DB access):Fix
All three write sites now go through a
rememberUserApiKey()helper backed by a 1000-entry LRU. Map insertion order is the recency order: a cache hit re-inserts the id, so an active user is not evicted by a burst of new ids, and the oldest entry is dropped once the cap is reached.Tests
tests/unit/telegram-keycache-bounded-13165.test.ts(node:test, matching this directory's runner):got 0 mint(s)), green after.Verified in both directions on this branch: with the patch stashed the first test fails, with it restored both pass.
tsc -p tsconfig.json --noEmitis clean.Note for maintainers (not addressed here)
A cache miss falls through to
createApiKey(), so a distinct id on the unauthenticated webhook path also mints and persists a new API key row, not just a memory entry. I did not change auth behaviour in a leak fix; flagged in #13165 for a separate decision.