fix: use resolved ipc dirs for recovery flow

This commit is contained in:
Eyejoker
2026-03-23 07:18:47 +09:00
parent 9def49f7fb
commit f5eae07657
6 changed files with 35 additions and 13 deletions

View File

@@ -53,7 +53,9 @@ describe('group folder validation', () => {
it('throws for unsafe folder names', () => {
expect(() => resolveGroupFolderPath('../../etc')).toThrow();
expect(() => resolveGroupIpcPath('/tmp')).toThrow();
expect(() => resolveTaskRuntimeIpcPath('family-chat', '../../etc')).toThrow();
expect(() =>
resolveTaskRuntimeIpcPath('family-chat', '../../etc'),
).toThrow();
expect(() => resolveTaskSessionsPath('family-chat', '/tmp')).toThrow();
});
});

View File

@@ -29,7 +29,11 @@ function assertValidRuntimeSegment(segment: string, label: string): void {
if (!RUNTIME_SEGMENT_PATTERN.test(segment)) {
throw new Error(`Invalid ${label} "${segment}"`);
}
if (segment.includes('/') || segment.includes('\\') || segment.includes('..')) {
if (
segment.includes('/') ||
segment.includes('\\') ||
segment.includes('..')
) {
throw new Error(`Invalid ${label} "${segment}"`);
}
}
@@ -76,7 +80,10 @@ export function resolveTaskRuntimeIpcPath(
return ipcPath;
}
export function resolveTaskSessionsPath(folder: string, taskId: string): string {
export function resolveTaskSessionsPath(
folder: string,
taskId: string,
): string {
assertValidGroupFolder(folder);
assertValidRuntimeSegment(taskId, 'task ID');
const sessionsBaseDir = path.resolve(DATA_DIR, 'sessions');

View File

@@ -77,10 +77,9 @@ describe('GroupQueue', () => {
await vi.advanceTimersByTimeAsync(10);
expect(queue.sendMessage('group1@g.us', '후속 메시지')).toBe(true);
expect(fs.mkdirSync).toHaveBeenCalledWith(
`${ipcDir}/input`,
{ recursive: true },
);
expect(fs.mkdirSync).toHaveBeenCalledWith(`${ipcDir}/input`, {
recursive: true,
});
expect(fs.writeFileSync).toHaveBeenCalled();
expect(fs.renameSync).toHaveBeenCalled();

View File

@@ -39,7 +39,7 @@ import {
} from './db.js';
import { composeDashboardContent } from './dashboard-render.js';
import { GroupQueue } from './group-queue.js';
import { resolveGroupFolderPath } from './group-folder.js';
import { resolveGroupFolderPath, resolveGroupIpcPath } from './group-folder.js';
import { startIpcWatcher } from './ipc.js';
import { findChannel, formatOutbound } from './router.js';
import {
@@ -428,7 +428,10 @@ async function main(): Promise<void> {
restartContext,
registeredGroups,
)) {
queue.enqueueMessageCheck(candidate.chatJid, candidate.groupFolder);
queue.enqueueMessageCheck(
candidate.chatJid,
resolveGroupIpcPath(candidate.groupFolder),
);
logger.info(
{
chatJid: candidate.chatJid,

View File

@@ -533,7 +533,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
continue;
}
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
deps.queue.enqueueMessageCheck(
chatJid,
resolveGroupIpcPath(group.folder),
);
}
}
} catch (err) {
@@ -555,7 +558,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
{ chatJid, group: group.name, workItemId: openWorkItem.id },
'Recovery: found open work item awaiting delivery',
);
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
deps.queue.enqueueMessageCheck(
chatJid,
resolveGroupIpcPath(group.folder),
);
continue;
}
@@ -576,7 +582,10 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
{ group: group.name, pendingCount: pending.length },
'Recovery: found unprocessed messages',
);
deps.queue.enqueueMessageCheck(chatJid, resolveGroupIpcPath(group.folder));
deps.queue.enqueueMessageCheck(
chatJid,
resolveGroupIpcPath(group.folder),
);
} else if (rawPending.length > 0) {
const endSeq = rawPending[rawPending.length - 1].seq;
if (endSeq != null) {

View File

@@ -10,7 +10,9 @@ const { runAgentProcessMock, writeTasksSnapshotMock } = vi.hoisted(() => ({
vi.mock('./agent-runner.js', async () => {
const actual =
await vi.importActual<typeof import('./agent-runner.js')>('./agent-runner.js');
await vi.importActual<typeof import('./agent-runner.js')>(
'./agent-runner.js',
);
return {
...actual,
runAgentProcess: runAgentProcessMock,