mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-15 09:12:18 +00:00
refactor(ui): keep MCP grant inputs in named variables for the lint budget
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
9c86d311e8
commit
33ceaabfcd
2 changed files with 41 additions and 68 deletions
|
|
@ -9,6 +9,7 @@ import type { EffectiveMcpServer } from "../mcp_server_management/effectiveMcpSe
|
|||
import type { MCPServer } from "../mcp_tools/types";
|
||||
import TeamInfoView, {
|
||||
grantedMcpServerIds,
|
||||
type McpGrantInput,
|
||||
retainedMcpToolPermissions,
|
||||
standingToolPermissionServerIds,
|
||||
type TeamData,
|
||||
|
|
@ -2367,13 +2368,22 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
errorToast.mockRestore();
|
||||
};
|
||||
|
||||
it("retains permissions for directly and indirectly granted servers", async () => {
|
||||
const resolution = await grantedMcpServerIds({
|
||||
effectiveServers: [effective("direct", "direct"), effective("inherited", "toolPermission")],
|
||||
const resolveGrants = (overrides: Partial<McpGrantInput>) => {
|
||||
const input: McpGrantInput = {
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
accessGroups: [{ access_group_id: "ag-1", access_mcp_server_ids: ["inherited"] }],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
loadTeamGroups: vi.fn(),
|
||||
...overrides,
|
||||
};
|
||||
return grantedMcpServerIds(input);
|
||||
};
|
||||
|
||||
it("retains permissions for directly and indirectly granted servers", async () => {
|
||||
const resolution = await resolveGrants({
|
||||
effectiveServers: [effective("direct", "direct"), effective("inherited", "toolPermission")],
|
||||
accessGroups: [{ access_group_id: "ag-1", access_mcp_server_ids: ["inherited"] }],
|
||||
});
|
||||
expect(resolution.kind).toBe("resolved");
|
||||
if (resolution.kind !== "resolved") return;
|
||||
|
|
@ -2408,12 +2418,9 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
it("does not reload the team when the access group list covers the selection", async () => {
|
||||
const loadTeamGroups = vi.fn();
|
||||
await expect(
|
||||
grantedMcpServerIds({
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
resolveGrants({
|
||||
accessGroups: [{ access_group_id: "ag-1", access_mcp_server_ids: ["group-server"] }],
|
||||
standingServerIds: new Set(),
|
||||
loadTeamGroups: loadTeamGroups,
|
||||
loadTeamGroups,
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
kind: "resolved",
|
||||
|
|
@ -2424,11 +2431,7 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
|
||||
it("falls back to the team's loaded access group servers when the list is unavailable and the selection is unchanged", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
await resolveGrants({
|
||||
loadTeamGroups: vi.fn().mockResolvedValue({ ids: ["ag-1"], serverIds: ["group-server"] }),
|
||||
}),
|
||||
).toEqual({
|
||||
|
|
@ -2439,10 +2442,8 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
|
||||
it("adds standing tool-permission grants to the reloaded team grants", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
await resolveGrants({
|
||||
effectiveServers: [effective("server-1", "direct"), effective("standing", "toolPermission")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(["standing"]),
|
||||
loadTeamGroups: vi.fn().mockResolvedValue({ ids: ["ag-1"], serverIds: ["group-server"] }),
|
||||
}),
|
||||
|
|
@ -2454,11 +2455,7 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
|
||||
it("is unresolvable when the list is unavailable and the selection changed", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
await resolveGrants({
|
||||
loadTeamGroups: vi.fn().mockResolvedValue({ ids: ["ag-1", "ag-2"], serverIds: ["group-server"] }),
|
||||
}),
|
||||
).toEqual({
|
||||
|
|
@ -2468,15 +2465,7 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
});
|
||||
|
||||
it("is unresolvable when the team reload fails", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
selectedAccessGroupIds: ["ag-1"],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
loadTeamGroups: vi.fn().mockRejectedValue(new Error("boom")),
|
||||
}),
|
||||
).toEqual({
|
||||
expect(await resolveGrants({ loadTeamGroups: vi.fn().mockRejectedValue(new Error("boom")) })).toEqual({
|
||||
kind: "unresolvable",
|
||||
reason: expect.stringMatching(/access groups could not be reloaded/),
|
||||
});
|
||||
|
|
@ -2484,11 +2473,8 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
|
||||
it("refuses an unresolved selected access group", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("server-1", "direct")],
|
||||
await resolveGrants({
|
||||
selectedAccessGroupIds: ["missing"],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
loadTeamGroups: vi.fn().mockResolvedValue({ ids: [], serverIds: [] }),
|
||||
}),
|
||||
).toEqual({
|
||||
|
|
@ -2610,27 +2596,12 @@ describe("TeamInfo MCP permission retention", () => {
|
|||
});
|
||||
|
||||
it("includes standing tool-permission grants in the resolved server ids", async () => {
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("x", "toolPermission")],
|
||||
selectedAccessGroupIds: [],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(["x"]),
|
||||
loadTeamGroups: vi.fn(),
|
||||
}),
|
||||
).toEqual({
|
||||
const standingOnly = { effectiveServers: [effective("x", "toolPermission")], selectedAccessGroupIds: [] };
|
||||
expect(await resolveGrants({ ...standingOnly, standingServerIds: new Set(["x"]) })).toEqual({
|
||||
kind: "resolved",
|
||||
serverIds: new Set(["x"]),
|
||||
});
|
||||
expect(
|
||||
await grantedMcpServerIds({
|
||||
effectiveServers: [effective("x", "toolPermission")],
|
||||
selectedAccessGroupIds: [],
|
||||
accessGroups: [],
|
||||
standingServerIds: new Set(),
|
||||
loadTeamGroups: vi.fn(),
|
||||
}),
|
||||
).toEqual({
|
||||
expect(await resolveGrants(standingOnly)).toEqual({
|
||||
kind: "resolved",
|
||||
serverIds: new Set(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -972,36 +972,38 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
|
|||
toolPermissions: submittedToolPermissions,
|
||||
};
|
||||
const loadedObjectPermission = info.object_permission ?? {};
|
||||
const loadedEffectiveMcpServers = resolveEffectiveMcpServers({
|
||||
const loadedEffectiveMcpInput = {
|
||||
allServers: allMcpServers,
|
||||
selectedServers: loadedObjectPermission.mcp_servers ?? [],
|
||||
selectedAccessGroups: loadedObjectPermission.mcp_access_groups ?? [],
|
||||
selectedToolsets: loadedObjectPermission.mcp_toolsets ?? [],
|
||||
toolsets: allMcpToolsets,
|
||||
toolPermissions: loadedObjectPermission.mcp_tool_permissions ?? {},
|
||||
});
|
||||
};
|
||||
const loadedEffectiveMcpServers = resolveEffectiveMcpServers(loadedEffectiveMcpInput);
|
||||
const standingServerIds = standingToolPermissionServerIds(
|
||||
loadedEffectiveMcpServers,
|
||||
info.access_group_ids ?? [],
|
||||
allAccessGroups,
|
||||
info.access_group_mcp_server_ids ?? [],
|
||||
);
|
||||
const mcpGrantInput: McpGrantInput = {
|
||||
effectiveServers: resolveEffectiveMcpServers(effectiveMcpInput),
|
||||
selectedAccessGroupIds: values.access_group_ids || [],
|
||||
accessGroups: allAccessGroups,
|
||||
standingServerIds,
|
||||
loadTeamGroups: async () => {
|
||||
const teamInfo = await teamInfoCall(accessToken, teamId);
|
||||
return {
|
||||
ids: teamInfo.team_info.access_group_ids ?? [],
|
||||
serverIds: teamInfo.team_info.access_group_mcp_server_ids ?? [],
|
||||
};
|
||||
},
|
||||
};
|
||||
const mcpResolution: McpGrantResolution =
|
||||
mcpLookupFailure !== null
|
||||
? { kind: "unresolvable", reason: mcpLookupFailure }
|
||||
: await grantedMcpServerIds({
|
||||
effectiveServers: resolveEffectiveMcpServers(effectiveMcpInput),
|
||||
selectedAccessGroupIds: values.access_group_ids || [],
|
||||
accessGroups: allAccessGroups,
|
||||
standingServerIds,
|
||||
loadTeamGroups: async () => {
|
||||
const teamInfo = await teamInfoCall(accessToken, teamId);
|
||||
return {
|
||||
ids: teamInfo.team_info.access_group_ids ?? [],
|
||||
serverIds: teamInfo.team_info.access_group_mcp_server_ids ?? [],
|
||||
};
|
||||
},
|
||||
});
|
||||
: await grantedMcpServerIds(mcpGrantInput);
|
||||
if (mcpResolution.kind === "unresolvable" && Object.keys(submittedToolPermissions).length > 0) {
|
||||
toast.fromError(mcpUnresolvableSaveError(mcpResolution.reason));
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue