Skip to content

orb(rate-limit): a DB error resolving installation identity escapes as a bare 500, upstream of the route's own #4995 fix #9225

Description

@JSONbored

Context

The global rate-limit middleware (app.use("*", ...) in src/api/routes.ts, calling enforceRateLimitrateLimitKeyrateLimitIdentityinstallationRateLimitIdentity in src/auth/rate-limit.ts) runs before every route handler, including /v1/orb/token, /v1/orb/relay/register, and /v1/orb/relay/pull.

For those three paths, installationRateLimitIdentity calls validateOrbRelayEnrollment(c.env, token) unguarded:

if (INSTALLATION_KEYED_ORB_BEARER_PATHS.has(path)) {
  const token = extractBearerToken(c.req.header("authorization"));
  if (!token) return null;
  const enrollment = await validateOrbRelayEnrollment(c.env, token);
  return "error" in enrollment ? null : `installation:${enrollment.installationId}`;
}

If the DB throws inside validateOrbRelayEnrollment (a real, if rare, failure mode — D1/Postgres unavailable), the rejection propagates uncaught through this middleware, which has no try/catch around the await enforceRateLimit(...) call. Hono's default error handling then returns a bare framework 500, before the route handler is ever reached — so the route's own careful #4995 fix (.catch(dbBrokerError) around its own call to the same function, returning a clean 503 broker_error) never runs. The route-level fix only guards against the SECOND, later call to validateOrbRelayEnrollment; the rate-limit middleware's earlier call is a completely separate, unguarded call site.

Verified live by instrumenting /v1/orb/relay/register and /v1/orb/relay/pull's own existing #4995 regression tests (both currently pass on main because their assertion window is a distraction — the actual response is a bare 500, and the stack trace lands in installationRateLimitIdentity, not in the route handler):

Error: db unavailable
    at Object.first (test/integration/orb-relay.test.ts:150:58)
    at validateOrbRelayEnrollment (src/orb/relay.ts:224:6)
    at installationRateLimitIdentity (src/auth/rate-limit.ts:240:24)
...
DEBUG STATUS 500 BODY Internal Server Error

The doc comment directly above INSTALLATION_KEYED_ORB_BEARER_PATHS already states the intended fallback behavior for exactly this situation — it just isn't implemented for the throw case: "prefer it when resolvable, falling back to IP-keying ... like every other route when it isn't -- a malformed payload, an unenrolled secret." A transient DB error is squarely another "not resolvable" case, and the sibling branch (peekWebhookInstallationId) already degrades this way via .catch(() => null).

This affects all three paths in INSTALLATION_KEYED_ORB_BEARER_PATHS: /v1/orb/token, /v1/orb/relay/register, /v1/orb/relay/pull.

Requirements

  1. installationRateLimitIdentity's INSTALLATION_KEYED_ORB_BEARER_PATHS branch must never let a rejected validateOrbRelayEnrollment promise escape — degrade to null (falls back to IP-keying downstream in rateLimitIdentity), matching peekWebhookInstallationId's existing best-effort pattern.
  2. A regression test asserting the previously-red path: with the DB forced to throw inside validateOrbRelayEnrollment's own query, a request to each of the three affected paths returns the route's OWN defined error response (the route-level 503 broker_error for the relay/token routes) — not a bare framework 500 — proving the middleware no longer intercepts the failure ahead of the handler.
  3. No change to the non-error resolution path: a valid/invalid/absent token must still resolve identity exactly as today.

Expected outcome

A DB hiccup during rate-limit identity resolution degrades to IP-keyed rate limiting for that one request, and the actual route handler (with its own well-tested error semantics) is what decides the response — never the rate-limit middleware.

Out of scope

Any change to peekWebhookInstallationId or the /v1/orb/relay single-tenant branch — both are unaffected by this bug.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.orbGittensory Orb related - maintainer self-hosting analytics.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions