Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/thirty-turtles-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostream": patch
---

Fix Redis cache connection config to skip AUTH when `REDIS_PASSWORD` is unset
55 changes: 48 additions & 7 deletions src/cache/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,50 @@ import { createLogger } from '../factories/logger-factory'

const logger = createLogger('cache-client')

export const getCacheConfig = (): RedisClientOptions => ({
url: process.env.REDIS_URI
? process.env.REDIS_URI
: `redis://${process.env.REDIS_USER}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
password: process.env.REDIS_PASSWORD,
})
const redactRedisUrlCredentials = (url: string): string => {
try {
const parsedUrl = new URL(url)

if (!parsedUrl.username && !parsedUrl.password) {
return url
}

parsedUrl.username = parsedUrl.username ? '***' : ''
parsedUrl.password = parsedUrl.password ? '***' : ''

return parsedUrl.toString()
} catch {
return url
}
}

export const getCacheConfig = (): RedisClientOptions => {
const password = process.env.REDIS_PASSWORD

if (process.env.REDIS_URI) {
return {
url: process.env.REDIS_URI,
...(password ? { password } : {}),
}
}

const host = process.env.REDIS_HOST
const port = process.env.REDIS_PORT

if (password) {
const username = process.env.REDIS_USER ?? 'default'
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is default in the Redis documentation? how does this default user come to be?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


return {
url: `redis://${host}:${port}`,
username,
password,
}
}

return {
url: `redis://${host}:${port}`,
}
}

let instance: CacheClient | undefined = undefined

Expand All @@ -18,7 +56,10 @@ export const getCacheClient = (): CacheClient => {
const config = getCacheConfig()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { password: _, ...loggableConfig } = config
logger('config: %o', loggableConfig)
logger('config: %o', {
...loggableConfig,
...(loggableConfig.url ? { url: redactRedisUrlCredentials(loggableConfig.url) } : {}),
})
instance = createClient(config)
}

Expand Down
72 changes: 72 additions & 0 deletions test/unit/cache/client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expect } from 'chai'

import { getCacheConfig } from '../../../src/cache/client'

describe('getCacheConfig', () => {
const originalEnv = process.env

beforeEach(() => {
process.env = { ...originalEnv }
delete process.env.REDIS_URI
delete process.env.REDIS_USER
delete process.env.REDIS_PASSWORD
delete process.env.REDIS_HOST
delete process.env.REDIS_PORT
})

afterEach(() => {
process.env = originalEnv
})

it('builds unauthenticated redis url when REDIS_URI and REDIS_PASSWORD are unset', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
})
})

it('builds authenticated redis config when REDIS_PASSWORD is set', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'
process.env.REDIS_USER = 'default'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
username: 'default',
password: 'secret',
})
})

it('defaults REDIS_USER to default when REDIS_PASSWORD is set and REDIS_USER is unset', () => {
process.env.REDIS_HOST = 'localhost'
process.env.REDIS_PORT = '6379'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://localhost:6379',
username: 'default',
password: 'secret',
})
})

it('prefers REDIS_URI over host/port settings', () => {
process.env.REDIS_URI = 'redis://cache.internal:6380'
process.env.REDIS_PASSWORD = 'secret'

const config = getCacheConfig()

expect(config).to.deep.equal({
url: 'redis://cache.internal:6380',
password: 'secret',
})
})
})
Loading