merge: remote-tracking branch 'origin/main' into feat/database-restores

This commit is contained in:
izzy
2025-11-24 16:52:41 +00:00
31 changed files with 795 additions and 355 deletions

View File

@@ -154,6 +154,39 @@ describe(BackupService.name, () => {
mocks.storage.createWriteStream.mockReturnValue(new PassThrough());
});
it('should sanitize DB_URL (remove uselibpqcompat) before calling pg_dumpall', async () => {
// create a service instance with a URL connection that includes libpqcompat
const dbUrl = 'postgresql://postgres:pwd@host:5432/immich?sslmode=require&uselibpqcompat=true';
const configMock = {
getEnv: () => ({ database: { config: { connectionType: 'url', url: dbUrl }, skipMigrations: false } }),
getWorker: () => ImmichWorker.Api,
isDev: () => false,
} as unknown as any;
({ sut, mocks } = newTestService(BackupService, { config: configMock }));
mocks.storage.readdir.mockResolvedValue([]);
mocks.process.createSpawnDuplexStream.mockImplementation(() => mockDuplex('command', 0, 'data', ''));
mocks.storage.rename.mockResolvedValue();
mocks.storage.unlink.mockResolvedValue();
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.backupEnabled);
mocks.storage.createWriteStream.mockReturnValue(new PassThrough());
mocks.database.getPostgresVersion.mockResolvedValue('14.10');
await sut.handleBackupDatabase();
expect(mocks.process.createSpawnDuplexStream).toHaveBeenCalled();
const call = mocks.process.createSpawnDuplexStream.mock.calls[0];
const args = call[1] as string[];
expect(args).toMatchInlineSnapshot(`
[
"postgresql://postgres:pwd@host:5432/immich?sslmode=require",
"--clean",
"--if-exists",
]
`);
});
it('should run a database backup successfully', async () => {
const result = await sut.handleBackupDatabase();
expect(result).toBe(JobStatus.Success);

View File

@@ -69,7 +69,11 @@ export async function buildPostgresLaunchArguments(
args.push('--dbname');
}
args.push(databaseConfig.url);
const url = new URL(databaseConfig.url);
// remove known bad parameters
url.searchParams.delete('uselibpqcompat');
args.push(url.toString());
} else {
args.push(
'--username',