fix(backups): prevent recursion in path that is backed up

This commit is contained in:
jubnl
2026-06-29 12:19:24 +02:00
parent 0631e34a79
commit 23b9be64de
2 changed files with 46 additions and 2 deletions
@@ -475,7 +475,7 @@ describe('BACKUP-036 createBackup', () => {
'**/*',
expect.objectContaining({
cwd: expect.stringContaining('uploads'),
ignore: ['photos/google/**', 'photos/trek/**'],
ignore: ['photos/google/**', 'photos/trek/**', 'backups/**', 'restore-*/**'],
}),
{ prefix: 'uploads' },
);
@@ -483,6 +483,38 @@ describe('BACKUP-036 createBackup', () => {
expect(archiverInstanceMock.directory).not.toHaveBeenCalled();
});
it('BACKUP-036h — never sweeps backups/ or restore-* into the archive (issue #1358)', async () => {
// Regression guard: when data and uploads map to the same directory, the
// uploads glob would otherwise pick up the backups/ dir and recursively
// embed every prior backup zip, compounding size without bound.
fsMock.existsSync.mockImplementation((p: string) => String(p).endsWith('uploads'));
fsMock.mkdirSync.mockReturnValue(undefined);
const writableEvents: Record<string, Function> = {};
const fakeWriteStream = {
on: vi.fn((event: string, cb: Function) => {
writableEvents[event] = cb;
}),
};
fsMock.createWriteStream.mockReturnValue(fakeWriteStream);
archiverInstanceMock.on.mockImplementation((_e: string, _cb: Function) => {});
archiverInstanceMock.pipe.mockReturnValue(undefined);
archiverInstanceMock.finalize.mockImplementation(() => {
if (writableEvents['close']) writableEvents['close']();
});
archiverMock.mockReturnValue(archiverInstanceMock);
fsMock.statSync.mockReturnValue({ size: 1024, birthtime: new Date('2026-04-06T12:00:00Z') });
await createBackup();
const globCall = archiverInstanceMock.glob.mock.calls.at(-1);
const ignore: string[] = globCall?.[1]?.ignore ?? [];
expect(ignore).toContain('backups/**');
expect(ignore).toContain('restore-*/**');
});
it('BACKUP-036f — bundles .encryption_key when present and ENCRYPTION_KEY env is unset', async () => {
const prevEnvKey = process.env.ENCRYPTION_KEY;
delete process.env.ENCRYPTION_KEY;