diff --git a/server/src/__tests__/connection-management.integration.test.ts b/server/src/__tests__/connection-management.integration.test.ts index 78140ec31d6..963940c179d 100644 --- a/server/src/__tests__/connection-management.integration.test.ts +++ b/server/src/__tests__/connection-management.integration.test.ts @@ -295,7 +295,7 @@ describe("connection management with production default agents", () => { const ownBinding = await f.request("POST", `${path}/bind`, { targetType: "issue", targetId: f.issueId }); expect(ownBinding, JSON.stringify(ownBinding)).toMatchObject({ status: 201 }); expect(await f.request("POST", `${path}/unbind`, { targetType: "issue", targetId: f.issueId })).toMatchObject({ status: 200 }); - for (const target of [{ targetType: "issue", targetId: issue.id }, { targetType: "routine", targetId: routine.id }, { targetType: "gateway", targetId: gateway.body.id }]) { + for (const target of [{ targetType: "project", targetId: f.projectId }, { targetType: "issue", targetId: issue.id }, { targetType: "routine", targetId: routine.id }, { targetType: "gateway", targetId: gateway.body.id }]) { expect(await f.request("POST", `${path}/bind`, target), JSON.stringify(target)).toMatchObject({ status: 403 }); const [saved] = await server.db.insert(toolProfileBindings).values({ ...target, companyId: f.companyId, profileId: profile.body.id }).returning(); expect(await f.request("PATCH", `/tool-profiles/${profile.body.id}`, { description: "Cannot edit retained target" })).toMatchObject({ status: 403 }); diff --git a/server/src/routes/connection-management-authz.ts b/server/src/routes/connection-management-authz.ts index 0e589266c6f..251d7bb8261 100644 --- a/server/src/routes/connection-management-authz.ts +++ b/server/src/routes/connection-management-authz.ts @@ -353,7 +353,7 @@ export function connectionManagementGuard(db: Db, purpose: "tool" | "chat" | "ai selfServiceUserId: connection.createdByUserId, }); } - if (["issue", "routine", "gateway"].includes(String(selected.targetType)) && text(selected.targetId)) bindingTargets.push({ targetType: String(selected.targetType), targetId: uuid(selected.targetId) }); + if (["project", "issue", "routine", "gateway"].includes(String(selected.targetType)) && text(selected.targetId)) bindingTargets.push({ targetType: String(selected.targetType), targetId: uuid(selected.targetId) }); if (text(selected.routineId)) extraResources.push({ ...resource, routineId: uuid(selected.routineId) }); if (selected.targetType === "project" && text(selected.targetId)) extraResources.push({ ...resource, projectId: String(selected.targetId) }); if (text(selected.projectId)) extraResources.push({ ...resource, projectId: String(selected.projectId) }); diff --git a/server/src/services/connection-management.ts b/server/src/services/connection-management.ts index 299cf897e13..4de417d2605 100644 --- a/server/src/services/connection-management.ts +++ b/server/src/services/connection-management.ts @@ -97,12 +97,10 @@ export function connectionManagementService(db: Db) { const companyAgents = await db.select({ id: agents.id }).from(agents).where(eq(agents.companyId, resource.companyId)); companyAgents.forEach(agent => expandedTargets.add(agent.id)); } - if (["issue", "routine", "gateway"].includes(binding.targetType)) { + if (["project", "issue", "routine", "gateway"].includes(binding.targetType)) { await authorizeBindingTarget(actor, action, resource, binding, options); } - if (binding.targetType === "project") { - await authorize(actor, action, { ...resource, projectId: binding.targetId }, { ...options, expandedProfile: true, gatewayContextChecked: options.gatewayContextChecked || Boolean(resource.gatewayId) }); - } + } const linkedGateways = await db.select({ id: toolMcpGateways.id }).from(toolMcpGateways).where(and(eq(toolMcpGateways.companyId, resource.companyId), eq(toolMcpGateways.profileId, profile.id))); for (const gateway of linkedGateways) await authorizeBindingTarget(actor, action, resource, { targetType: "gateway", targetId: gateway.id }, options); @@ -250,7 +248,12 @@ export function connectionManagementService(db: Db) { options: NonNullable[3]> = {}): Promise { let resolved = { ...resource }; const checkOptions = { ...options, expandedProfile: true }; - if (binding.targetType === "issue") resolved.issueId = binding.targetId; + if (binding.targetType === "project") { + resolved.projectId = binding.targetId; + const rows = await db.select({ id: agents.id }).from(agents).where(eq(agents.companyId, resource.companyId)); + checkOptions.targetAgentIds = [...new Set([...(options.targetAgentIds ?? []), ...rows.map(row => row.id)])]; + } + else if (binding.targetType === "issue") resolved.issueId = binding.targetId; else if (binding.targetType === "routine") resolved.routineId = binding.targetId; else if (binding.targetType === "gateway") { const [gateway] = await db.select().from(toolMcpGateways).where(and(eq(toolMcpGateways.id, binding.targetId), eq(toolMcpGateways.companyId, resource.companyId)));