fix(authz): preserve board org-membership check in assertBoardOrAgent

Greptile flagged that swapping `assertBoardOrgAccess` → `assertBoardOrAgent`
on `GET /api/plugins/tools` and `POST /api/plugins/tools/execute` silently
dropped the org-membership check for board actors. `GET /api/plugins/tools`
has no downstream company-scope guard, so memberless board users could
enumerate every installed plugin tool.

Tighten `assertBoardOrAgent` to delegate the board branch back to
`assertBoardOrgAccess` (require company membership or instance-admin) while
keeping the new agent-JWT path. Adds a regression test asserting a board
user with no memberships gets 403 on tool listing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin FoleyandPaperclip committed 2026-06-03 20:42:47 -07:00
1 parent 8582881777
commit 09a82c271e
2 files changed
+29 -2

No files matched your search

@@ -915,6 +915,28 @@ describe.sequential("plugin tool and bridge authz", () => {
// ─── Agent JWT tool execution (cherry-picked from #5549) ─────────────────────
it("rejects board users with no company memberships from listing plugin tools", async () => {
const listToolsForAgent = vi.fn(() => []);
const { app } = await createApp(
boardActor({ companyIds: [], isInstanceAdmin: false, source: "session" }),
{},
{
toolDeps: {
toolDispatcher: {
listToolsForAgent,
getTool: vi.fn(),
executeTool: vi.fn(),
},
},
},
);
const res = await request(app).get("/api/plugins/tools");
expect(res.status).toBe(403);
expect(listToolsForAgent).not.toHaveBeenCalled();
});
it("allows agent JWT to list available plugin tools", async () => {
const listToolsForAgent = vi.fn(() => []);
const { app } = await createApp(agentActor(), {}, {
+7 -2
View File
@@ -32,9 +32,14 @@ export function assertBoardOrgAccess(req: Request) {
}
export function assertBoardOrAgent(req: Request) {
if (req.actor.type !== "board" && req.actor.type !== "agent") {
throw forbidden("Board or agent access required");
if (req.actor.type === "agent") {
return;
}
if (req.actor.type === "board") {
assertBoardOrgAccess(req);
return;
}
throw forbidden("Board or agent access required");
}
export function assertInstanceAdmin(req: Request) {