From be3182793d166c42464f5d677665889fc8fddb8b Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Wed, 3 Jun 2026 17:28:25 +0200 Subject: [PATCH] fix(agent-backups): validate agent ownership --- .../__tests__/agents-manager.events.test.ts | 35 +++++++++++++++++++ app/server/modules/agents/agents-manager.ts | 5 +++ 2 files changed, 40 insertions(+) diff --git a/app/server/modules/agents/__tests__/agents-manager.events.test.ts b/app/server/modules/agents/__tests__/agents-manager.events.test.ts index fd27d505..8dde6e71 100644 --- a/app/server/modules/agents/__tests__/agents-manager.events.test.ts +++ b/app/server/modules/agents/__tests__/agents-manager.events.test.ts @@ -106,6 +106,41 @@ test("backup progress is delivered to the running backup callback", async () => await stopAgentController(); }); +test("backup events from agents that do not own the active run are ignored", async () => { + resetAgentRuntime(); + controllerMock.sendBackup.mockImplementation(() => Effect.succeed(true)); + const { agentManager, startAgentController, stopAgentController } = await import("../agents-manager"); + + await startAgentController(); + const resultPromise = agentManager.runBackup("local", { + scheduleId: 42, + payload: backupPayload, + signal: new AbortController().signal, + onProgress: vi.fn(), + }); + + controllerMock.onEvent?.({ + type: "backup.completed", + agentId: "remote", + agentName: "Remote Agent", + payload: { jobId: "job-1", scheduleId: "schedule-1", exitCode: 0, result: null }, + }); + controllerMock.onEvent?.({ + type: "backup.completed", + agentId: "local", + agentName: "Local Agent", + payload: { jobId: "job-1", scheduleId: "schedule-1", exitCode: 0, result: null }, + }); + + await expect(resultPromise).resolves.toEqual({ + status: "completed", + exitCode: 0, + result: null, + warningDetails: null, + }); + await stopAgentController(); +}); + test("backup failed and cancelled events resolve the matching running backup", async () => { resetAgentRuntime(); controllerMock.sendBackup.mockImplementation(() => Effect.succeed(true)); diff --git a/app/server/modules/agents/agents-manager.ts b/app/server/modules/agents/agents-manager.ts index 0f1624a8..b8356c95 100644 --- a/app/server/modules/agents/agents-manager.ts +++ b/app/server/modules/agents/agents-manager.ts @@ -152,6 +152,11 @@ const getActiveBackupRun = (jobId: string, scheduleId: string, eventName: string return null; } + if (activeBackupRun.agentId !== agentId) { + logger.warn(`Ignoring ${eventName} for job ${jobId} from unexpected agent ${agentId}`); + return null; + } + return activeBackupRun; };