Skip to content

v0.6.84: redis pub/sub SNI override, security hardening, copilot reads trimmed#4641

Merged
TheodoreSpeaks merged 3 commits into
mainfrom
staging
May 17, 2026
Merged

v0.6.84: redis pub/sub SNI override, security hardening, copilot reads trimmed#4641
TheodoreSpeaks merged 3 commits into
mainfrom
staging

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

@TheodoreSpeaks TheodoreSpeaks commented May 17, 2026

* fix(redis): apply TLS SNI override to pub/sub clients too

Pub/sub clients in lib/events/pubsub.ts build their own ioredis instances
directly via new Redis(redisUrl, ...) because pub/sub needs dedicated
connections (can't multiplex on the shared client from getRedisClient).
That path skipped the resolveTlsOptions helper added for trigger.dev's
PrivateLink VPCE IP, so every pub/sub channel hit
'Hostname/IP does not match certificate's altnames' on connect.

Export the helper as resolveRedisTlsOptions and use it from pubsub.ts.

* refactor(redis): share connection defaults via one helper

Extract keepAlive/connectTimeout/enableOfflineQueue + TLS SNI into a
single getRedisConnectionDefaults helper. Main client and pub/sub
clients both spread it; caller-specific retry/timeout policy stays
per-caller (pub/sub still needs maxRetriesPerRequest: null and a
different retry strategy for SUBSCRIBE).

* fix(pubsub): surface TLS config errors instead of silently degrading

resolveRedisTlsOptions (via getRedisConnectionDefaults) throws if
REDIS_TLS_SERVERNAME is missing for an IP-based rediss:// URL. Calling
it inside the constructor let createPubSubChannel's try/catch swallow
the error and fall back to in-process EventEmitter — silent
cross-replica pub/sub breakage in prod. Resolve defaults before the
try so config errors propagate; only catch genuine runtime construction
failures.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment May 17, 2026 6:10am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 17, 2026

PR Summary

Medium Risk
Touches Redis connection initialization and pub/sub transport selection; misconfiguration (missing REDIS_TLS_SERVERNAME with rediss:// IP) will now throw instead of silently falling back to local pub/sub, potentially changing runtime behavior.

Overview
Adds a shared getRedisConnectionDefaults() helper (including TLS SNI override when rediss:// targets an IP) and uses it for both the global Redis client and Redis-backed pub/sub connections.

Updates createPubSubChannel to resolve these defaults outside the try/catch so config errors (notably missing REDIS_TLS_SERVERNAME) surface rather than silently degrading to the in-process EventEmitter fallback.

Reviewed by Cursor Bugbot for commit 4945d55. Bugbot is set up for automated code reviews on this repo. Configure here.

… authz (#4639)

* fix(security): KB fileUrl LFI, MCP/Agiloft SSRF pinning, form OTP, KB authz

* fix(otp): don't leak caught error.message; fail-closed on DB retry exhaust

- Chat/form OTP routes: replace `error.message || fallback` with generic
  `Failed to process request` in 500 responses (logger still captures detail).
- otp.ts incrementOTPAttempts DB path: on MAX_RETRIES exhaustion, delete the
  verification row and return `'locked'` instead of trusting a possibly-
  undercounted final read.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(mcp): use undici fetch directly in pinned-fetch for typed dispatcher

Replace `globalThis.fetch` + double-cast with `undici.fetch` so the
`dispatcher` option is part of the real type contract. This guarantees
pinning won't silently break if a future runtime swaps the underlying
fetch implementation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(build): keep agiloft/grafana tool configs client-safe

Tool config files are statically reachable from the client bundle (via
tools/registry.ts → tools/{service}/index.ts). Importing
`@/lib/core/security/input-validation.server` from these files pulled
`node:dns/promises` into the Turbopack client bundle and broke the build.

Split agiloft utils into client-safe (`utils.ts`, plain fetch + sync
`validateExternalUrl`) and server-only (`utils.server.ts`, DNS-pinned
variants). Routes that need TOCTOU protection import the pinned helpers;
the executor-side tool path falls back to sync URL validation (matches
the supabase precedent and pre-PR baseline).

Grafana update tools likewise switch from `secureFetchWithValidation`
(server-only) to inline sync `validateExternalUrl` + plain fetch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): case-insensitive scheme checks for fileUrl

Boundary schema accepted uppercase schemes (e.g. HTTPS://, DATA:) via the
case-insensitive http regex, but the processor's case-sensitive
startsWith('data:') / startsWith('http') / startsWith('https://') checks
rejected them with a confusing "Unsupported fileUrl scheme" error.
Aligns processor checks to the schema using case-insensitive regex per
RFC 3986 §3.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(mcp): annotate undici/DOM type-bridge double-casts in pinned-fetch

Strict audit was failing on two new `as unknown as` casts in pinned-fetch.ts.
They bridge DOM `RequestInit`/`Response` ↔ undici equivalents (structurally
compatible at runtime since Node's global fetch is undici) and are required
to satisfy the FetchLike contract. Annotate so they count as documented
exemptions instead of new violations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR refactors shared Redis connection options (keepAlive, connectTimeout, enableOfflineQueue, and TLS SNI override) into a new exported getRedisConnectionDefaults() helper, then applies it to the pub/sub clients that previously lacked the TLS SNI override — the root cause of TLS failures when connecting to trigger.dev PrivateLink via an IP-addressed rediss:// endpoint.

  • redis.ts: Renames resolveTlsOptionsresolveRedisTlsOptions, extracts shared defaults into the new getRedisConnectionDefaults() export, and keeps the existing getRedisClient() wired through it.
  • pubsub.ts: Imports and passes connectionDefaults to RedisPubSubChannel, ensuring both the publish and subscribe connections use the TLS SNI override. The getRedisConnectionDefaults() call is deliberately placed outside the try/catch so a misconfigured REDIS_TLS_SERVERNAME surfaces as an error rather than silently degrading to the process-local EventEmitter and breaking cross-replica pub/sub.

Confidence Score: 5/5

Safe to merge — the change is a clean refactor plus a targeted bug fix with no unintended side effects.

Both files receive identical connection options to what they had before, with the addition of the TLS SNI override that was previously missing from the pub/sub clients. The error-surfacing behavior change in createPubSubChannel is intentional, well-commented, and consistent with how getRedisClient() already handled the same case before this PR.

No files require special attention; both changed files are straightforward and the logic is easy to follow.

Important Files Changed

Filename Overview
apps/sim/lib/core/config/redis.ts Extracts shared Redis connection defaults into getRedisConnectionDefaults() and renames the internal TLS resolver; no logic changes to existing behavior.
apps/sim/lib/events/pubsub.ts Applies shared connection defaults (including TLS SNI) to pub/sub clients; moves config resolution outside the try/catch intentionally to surface misconfiguration rather than silently falling back.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant createPubSubChannel
    participant getRedisConnectionDefaults
    participant resolveRedisTlsOptions
    participant RedisPubSubChannel
    participant Redis as ioredis (pub + sub)

    Caller->>createPubSubChannel: createPubSubChannel(config)
    createPubSubChannel->>getRedisConnectionDefaults: getRedisConnectionDefaults(redisUrl)
    getRedisConnectionDefaults->>resolveRedisTlsOptions: resolveRedisTlsOptions(url)
    alt rediss plus IP host plus REDIS_TLS_SERVERNAME set
        resolveRedisTlsOptions-->>getRedisConnectionDefaults: servername
        getRedisConnectionDefaults-->>createPubSubChannel: keepAlive connectTimeout enableOfflineQueue tls
    else rediss plus IP host plus REDIS_TLS_SERVERNAME missing
        resolveRedisTlsOptions-->>createPubSubChannel: throws Error surfaces to Caller
    else DNS host or non-TLS
        resolveRedisTlsOptions-->>getRedisConnectionDefaults: undefined
        getRedisConnectionDefaults-->>createPubSubChannel: keepAlive connectTimeout enableOfflineQueue
    end
    createPubSubChannel->>RedisPubSubChannel: new RedisPubSubChannel(redisUrl connectionDefaults config)
    RedisPubSubChannel->>Redis: new Redis pub connection with SNI
    RedisPubSubChannel->>Redis: new Redis sub connection with SNI
    Redis-->>RedisPubSubChannel: connections established TLS SNI applied
    RedisPubSubChannel-->>createPubSubChannel: instance
    createPubSubChannel-->>Caller: PubSubChannel
Loading

Reviews (1): Last reviewed commit: "fix(security): KB fileUrl LFI, MCP/Agilo..." | Re-trigger Greptile

@TheodoreSpeaks TheodoreSpeaks changed the title v0.6.84: redis pub/sub TLS SNI override for trigger.dev PrivateLink v0.6.84: redis pub/sub SNI override, security hardening, copilot reads trimmed May 17, 2026
@TheodoreSpeaks TheodoreSpeaks merged commit 11bcb8f into main May 17, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants