Skip to content

Commit 8e97e44

Browse files
d-csTrigger.dev RepoOps
authored andcommitted
fix(webapp): preserve TLS hostname for snapshot Redis clusters
Preserve the configured TLS hostname when connecting the snapshot Redis cluster client to discovered nodes, without disabling certificate verification. Mono-RevId: e5da247d6c0c75ea6bb827c173c64872ef17ede9
1 parent 34ec7ee commit 8e97e44

2 files changed

Lines changed: 21 additions & 3 deletions

File tree

‎apps/webapp/app/v3/utils/snapshotStoreConnection.server.ts‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@ export function snapshotClusterOptions(endpoint: string) {
1818
return {
1919
nodes: [{ host: url.hostname, port: Number(url.port || 6379) }],
2020
failFast: true,
21-
clusterOptions: { lazyConnect: true, scaleReads: "master" as const },
21+
clusterOptions: {
22+
lazyConnect: true,
23+
scaleReads: "master" as const,
24+
...(url.protocol === "rediss:" && {
25+
// Preserve the seed hostname; AWS TLS certificates do not identify private IPs.
26+
dnsLookup: (address: string, callback: (err: Error | null, address: string) => void) =>
27+
callback(null, address),
28+
}),
29+
},
2230
redisOptions: {
2331
username: url.username ? decodeURIComponent(url.username) : undefined,
2432
password: url.password ? decodeURIComponent(url.password) : undefined,
25-
tls: url.protocol === "rediss:" ? {} : undefined,
33+
// Discovered nodes can be IPs too; verify them against the configured cluster hostname.
34+
tls: url.protocol === "rediss:" ? { servername: url.hostname } : undefined,
2635
commandTimeout: COMMAND_TIMEOUT_MS,
2736
connectTimeout: CONNECT_TIMEOUT_MS,
2837
},

‎apps/webapp/app/v3/utils/snapshotStoreMetrics.server.test.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@ test("snapshot metrics ignore raw organization IDs; the endpoint creates no eage
1414

1515
const options = snapshotClusterOptions("rediss://snapshot.example:6379");
1616
expect(options.failFast).toBe(true);
17-
expect(options.clusterOptions).toEqual({ lazyConnect: true, scaleReads: "master" });
17+
expect(options.clusterOptions).toMatchObject({ lazyConnect: true, scaleReads: "master" });
18+
expect(options.redisOptions.tls).toEqual({ servername: "snapshot.example" });
19+
expect(options.clusterOptions.dnsLookup).toBeTypeOf("function");
20+
options.clusterOptions.dnsLookup!("snapshot.example", (error, address) => {
21+
expect(error).toBeNull();
22+
expect(address).toBe("snapshot.example");
23+
});
24+
const plainOptions = snapshotClusterOptions("redis://127.0.0.1:1");
25+
expect(plainOptions.clusterOptions).toEqual({ lazyConnect: true, scaleReads: "master" });
26+
expect(plainOptions.redisOptions.tls).toBeUndefined();
1827
expect(options.redisOptions.commandTimeout).toBe(500);
1928
const connection = createSnapshotConnection("redis://127.0.0.1:1");
2029
connection.getStore(); // Registers local Lua commands only.

0 commit comments

Comments
 (0)