forked from farhoodlabs/paperclip
test(skills): cover PAT import, skill auth, and scan-projects routes
- importFromSource is invoked with the PAT when one is supplied in the body - PATCH /skills/:id/auth updates and clears tokens, with matching activity log entries - POST /skills/scan-projects is reachable to agents that hold canCreateAgents - Update existing import-permission assertion to include the new authToken arg
This commit is contained in:
@@ -14,6 +14,8 @@ const mockAccessService = vi.hoisted(() => ({
|
|||||||
const mockCompanySkillService = vi.hoisted(() => ({
|
const mockCompanySkillService = vi.hoisted(() => ({
|
||||||
importFromSource: vi.fn(),
|
importFromSource: vi.fn(),
|
||||||
deleteSkill: vi.fn(),
|
deleteSkill: vi.fn(),
|
||||||
|
updateSkillAuth: vi.fn(),
|
||||||
|
scanProjectWorkspaces: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockLogActivity = vi.hoisted(() => vi.fn());
|
const mockLogActivity = vi.hoisted(() => vi.fn());
|
||||||
@@ -97,6 +99,15 @@ describe("company skill mutation permissions", () => {
|
|||||||
slug: "find-skills",
|
slug: "find-skills",
|
||||||
name: "Find Skills",
|
name: "Find Skills",
|
||||||
});
|
});
|
||||||
|
mockCompanySkillService.scanProjectWorkspaces.mockResolvedValue({
|
||||||
|
scannedProjects: 1,
|
||||||
|
scannedWorkspaces: 2,
|
||||||
|
discovered: [],
|
||||||
|
imported: [],
|
||||||
|
updated: [],
|
||||||
|
conflicts: [],
|
||||||
|
warnings: [],
|
||||||
|
});
|
||||||
mockLogActivity.mockResolvedValue(undefined);
|
mockLogActivity.mockResolvedValue(undefined);
|
||||||
mockAccessService.canUser.mockResolvedValue(true);
|
mockAccessService.canUser.mockResolvedValue(true);
|
||||||
mockAccessService.hasPermission.mockResolvedValue(false);
|
mockAccessService.hasPermission.mockResolvedValue(false);
|
||||||
@@ -294,9 +305,120 @@ describe("company skill mutation permissions", () => {
|
|||||||
expect(mockCompanySkillService.importFromSource).toHaveBeenCalledWith(
|
expect(mockCompanySkillService.importFromSource).toHaveBeenCalledWith(
|
||||||
"company-1",
|
"company-1",
|
||||||
"https://github.com/vercel-labs/agent-browser",
|
"https://github.com/vercel-labs/agent-browser",
|
||||||
|
undefined,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("passes a PAT through skill import requests", async () => {
|
||||||
|
const res = await request(await 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",
|
||||||
|
authToken: "ghp_private_token",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status, JSON.stringify(res.body)).toBe(201);
|
||||||
|
expect(mockCompanySkillService.importFromSource).toHaveBeenCalledWith(
|
||||||
|
"company-1",
|
||||||
|
"https://github.com/vercel-labs/agent-browser",
|
||||||
|
"ghp_private_token",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates a skill auth token", async () => {
|
||||||
|
mockCompanySkillService.updateSkillAuth.mockResolvedValue({
|
||||||
|
id: "skill-1",
|
||||||
|
slug: "find-skills",
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await request(await createApp({
|
||||||
|
type: "board",
|
||||||
|
userId: "local-board",
|
||||||
|
companyIds: ["company-1"],
|
||||||
|
source: "local_implicit",
|
||||||
|
isInstanceAdmin: false,
|
||||||
|
}))
|
||||||
|
.patch("/api/companies/company-1/skills/skill-1/auth")
|
||||||
|
.send({ authToken: "ghp_private_token" });
|
||||||
|
|
||||||
|
expect(res.status, JSON.stringify(res.body)).toBe(200);
|
||||||
|
expect(mockCompanySkillService.updateSkillAuth).toHaveBeenCalledWith(
|
||||||
|
"company-1",
|
||||||
|
"skill-1",
|
||||||
|
"ghp_private_token",
|
||||||
|
);
|
||||||
|
expect(mockLogActivity).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.objectContaining({
|
||||||
|
companyId: "company-1",
|
||||||
|
action: "company.skill_auth_updated",
|
||||||
|
entityType: "company_skill",
|
||||||
|
entityId: "skill-1",
|
||||||
|
details: { slug: "find-skills" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("clears a skill auth token", async () => {
|
||||||
|
mockCompanySkillService.updateSkillAuth.mockResolvedValue({
|
||||||
|
id: "skill-1",
|
||||||
|
slug: "find-skills",
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await request(await createApp({
|
||||||
|
type: "board",
|
||||||
|
userId: "local-board",
|
||||||
|
companyIds: ["company-1"],
|
||||||
|
source: "local_implicit",
|
||||||
|
isInstanceAdmin: false,
|
||||||
|
}))
|
||||||
|
.patch("/api/companies/company-1/skills/skill-1/auth")
|
||||||
|
.send({ authToken: null });
|
||||||
|
|
||||||
|
expect(res.status, JSON.stringify(res.body)).toBe(200);
|
||||||
|
expect(mockCompanySkillService.updateSkillAuth).toHaveBeenCalledWith(
|
||||||
|
"company-1",
|
||||||
|
"skill-1",
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
expect(mockLogActivity).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.objectContaining({
|
||||||
|
companyId: "company-1",
|
||||||
|
action: "company.skill_auth_removed",
|
||||||
|
entityType: "company_skill",
|
||||||
|
entityId: "skill-1",
|
||||||
|
details: { slug: "find-skills" },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows agents with canCreateAgents to scan project workspaces", async () => {
|
||||||
|
mockAgentService.getById.mockResolvedValue({
|
||||||
|
id: "agent-1",
|
||||||
|
companyId: "company-1",
|
||||||
|
permissions: { canCreateAgents: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await request(await createApp({
|
||||||
|
type: "agent",
|
||||||
|
agentId: "agent-1",
|
||||||
|
companyId: "company-1",
|
||||||
|
runId: "run-1",
|
||||||
|
}))
|
||||||
|
.post("/api/companies/company-1/skills/scan-projects")
|
||||||
|
.send({});
|
||||||
|
|
||||||
|
expect(res.status, JSON.stringify(res.body)).toBe(200);
|
||||||
|
expect(mockCompanySkillService.scanProjectWorkspaces).toHaveBeenCalledWith("company-1", {});
|
||||||
|
});
|
||||||
|
|
||||||
it("returns a blocking error when attempting to delete a skill still used by agents", async () => {
|
it("returns a blocking error when attempting to delete a skill still used by agents", async () => {
|
||||||
const { unprocessable } = await import("../errors.js");
|
const { unprocessable } = await import("../errors.js");
|
||||||
mockCompanySkillService.deleteSkill.mockImplementationOnce(async () => {
|
mockCompanySkillService.deleteSkill.mockImplementationOnce(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user