mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(ui): hide the Add Provider wizard from view-only admins
effectiveSessionRole deliberately reports a proxy_admin_viewer session as "Admin", so gating the tab on all_admin_roles showed a read-only admin a wizard whose every step is a write the proxy then refuses. The first step solicits a provider API key, so a viewer types a real secret into a form that 403s on submit. Only the raw-role isViewOnly separates the two, which is the same mechanism the Playground already uses for this carve-out. Both conjuncts of the gate are covered: dropping either one fails a test. The five older admin panels on this page have the same gap, but they predate this PR and fixing them is a page-wide change, so they are left for a follow-up.
This commit is contained in:
parent
bacf9c9ad0
commit
2b1e56b877
2 changed files with 23 additions and 3 deletions
|
|
@ -40,6 +40,15 @@ vi.mock("./useModelDashboardData", () => ({
|
|||
|
||||
const ADMIN = { accessToken: "at", token: "t", userRole: "Admin", userId: "u1", premiumUser: false };
|
||||
const NON_ADMIN = { accessToken: "at", token: "t", userRole: "Internal User", userId: "u1", premiumUser: false };
|
||||
// effectiveSessionRole reports a proxy_admin_viewer session as "Admin"; only isViewOnly tells them apart.
|
||||
const ADMIN_VIEWER = {
|
||||
accessToken: "at",
|
||||
token: "t",
|
||||
userRole: "Admin",
|
||||
userId: "u1",
|
||||
premiumUser: false,
|
||||
isViewOnly: true,
|
||||
};
|
||||
|
||||
const renderPage = () => {
|
||||
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } });
|
||||
|
|
@ -68,9 +77,17 @@ describe("ModelsAndEndpointsPage", () => {
|
|||
expect(getByRole("tab", { name: "All Models" })).toBeInTheDocument();
|
||||
expect(getByRole("tab", { name: "LLM Credentials" })).toBeInTheDocument();
|
||||
expect(getByRole("tab", { name: "Health Status" })).toBeInTheDocument();
|
||||
expect(getByRole("tab", { name: "Add Provider" })).toBeInTheDocument();
|
||||
expect(getByTestId("panel-all-models")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("hides the write-only Add Provider tab from a view-only admin", () => {
|
||||
mockUseAuthorized.mockReturnValue(ADMIN_VIEWER);
|
||||
const { getByRole, queryByRole } = renderPage();
|
||||
expect(getByRole("tab", { name: "All Models" })).toBeInTheDocument();
|
||||
expect(queryByRole("tab", { name: "Add Provider" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("switches tabs in-memory, mounting only the active panel", async () => {
|
||||
const user = userEvent.setup();
|
||||
const { getByRole, getByTestId, queryByTestId } = renderPage();
|
||||
|
|
@ -97,6 +114,7 @@ describe("ModelsAndEndpointsPage", () => {
|
|||
const { queryByRole } = renderPage();
|
||||
expect(queryByRole("tab", { name: "LLM Credentials" })).not.toBeInTheDocument();
|
||||
expect(queryByRole("tab", { name: "Health Status" })).not.toBeInTheDocument();
|
||||
expect(queryByRole("tab", { name: "Add Provider" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Auto-routers are excluded from the All Models table, so this tab is their home: the only
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ const renderPanel = (key: string) => {
|
|||
};
|
||||
|
||||
export default function ModelsAndEndpointsPage() {
|
||||
const { accessToken, userRole, userId: userID, premiumUser } = useAuthorized();
|
||||
const { accessToken, userRole, userId: userID, premiumUser, isViewOnly } = useAuthorized();
|
||||
const { data: teams } = useTeams();
|
||||
const { data: uiSettings } = useUISettings();
|
||||
const queryClient = useQueryClient();
|
||||
|
|
@ -106,12 +106,14 @@ export default function ModelsAndEndpointsPage() {
|
|||
"",
|
||||
...(canCreate ? (["add"] as const) : []),
|
||||
...(isAdmin || canCreate ? (["auto-routers"] as const) : []),
|
||||
...(isAdmin ? (["add-provider"] as const) : []),
|
||||
// effectiveSessionRole reports proxy_admin_viewer as "Admin", so isAdmin alone would show
|
||||
// a viewer this write-only wizard; only the raw-role isViewOnly separates them.
|
||||
...(isAdmin && !isViewOnly ? (["add-provider"] as const) : []),
|
||||
...(isAdmin
|
||||
? (["llm-credentials", "pass-through", "health", "retry-settings", "model-group-alias", "price-data"] as const)
|
||||
: []),
|
||||
],
|
||||
[canCreate, isAdmin],
|
||||
[canCreate, isAdmin, isViewOnly],
|
||||
);
|
||||
|
||||
const allModelsLabel = isAdmin ? "All Models" : "Your Models";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue