diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 023c88c5e83..ecf97cea2dc 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -5652,6 +5652,68 @@ export const getResolvedGuardrails = async (accessToken: string, policyId: strin } }; +export const resolvePoliciesCall = async ( + accessToken: string, + context: { team_alias?: string; key_alias?: string; model?: string; tags?: string[] } +) => { + try { + const url = proxyBaseUrl + ? `${proxyBaseUrl}/policies/resolve` + : `/policies/resolve`; + const response = await fetch(url, { + method: "POST", + headers: { + [globalLitellmHeaderName]: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(context), + }); + + if (!response.ok) { + const errorData = await response.json(); + const errorMessage = deriveErrorMessage(errorData); + handleError(errorMessage); + throw new Error(errorMessage); + } + + return await response.json(); + } catch (error) { + console.error("Failed to resolve policies:", error); + throw error; + } +}; + +export const estimateAttachmentImpactCall = async ( + accessToken: string, + attachmentData: any +) => { + try { + const url = proxyBaseUrl + ? `${proxyBaseUrl}/policies/attachments/estimate-impact` + : `/policies/attachments/estimate-impact`; + const response = await fetch(url, { + method: "POST", + headers: { + [globalLitellmHeaderName]: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(attachmentData), + }); + + if (!response.ok) { + const errorData = await response.json(); + const errorMessage = deriveErrorMessage(errorData); + handleError(errorMessage); + throw new Error(errorMessage); + } + + return await response.json(); + } catch (error) { + console.error("Failed to estimate attachment impact:", error); + throw error; + } +}; + export const getPromptsList = async (accessToken: string): Promise => { try { const url = proxyBaseUrl ? `${proxyBaseUrl}/prompts/list` : `/prompts/list`; diff --git a/ui/litellm-dashboard/src/components/policies/index.tsx b/ui/litellm-dashboard/src/components/policies/index.tsx index 717a6ff612f..204f32e4491 100644 --- a/ui/litellm-dashboard/src/components/policies/index.tsx +++ b/ui/litellm-dashboard/src/components/policies/index.tsx @@ -8,6 +8,7 @@ import PolicyInfoView from "./policy_info"; import AddPolicyForm from "./add_policy_form"; import AttachmentTable from "./attachment_table"; import AddAttachmentForm from "./add_attachment_form"; +import PolicyTestPanel from "./policy_test_panel"; import { getPoliciesList, deletePolicyCall, @@ -177,6 +178,7 @@ const PoliciesPanel: React.FC = ({ Policies Attachments + Policy Simulator @@ -279,7 +281,7 @@ const PoliciesPanel: React.FC = ({ description={

- Policy attachments control where your policies apply. Policies don't do anything until you attach them to specific teams, keys, models, or globally. + Policy attachments control where your policies apply. Policies don't do anything until you attach them to specific teams, keys, models, tags, or globally.

Attachment Scopes:

    @@ -287,6 +289,7 @@ const PoliciesPanel: React.FC = ({
  • Teams - Applies only to specific teams
  • Keys - Applies only to specific API keys (supports wildcards like dev-*)
  • Models - Applies only when specific models are used
  • +
  • Tags - Matches tags from key/team metadata.tags or tags passed dynamically in the request body (metadata.tags). Use this to enforce policies across groups, e.g. "all keys tagged healthcare get HIPAA guardrails." Supports wildcards (prod-*).
= ({ isLoading={isAttachmentsLoading} onDeleteClick={handleDeleteAttachment} isAdmin={isAdmin} + accessToken={accessToken} /> = ({ createAttachment={createPolicyAttachmentCall} /> + + + +