import express from "express"; import request from "supertest"; import { beforeEach, describe, expect, it, vi } from "vitest"; const mockInstanceSettingsService = vi.hoisted(() => ({ getGeneral: vi.fn(), getExperimental: vi.fn(), updateGeneral: vi.fn(), updateExperimental: vi.fn(), listCompanyIds: vi.fn(), })); const mockLogActivity = vi.hoisted(() => vi.fn()); function registerModuleMocks() { vi.doMock("../services/index.js", () => ({ instanceSettingsService: () => mockInstanceSettingsService, logActivity: mockLogActivity, })); } async function createApp(actor: any) { const [{ errorHandler }, { instanceSettingsRoutes }] = await Promise.all([ vi.importActual("../middleware/index.js"), vi.importActual("../routes/instance-settings.js"), ]); const app = express(); app.use(express.json()); app.use((req, _res, next) => { req.actor = actor; next(); }); app.use("/api", instanceSettingsRoutes({} as any)); app.use(errorHandler); return app; } describe("instance settings routes", () => { beforeEach(() => { vi.resetModules(); vi.doUnmock("../services/index.js"); vi.doUnmock("../routes/instance-settings.js"); vi.doUnmock("../routes/authz.js"); vi.doUnmock("../middleware/index.js"); registerModuleMocks(); vi.clearAllMocks(); mockInstanceSettingsService.getGeneral.mockReset(); mockInstanceSettingsService.getExperimental.mockReset(); mockInstanceSettingsService.updateGeneral.mockReset(); mockInstanceSettingsService.updateExperimental.mockReset(); mockInstanceSettingsService.listCompanyIds.mockReset(); mockLogActivity.mockReset(); mockInstanceSettingsService.getGeneral.mockResolvedValue({ censorUsernameInLogs: false, keyboardShortcuts: false, feedbackDataSharingPreference: "prompt", }); mockInstanceSettingsService.getExperimental.mockResolvedValue({ enableEnvironments: false, enableIsolatedWorkspaces: false, autoRestartDevServerWhenIdle: false, enableIssueGraphLivenessAutoRecovery: false, }); mockInstanceSettingsService.updateGeneral.mockResolvedValue({ id: "instance-settings-1", general: { censorUsernameInLogs: true, keyboardShortcuts: true, feedbackDataSharingPreference: "allowed", }, }); mockInstanceSettingsService.updateExperimental.mockResolvedValue({ id: "instance-settings-1", experimental: { enableEnvironments: true, enableIsolatedWorkspaces: true, autoRestartDevServerWhenIdle: false, enableIssueGraphLivenessAutoRecovery: false, }, }); mockInstanceSettingsService.listCompanyIds.mockResolvedValue(["company-1", "company-2"]); }); it("allows local board users to read and update experimental settings", async () => { const app = await createApp({ type: "board", userId: "local-board", source: "local_implicit", isInstanceAdmin: true, }); const getRes = await request(app).get("/api/instance/settings/experimental"); expect(getRes.status).toBe(200); expect(getRes.body).toEqual({ enableEnvironments: false, enableIsolatedWorkspaces: false, autoRestartDevServerWhenIdle: false, enableIssueGraphLivenessAutoRecovery: false, }); const patchRes = await request(app) .patch("/api/instance/settings/experimental") .send({ enableIsolatedWorkspaces: true }); expect(patchRes.status).toBe(200); expect(mockInstanceSettingsService.updateExperimental).toHaveBeenCalledWith({ enableIsolatedWorkspaces: true, }); expect(mockLogActivity).toHaveBeenCalledTimes(2); }, 10_000); it("allows local board users to update guarded dev-server auto-restart", async () => { const app = await createApp({ type: "board", userId: "local-board", source: "local_implicit", isInstanceAdmin: true, }); await request(app) .patch("/api/instance/settings/experimental") .send({ autoRestartDevServerWhenIdle: true }) .expect(200); expect( mockInstanceSettingsService.updateExperimental.mock.calls.some( ([patch]) => patch?.autoRestartDevServerWhenIdle === true, ), ).toBe(true); }); it("allows local board users to update issue graph liveness auto-recovery", async () => { const app = await createApp({ type: "board", userId: "local-board", source: "local_implicit", isInstanceAdmin: true, }); await request(app) .patch("/api/instance/settings/experimental") .send({ enableIssueGraphLivenessAutoRecovery: true }) .expect(200); expect(mockInstanceSettingsService.updateExperimental).toHaveBeenCalledWith({ enableIssueGraphLivenessAutoRecovery: true, }); }); it("allows local board users to update environment controls", async () => { const app = await createApp({ type: "board", userId: "local-board", source: "local_implicit", isInstanceAdmin: true, }); await request(app) .patch("/api/instance/settings/experimental") .send({ enableEnvironments: true }) .expect(200); expect(mockInstanceSettingsService.updateExperimental).toHaveBeenCalledWith({ enableEnvironments: true, }); }); it("allows local board users to read and update general settings", async () => { const app = await createApp({ type: "board", userId: "local-board", source: "local_implicit", isInstanceAdmin: true, }); const getRes = await request(app).get("/api/instance/settings/general"); expect(getRes.status).toBe(200); expect(getRes.body).toEqual({ censorUsernameInLogs: false, keyboardShortcuts: false, feedbackDataSharingPreference: "prompt", }); const patchRes = await request(app) .patch("/api/instance/settings/general") .send({ censorUsernameInLogs: true, keyboardShortcuts: true, feedbackDataSharingPreference: "allowed", }); expect(patchRes.status).toBe(200); expect(mockInstanceSettingsService.updateGeneral).toHaveBeenCalledWith({ censorUsernameInLogs: true, keyboardShortcuts: true, feedbackDataSharingPreference: "allowed", }); expect(mockLogActivity).toHaveBeenCalledTimes(2); }); it("allows non-admin board users to read general settings", async () => { const app = await createApp({ type: "board", userId: "user-1", source: "session", isInstanceAdmin: false, companyIds: ["company-1"], }); const res = await request(app).get("/api/instance/settings/general"); expect(res.status).toBe(200); expect(res.body).toEqual({ censorUsernameInLogs: false, keyboardShortcuts: false, feedbackDataSharingPreference: "prompt", }); }); it("rejects signed-in users without company access from reading general settings", async () => { const app = await createApp({ type: "board", userId: "user-2", source: "session", isInstanceAdmin: false, companyIds: [], memberships: [], }); const res = await request(app).get("/api/instance/settings/general"); expect(res.status).toBe(403); expect(mockInstanceSettingsService.getGeneral).not.toHaveBeenCalled(); }); it("rejects non-admin board users from updating general settings", async () => { const app = await createApp({ type: "board", userId: "user-1", source: "session", isInstanceAdmin: false, companyIds: ["company-1"], }); const res = await request(app) .patch("/api/instance/settings/general") .send({ censorUsernameInLogs: true, keyboardShortcuts: true }); expect(res.status).toBe(403); expect(mockInstanceSettingsService.updateGeneral).not.toHaveBeenCalled(); }); it("rejects agent callers", async () => { const app = await createApp({ type: "agent", agentId: "agent-1", companyId: "company-1", source: "agent_key", }); const res = await request(app) .patch("/api/instance/settings/general") .send({ feedbackDataSharingPreference: "not_allowed" }); expect(res.status).toBe(403); expect(mockInstanceSettingsService.updateGeneral).not.toHaveBeenCalled(); }); });