Skip to content

Commit 3a1f141

Browse files
committed
fix: encode uri component
1 parent 3a7bc0e commit 3a1f141

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

src/models/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ function buildDatabaseUrl(): string {
3232
throw new Error('Missing required DB environment variables.');
3333
}
3434

35-
return `postgres://${DB_USER}:${DB_PASSWORD ?? ''}@${DB_HOST}:${DB_PORT}/${DB_NAME}`;
35+
const encodedDbUser = encodeURIComponent(DB_USER);
36+
const encodedDbPassword = encodeURIComponent(DB_PASSWORD ?? '');
37+
38+
return `postgres://${encodedDbUser}:${encodedDbPassword}@${DB_HOST}:${DB_PORT}/${DB_NAME}`;
3639
}
3740

3841
export function getSequelize(): Sequelize {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
const sequelizeConstructor = vi.fn();
4+
5+
vi.mock('sequelize', () => ({
6+
Sequelize: sequelizeConstructor,
7+
}));
8+
9+
describe('getSequelize database URL building', () => {
10+
const originalEnv = process.env;
11+
12+
beforeEach(() => {
13+
vi.resetModules();
14+
vi.clearAllMocks();
15+
process.env = { ...originalEnv };
16+
delete process.env.DATABASE_URL;
17+
delete process.env.TEST_DB;
18+
process.env.NODE_ENV = 'development';
19+
process.env.DB_LOGGING = 'false';
20+
});
21+
22+
afterEach(() => {
23+
process.env = originalEnv;
24+
});
25+
26+
it('percent-encodes DB user and password when building fallback DATABASE_URL', async () => {
27+
process.env.DB_HOST = 'db.internal';
28+
process.env.DB_PORT = '5432';
29+
process.env.DB_NAME = 'auth_db';
30+
process.env.DB_USER = 'review@admin';
31+
process.env.DB_PASSWORD = 'p@ss:wo/rd?with#symbols';
32+
33+
const { getSequelize } = await import('../../../src/models/index.js');
34+
35+
getSequelize();
36+
37+
expect(sequelizeConstructor).toHaveBeenCalledWith(
38+
'postgres://review%40admin:p%40ss%3Awo%2Frd%3Fwith%23symbols@db.internal:5432/auth_db',
39+
expect.objectContaining({
40+
logging: false,
41+
}),
42+
);
43+
});
44+
45+
it('uses DATABASE_URL as-is when provided', async () => {
46+
process.env.DATABASE_URL = 'postgres://already:encoded@example.com:5432/auth_db';
47+
48+
const { getSequelize } = await import('../../../src/models/index.js');
49+
50+
getSequelize();
51+
52+
expect(sequelizeConstructor).toHaveBeenCalledWith(
53+
process.env.DATABASE_URL,
54+
expect.objectContaining({
55+
logging: false,
56+
}),
57+
);
58+
});
59+
});

0 commit comments

Comments
 (0)