fix(orb): degrade rate-limit installation-identity resolution on a DB error instead of escaping uncaught#9227
Merged
Conversation
… error instead of escaping uncaught (#9225)
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
❌ 2 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
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.
Summary
The global rate-limit middleware (
app.use("*", ...)→enforceRateLimit→rateLimitIdentity→installationRateLimitIdentity) runs before every route handler, including/v1/orb/token,/v1/orb/relay/register, and/v1/orb/relay/pull. For those three paths it calledvalidateOrbRelayEnrollment(c.env, token)unguarded.If the DB throws inside that function (a real, if rare, failure mode), the rejection propagated uncaught through the middleware — which has no try/catch around
await enforceRateLimit(...)— producing a bare framework500upstream of the route handler. This silently defeated the route-level#4995fix, whose.catch(dbBrokerError)only guards the handler's own, LATER call to the same function.Verified live by instrumenting the existing
#4995regression tests intest/integration/orb-relay.test.ts— both currently pass onmain, but only because their assertions never inspected the actual failure mode. The real response was a bare 500 with the throw originating ininstallationRateLimitIdentity, not in the route handler:Fix:
.catch(() => null)around the call, degrading to IP-keyed rate limiting for that one request — exactly the fallback this function's own doc comment already promises ("falling back to IP-keying ... when [identity is] not resolvable -- a malformed payload, an unenrolled secret"), matching the siblingpeekWebhookInstallationIdbranch's existing best-effort pattern. A DB error is just another "not resolvable" case.Closes #9225
Validation
test/unit/auth.test.ts(co-located with the existing Move GitHub-webhook rate-limit buckets from IP-keyed to installation-keyed #4891/installation-keying suite): forces theorb_enrollmentslookup to reject, asserts all three affected paths resolve to IP-keying rather than rejecting.npx vitest run test/unit/auth.test.ts test/integration/orb-relay.test.ts— 133/133 pass, including both oforb-relay.test.ts's own pre-existing#4995regression tests, which now exercise the code path their names actually describe.npm run typecheck— clean.Safety
peekWebhookInstallationIdor the/v1/orb/relaysingle-tenant branch (out of scope, unaffected).