From 35601941461394e8752f78c8185c2cfec5f09877 Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 14 Aug 2026 08:29:24 +0000 Subject: [PATCH] fix(server): restrict state bundle exports to board Co-Authored-By: Paperclip --- server/src/__tests__/state-repo-routes.test.ts | 18 ++++++++++++++++-- server/src/routes/state-repo.ts | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/server/src/__tests__/state-repo-routes.test.ts b/server/src/__tests__/state-repo-routes.test.ts index d56b79df670..ccb7926d011 100644 --- a/server/src/__tests__/state-repo-routes.test.ts +++ b/server/src/__tests__/state-repo-routes.test.ts @@ -9,11 +9,16 @@ vi.mock("../services/activity-log.js", () => ({ logActivity: mockLogActivity })) const mockRemotes = vi.hoisted(() => ({ get: vi.fn(), set: vi.fn(), clear: vi.fn() })); vi.mock("../services/state-repo-remote.js", () => ({ stateRepoRemoteService: () => mockRemotes })); -function createApp(service: Record>) { +function createApp( + service: Record>, + actorType: "board" | "agent" = "board", +) { const app = express(); app.use(express.json()); app.use((req, _res, next) => { - req.actor = { type: "board", userId: "board-user", source: "local_implicit" }; + req.actor = actorType === "board" + ? { type: "board", userId: "board-user", source: "local_implicit" } + : { type: "agent", agentId: "agent-1", companyId: "company-1" }; next(); }); app.use("/api", stateRepoRoutes({} as never, service as never, "/tmp")); @@ -66,6 +71,15 @@ describe("state repo routes", () => { expect(service.health).toHaveBeenCalledWith("company-1"); }); + it("rejects agent credentials before exporting a company state bundle", async () => { + const service = { exportBundle: vi.fn() }; + const response = await request(createApp(service, "agent")) + .get("/api/companies/company-1/state-repo/bundle"); + + expect(response.status).toBe(403); + expect(service.exportBundle).not.toHaveBeenCalled(); + }); + it("tests the configured mirror", async () => { const service = { testMirror: vi.fn().mockResolvedValue(undefined), diff --git a/server/src/routes/state-repo.ts b/server/src/routes/state-repo.ts index 6dbe2386cdb..931ee09269d 100644 --- a/server/src/routes/state-repo.ts +++ b/server/src/routes/state-repo.ts @@ -87,6 +87,7 @@ export function stateRepoRoutes(db: Db, service: StateRepoService, markerDir: st router.get("/companies/:companyId/state-repo/bundle", async (req, res) => { const companyId = req.params.companyId as string; + assertBoard(req); assertCompanyAccess(req, companyId); await fs.mkdir(markerDir, { recursive: true }); const outputPath = path.join(markerDir, `state-repo-${companyId}-${Date.now()}.bundle`);