import express from "express"; import request from "supertest"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { companySkillRoutes } from "../routes/company-skills.js"; import { errorHandler } from "../middleware/index.js"; const mockAgentService = vi.hoisted(() => ({ getById: vi.fn(), })); const mockAccessService = vi.hoisted(() => ({ canUser: vi.fn(), hasPermission: vi.fn(), })); const mockCompanySkillService = vi.hoisted(() => ({ importFromSource: vi.fn(), })); const mockLogActivity = vi.hoisted(() => vi.fn()); vi.mock("../services/index.js", () => ({ accessService: () => mockAccessService, agentService: () => mockAgentService, companySkillService: () => mockCompanySkillService, logActivity: mockLogActivity, })); function createApp(actor: Record) { const app = express(); app.use(express.json()); app.use((req, _res, next) => { (req as any).actor = actor; next(); }); app.use("/api", companySkillRoutes({} as any)); app.use(errorHandler); return app; } describe("company skill mutation permissions", () => { beforeEach(() => { vi.clearAllMocks(); mockCompanySkillService.importFromSource.mockResolvedValue({ imported: [], warnings: [], }); mockLogActivity.mockResolvedValue(undefined); mockAccessService.canUser.mockResolvedValue(true); mockAccessService.hasPermission.mockResolvedValue(false); }); it("allows local board operators to mutate company skills", async () => { const res = await request(createApp({ type: "board", userId: "local-board", companyIds: ["company-1"], source: "local_implicit", isInstanceAdmin: false, })) .post("/api/companies/company-1/skills/import") .send({ source: "https://github.com/vercel-labs/agent-browser" }); expect(res.status, JSON.stringify(res.body)).toBe(201); expect(mockCompanySkillService.importFromSource).toHaveBeenCalledWith( "company-1", "https://github.com/vercel-labs/agent-browser", ); }); it("blocks same-company agents without management permission from mutating company skills", async () => { mockAgentService.getById.mockResolvedValue({ id: "agent-1", companyId: "company-1", permissions: {}, }); const res = await request(createApp({ type: "agent", agentId: "agent-1", companyId: "company-1", runId: "run-1", })) .post("/api/companies/company-1/skills/import") .send({ source: "https://github.com/vercel-labs/agent-browser" }); expect(res.status, JSON.stringify(res.body)).toBe(403); expect(mockCompanySkillService.importFromSource).not.toHaveBeenCalled(); }); it("allows agents with canCreateAgents to mutate company skills", async () => { mockAgentService.getById.mockResolvedValue({ id: "agent-1", companyId: "company-1", permissions: { canCreateAgents: true }, }); const res = await request(createApp({ type: "agent", agentId: "agent-1", companyId: "company-1", runId: "run-1", })) .post("/api/companies/company-1/skills/import") .send({ source: "https://github.com/vercel-labs/agent-browser" }); expect(res.status, JSON.stringify(res.body)).toBe(201); expect(mockCompanySkillService.importFromSource).toHaveBeenCalledWith( "company-1", "https://github.com/vercel-labs/agent-browser", ); }); });