mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
feat: support policy templates on ui
allows admin to enable pre-configured guardrails helps cover specific use-cases well
This commit is contained in:
parent
9c2ceb90c7
commit
770519be75
7 changed files with 793 additions and 5 deletions
|
|
@ -14,14 +14,388 @@ model_list:
|
|||
litellm_params:
|
||||
model: openai/gpt-4.1-mini
|
||||
|
||||
# ==============================================================================
|
||||
# GUARDRAILS - PII Detection for Fortescue (Australian Mining Company)
|
||||
# ==============================================================================
|
||||
|
||||
guardrails:
|
||||
- guardrail_name: redact-ssn
|
||||
# --------------------------------------------------------------------------
|
||||
# 1. AUSTRALIAN-SPECIFIC PII PATTERNS
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: au-pii-tax-identifiers
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# Australian Tax File Number (8-9 digits)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: au_tfn
|
||||
action: MASK
|
||||
# Australian Business Number (11 digits)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: au_abn
|
||||
action: MASK
|
||||
# Australian Medicare Number
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: au_medicare
|
||||
action: MASK
|
||||
pattern_redaction_format: "[{pattern_name}_REDACTED]"
|
||||
|
||||
- guardrail_name: au-pii-passports
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# Australian passport (critical for mining contractors/fly-in-fly-out workers)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_australia
|
||||
action: MASK
|
||||
pattern_redaction_format: "[PASSPORT_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 2. INTERNATIONAL PII (for global workforce)
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: international-pii-identifiers
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# US employees/contractors
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: us_ssn
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: us_ssn_no_dash
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_us
|
||||
action: MASK
|
||||
# UK operations
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_uk
|
||||
action: MASK
|
||||
# European operations
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_germany
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_france
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_netherlands
|
||||
action: MASK
|
||||
# Dutch BSN (contextual)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: nl_bsn_contextual
|
||||
action: MASK
|
||||
# Asian Pacific operations
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_china
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_india
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_japan
|
||||
action: MASK
|
||||
# Canadian operations
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: passport_canada
|
||||
action: MASK
|
||||
# South American operations (mining companies often have Brazilian presence)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_cpf
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_cpf_unformatted
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_rg
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_cnpj
|
||||
action: MASK
|
||||
pattern_redaction_format: "[{pattern_name}_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 3. CONTACT INFORMATION
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: contact-information-pii
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# Email addresses (employees, contractors, suppliers)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: email
|
||||
action: MASK
|
||||
# Phone numbers (US format, commonly used internationally)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: us_phone
|
||||
action: MASK
|
||||
# Brazilian phones (if applicable)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_phone_landline
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_phone_mobile
|
||||
action: MASK
|
||||
# Street addresses (mining sites, offices, residential)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: street_address
|
||||
action: MASK
|
||||
# Postal codes
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: br_cep
|
||||
action: MASK
|
||||
pattern_redaction_format: "[{pattern_name}_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 4. FINANCIAL & PAYMENT INFORMATION
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: financial-pii
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# Credit cards (corporate cards, employee expenses)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: visa
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: mastercard
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: amex
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: discover
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: credit_card
|
||||
action: MASK
|
||||
# International banking (IBAN for international payments)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: iban
|
||||
action: MASK
|
||||
pattern_redaction_format: "[{pattern_name}_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 5. CREDENTIALS & API KEYS (BLOCK - High Risk)
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: credentials-api-keys
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# AWS credentials (critical infrastructure access)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: aws_access_key
|
||||
action: BLOCK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: aws_secret_key
|
||||
action: BLOCK
|
||||
# GitHub tokens (code repository access)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: github_token
|
||||
action: BLOCK
|
||||
# Slack tokens (internal communications)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: slack_token
|
||||
action: BLOCK
|
||||
# Generic API keys
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: generic_api_key
|
||||
action: BLOCK
|
||||
pattern_redaction_format: "[{pattern_name}_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 6. NETWORK INFORMATION (Mining operations, remote sites)
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: network-infrastructure-pii
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# IP addresses (internal network, mining site infrastructure)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: ipv4
|
||||
action: MASK
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: ipv6
|
||||
action: MASK
|
||||
pattern_redaction_format: "[INTERNAL_IP_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 7. PROTECTED CLASS INFORMATION (Fair Lending, HR Compliance)
|
||||
# Critical for mining industry with diverse workforce
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: protected-class-information
|
||||
litellm_params:
|
||||
guardrail: litellm_content_filter
|
||||
mode: pre_call
|
||||
patterns:
|
||||
# Gender and sexual orientation (workplace discrimination prevention)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: gender_sexual_orientation
|
||||
action: MASK
|
||||
# Race, ethnicity, national origin (diversity/inclusion compliance)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: race_ethnicity_national_origin
|
||||
action: MASK
|
||||
# Religion and creed
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: religion
|
||||
action: MASK
|
||||
# Age discrimination (important for mining workforce management)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: age_discrimination
|
||||
action: MASK
|
||||
# Disability status (safety accommodations, worker's compensation)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: disability
|
||||
action: MASK
|
||||
# Marital and family status (relocation, benefits)
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: marital_family_status
|
||||
action: MASK
|
||||
# Military status
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: military_status
|
||||
action: MASK
|
||||
# Public assistance status
|
||||
- pattern_type: prebuilt
|
||||
pattern_name: public_assistance
|
||||
action: MASK
|
||||
pattern_redaction_format: "[PROTECTED_CLASS_INFO_REDACTED]"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 8. CUSTOM CODE GUARDRAIL - Mining Industry Specific PII
|
||||
# --------------------------------------------------------------------------
|
||||
- guardrail_name: mining-industry-custom-pii
|
||||
litellm_params:
|
||||
guardrail: custom_code
|
||||
mode: pre_call
|
||||
custom_code: |
|
||||
def apply_guardrail(inputs, request_data, input_type):
|
||||
"""
|
||||
Custom PII detection for mining industry:
|
||||
- Australian Company Numbers (ACN)
|
||||
- Mining License Numbers
|
||||
- Site-specific employee IDs
|
||||
- Geological coordinates (sensitive mine locations)
|
||||
"""
|
||||
import re
|
||||
|
||||
for text in inputs["texts"]:
|
||||
if regex_match(text, r"\d{3}-\d{2}-\d{4}"):
|
||||
return block("SSN detected in message")
|
||||
return allow()
|
||||
# Australian Company Number (ACN) - 9 digits, space-separated
|
||||
# Format: XXX XXX XXX
|
||||
acn_pattern = r'\b\d{3}\s\d{3}\s\d{3}\b'
|
||||
if re.search(acn_pattern, text):
|
||||
# Mask ACNs
|
||||
text = re.sub(acn_pattern, '[ACN_REDACTED]', text)
|
||||
|
||||
# Mining tenement/license numbers (Australian format)
|
||||
# Format: M/E/P + numbers (e.g., M12345, EL6789)
|
||||
mining_license_pattern = r'\b[MEP][A-Z]?\s?\d{4,6}\b'
|
||||
if re.search(mining_license_pattern, text, re.IGNORECASE):
|
||||
text = re.sub(mining_license_pattern, '[MINING_LICENSE_REDACTED]', text, flags=re.IGNORECASE)
|
||||
|
||||
# Precise GPS coordinates (sensitive mine locations)
|
||||
# Format: latitude, longitude with high precision
|
||||
gps_pattern = r'-?\d{1,3}\.\d{4,}\s*,\s*-?\d{1,3}\.\d{4,}'
|
||||
if re.search(gps_pattern, text):
|
||||
text = re.sub(gps_pattern, '[GPS_COORDINATES_REDACTED]', text)
|
||||
|
||||
# FIFO/DIDO roster numbers or employee mining IDs
|
||||
# Format: Common mining employee ID patterns
|
||||
employee_id_pattern = r'\b(?:EMP|FIF|DID|MIN)[_-]?\d{5,8}\b'
|
||||
if re.search(employee_id_pattern, text, re.IGNORECASE):
|
||||
text = re.sub(employee_id_pattern, '[EMPLOYEE_ID_REDACTED]', text, flags=re.IGNORECASE)
|
||||
|
||||
# Update the text in inputs if any modifications were made
|
||||
if text != inputs["texts"][inputs["texts"].index(inputs["texts"][next(i for i, t in enumerate(inputs["texts"]) if t == text)])]:
|
||||
inputs["texts"][inputs["texts"].index(inputs["texts"][next(i for i, t in enumerate(inputs["texts"]) if t == text)])] = text
|
||||
|
||||
return allow()
|
||||
|
||||
# ==============================================================================
|
||||
# POLICIES - Combining PII Guardrails
|
||||
# ==============================================================================
|
||||
|
||||
policies:
|
||||
# Comprehensive PII policy for Fortescue mining operations
|
||||
fortescue-pii-protection:
|
||||
description: >
|
||||
Comprehensive PII detection and masking policy for Fortescue.
|
||||
Protects Australian-specific identifiers, international employee data,
|
||||
financial information, credentials, protected class information,
|
||||
and mining industry-specific sensitive data.
|
||||
guardrails:
|
||||
add:
|
||||
# Australian-specific
|
||||
- au-pii-tax-identifiers
|
||||
- au-pii-passports
|
||||
# International workforce
|
||||
- international-pii-identifiers
|
||||
# Contact information
|
||||
- contact-information-pii
|
||||
# Financial data
|
||||
- financial-pii
|
||||
# Credentials (blocks instead of masks)
|
||||
- credentials-api-keys
|
||||
# Network infrastructure
|
||||
- network-infrastructure-pii
|
||||
# Protected class compliance
|
||||
- protected-class-information
|
||||
# Mining industry custom
|
||||
- mining-industry-custom-pii
|
||||
|
||||
# Baseline policy for non-sensitive internal use
|
||||
fortescue-pii-baseline:
|
||||
description: >
|
||||
Baseline PII protection for internal tools and testing.
|
||||
Focuses on credentials and high-risk identifiers only.
|
||||
guardrails:
|
||||
add:
|
||||
- au-pii-tax-identifiers
|
||||
- credentials-api-keys
|
||||
- financial-pii
|
||||
|
||||
# HR and recruiting policy (extra strict on protected class)
|
||||
fortescue-pii-hr-recruiting:
|
||||
description: >
|
||||
Strict PII protection for HR, recruiting, and workforce management.
|
||||
Emphasizes protected class information to ensure compliance with
|
||||
anti-discrimination laws and workplace regulations.
|
||||
inherit: fortescue-pii-protection
|
||||
guardrails:
|
||||
add:
|
||||
# Already includes protected-class-information from parent
|
||||
# This policy ensures all PII filters are active for HR use cases
|
||||
|
||||
# ==============================================================================
|
||||
# POLICY ATTACHMENTS - Apply Policies to Teams/Keys/Models
|
||||
# ==============================================================================
|
||||
|
||||
policy_attachments:
|
||||
# Apply comprehensive PII protection globally
|
||||
- policy: fortescue-pii-protection
|
||||
scope: "*" # Applies to all requests by default
|
||||
|
||||
# Override for HR team with stricter policy
|
||||
# Uncomment and modify team alias after creating teams
|
||||
# - policy: fortescue-pii-hr-recruiting
|
||||
# teams:
|
||||
# - hr-team
|
||||
# - recruiting-team
|
||||
# - workforce-management
|
||||
|
||||
# Override for internal development/testing with baseline policy
|
||||
# - policy: fortescue-pii-baseline
|
||||
# teams:
|
||||
# - internal-dev
|
||||
# - testing-team
|
||||
# keys:
|
||||
# - dev-*
|
||||
# - test-*
|
||||
|
|
@ -6,8 +6,13 @@ All /policy management endpoints
|
|||
/policy/validate - Validate a policy configuration
|
||||
/policy/list - List all loaded policies
|
||||
/policy/info - Get information about a specific policy
|
||||
/policy/templates - Get available policy templates
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from typing import Any, List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
|
|
@ -257,3 +262,52 @@ async def test_policy_matching(
|
|||
matching_policies=matching_policy_names,
|
||||
resolved_guardrails=resolved_guardrails,
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/policy/templates",
|
||||
tags=["policy management"],
|
||||
dependencies=[Depends(user_api_key_auth)],
|
||||
)
|
||||
@management_endpoint_wrapper
|
||||
async def get_policy_templates(
|
||||
request: Request,
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
) -> List[Any]:
|
||||
"""
|
||||
Get available policy templates for quick policy setup.
|
||||
|
||||
Returns a list of pre-configured policy templates that users can use
|
||||
as a starting point for creating their own policies.
|
||||
"""
|
||||
try:
|
||||
# Get the path to the policy_templates.json file
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
templates_path = os.path.join(
|
||||
os.path.dirname(current_dir), "policy_templates.json"
|
||||
)
|
||||
|
||||
# Read and return the templates
|
||||
with open(templates_path, "r") as f:
|
||||
templates = json.load(f)
|
||||
|
||||
verbose_proxy_logger.debug(f"Loaded {len(templates)} policy templates")
|
||||
return templates
|
||||
|
||||
except FileNotFoundError:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Policy templates file not found",
|
||||
)
|
||||
except json.JSONDecodeError as e:
|
||||
verbose_proxy_logger.error(f"Error parsing policy templates JSON: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Error parsing policy templates file",
|
||||
)
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(f"Error loading policy templates: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Error loading policy templates: {str(e)}",
|
||||
)
|
||||
|
|
|
|||
140
litellm/proxy/policy_templates.json
Normal file
140
litellm/proxy/policy_templates.json
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
[
|
||||
{
|
||||
"id": "advanced-pii-protection",
|
||||
"title": "Advanced PII Protection (Australia)",
|
||||
"description": "Comprehensive PII detection and masking policy. Protects Australian-specific identifiers, international employee data, financial information, credentials, protected class information, and industry-specific sensitive data.",
|
||||
"icon": "ShieldCheckIcon",
|
||||
"iconColor": "text-purple-500",
|
||||
"iconBg": "bg-purple-50",
|
||||
"guardrails": [
|
||||
"au-pii-tax-identifiers",
|
||||
"au-pii-passports",
|
||||
"international-pii-identifiers",
|
||||
"contact-information-pii",
|
||||
"financial-pii",
|
||||
"credentials-api-keys",
|
||||
"network-infrastructure-pii",
|
||||
"protected-class-information",
|
||||
"mining-industry-custom-pii"
|
||||
],
|
||||
"complexity": "High",
|
||||
"templateData": {
|
||||
"policy_name": "fortescue-pii-protection",
|
||||
"description": "Comprehensive PII detection and masking policy for Fortescue. Protects Australian-specific identifiers, international employee data, financial information, credentials, protected class information, and mining industry-specific sensitive data.",
|
||||
"guardrails": {
|
||||
"add": [
|
||||
"au-pii-tax-identifiers",
|
||||
"au-pii-passports",
|
||||
"international-pii-identifiers",
|
||||
"contact-information-pii",
|
||||
"financial-pii",
|
||||
"credentials-api-keys",
|
||||
"network-infrastructure-pii",
|
||||
"protected-class-information",
|
||||
"mining-industry-custom-pii"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "baseline-pii-protection",
|
||||
"title": "Baseline PII Protection",
|
||||
"description": "Baseline PII protection for internal tools and testing. Focuses on credentials and high-risk identifiers only. Suitable for non-sensitive internal use.",
|
||||
"icon": "ShieldCheckIcon",
|
||||
"iconColor": "text-blue-500",
|
||||
"iconBg": "bg-blue-50",
|
||||
"guardrails": [
|
||||
"au-pii-tax-identifiers",
|
||||
"credentials-api-keys",
|
||||
"financial-pii"
|
||||
],
|
||||
"complexity": "Low",
|
||||
"templateData": {
|
||||
"policy_name": "baseline-pii-protection",
|
||||
"description": "Baseline PII protection for internal tools and testing. Focuses on credentials and high-risk identifiers only.",
|
||||
"guardrails": {
|
||||
"add": [
|
||||
"au-pii-tax-identifiers",
|
||||
"credentials-api-keys",
|
||||
"financial-pii"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hr-recruiting-policy",
|
||||
"title": "HR & Recruiting Policy",
|
||||
"description": "Strict PII protection for HR, recruiting, and workforce management. Emphasizes protected class information to ensure compliance with anti-discrimination laws and workplace regulations.",
|
||||
"icon": "ShieldExclamationIcon",
|
||||
"iconColor": "text-indigo-500",
|
||||
"iconBg": "bg-indigo-50",
|
||||
"guardrails": [
|
||||
"au-pii-tax-identifiers",
|
||||
"au-pii-passports",
|
||||
"international-pii-identifiers",
|
||||
"contact-information-pii",
|
||||
"financial-pii",
|
||||
"credentials-api-keys",
|
||||
"network-infrastructure-pii",
|
||||
"protected-class-information"
|
||||
],
|
||||
"inherits": "Fortescue PII Protection",
|
||||
"complexity": "High",
|
||||
"templateData": {
|
||||
"policy_name": "hr-recruiting-policy",
|
||||
"description": "Strict PII protection for HR, recruiting, and workforce management. Emphasizes protected class information to ensure compliance with anti-discrimination laws and workplace regulations.",
|
||||
"inherit": "fortescue-pii-protection",
|
||||
"guardrails": {
|
||||
"add": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cost-control-policy",
|
||||
"title": "Cost Control Policy",
|
||||
"description": "Budget-focused guardrails to prevent unexpected spend. Routes expensive queries to cheaper models and enforces rate limiting.",
|
||||
"icon": "CurrencyDollarIcon",
|
||||
"iconColor": "text-green-500",
|
||||
"iconBg": "bg-green-50",
|
||||
"guardrails": [
|
||||
"budget-limit",
|
||||
"model-routing",
|
||||
"rate-limit"
|
||||
],
|
||||
"complexity": "Medium",
|
||||
"templateData": {
|
||||
"policy_name": "cost-control-policy",
|
||||
"description": "Budget-focused guardrails to prevent unexpected spend. Routes expensive queries to cheaper models.",
|
||||
"guardrails": {
|
||||
"add": [
|
||||
"budget-limit",
|
||||
"model-routing",
|
||||
"rate-limit"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "development-testing-policy",
|
||||
"title": "Development / Testing",
|
||||
"description": "Relaxed guardrails for development environments. Enables full logging for debugging purposes with minimal restrictions.",
|
||||
"icon": "BeakerIcon",
|
||||
"iconColor": "text-orange-500",
|
||||
"iconBg": "bg-orange-50",
|
||||
"guardrails": [
|
||||
"debug-logging",
|
||||
"latency-monitoring"
|
||||
],
|
||||
"complexity": "Low",
|
||||
"templateData": {
|
||||
"policy_name": "development-testing-policy",
|
||||
"description": "Relaxed guardrails for development environments. Enables full logging for debugging purposes.",
|
||||
"guardrails": {
|
||||
"add": [
|
||||
"debug-logging",
|
||||
"latency-monitoring"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -5438,6 +5438,32 @@ export const getPolicyInfoWithGuardrails = async (accessToken: string, policyNam
|
|||
}
|
||||
};
|
||||
|
||||
export const getPolicyTemplates = async (accessToken: string) => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/policy/templates` : `/policy/templates`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
const errorMessage = deriveErrorMessage(errorData);
|
||||
handleError(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Failed to get policy templates:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createPolicyCall = async (accessToken: string, policyData: any) => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/policies` : `/policies`;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import AddPolicyForm from "./add_policy_form";
|
|||
import AttachmentTable from "./attachment_table";
|
||||
import AddAttachmentForm from "./add_attachment_form";
|
||||
import PolicyTestPanel from "./policy_test_panel";
|
||||
import PolicyTemplates from "./policy_templates";
|
||||
import {
|
||||
getPoliciesList,
|
||||
deletePolicyCall,
|
||||
|
|
@ -172,6 +173,13 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({
|
|||
fetchAttachments();
|
||||
};
|
||||
|
||||
const handleUseTemplate = (templateData: any) => {
|
||||
// Pre-fill the add policy form with template data
|
||||
setEditingPolicy(templateData as Policy);
|
||||
setIsAddPolicyModalVisible(true);
|
||||
setActiveTab(0); // Switch to Policies tab
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full mx-auto flex-auto overflow-y-auto m-8 p-2">
|
||||
<TabGroup index={activeTab} onIndexChange={setActiveTab}>
|
||||
|
|
@ -179,6 +187,7 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({
|
|||
<Tab>Policies</Tab>
|
||||
<Tab>Attachments</Tab>
|
||||
<Tab>Policy Simulator</Tab>
|
||||
<Tab>Templates</Tab>
|
||||
</TabList>
|
||||
|
||||
<TabPanels>
|
||||
|
|
@ -338,6 +347,10 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({
|
|||
<TabPanel>
|
||||
<PolicyTestPanel accessToken={accessToken} />
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel>
|
||||
<PolicyTemplates onUseTemplate={handleUseTemplate} accessToken={accessToken} />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</TabGroup>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Card, Button, Spin, message } from "antd";
|
||||
import {
|
||||
ShieldCheckIcon,
|
||||
ShieldExclamationIcon,
|
||||
BeakerIcon,
|
||||
CurrencyDollarIcon,
|
||||
CheckCircleIcon,
|
||||
} from "@heroicons/react/outline";
|
||||
import { getPolicyTemplates } from "../networking";
|
||||
|
||||
interface PolicyTemplateCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;
|
||||
iconColor: string;
|
||||
iconBg: string;
|
||||
guardrails: string[];
|
||||
inherits?: string;
|
||||
complexity: "Low" | "Medium" | "High";
|
||||
onUseTemplate: () => void;
|
||||
}
|
||||
|
||||
const PolicyTemplateCard: React.FC<PolicyTemplateCardProps> = ({
|
||||
title,
|
||||
description,
|
||||
icon: Icon,
|
||||
iconColor,
|
||||
iconBg,
|
||||
guardrails,
|
||||
inherits,
|
||||
complexity,
|
||||
onUseTemplate,
|
||||
}) => {
|
||||
const getComplexityStyle = () => {
|
||||
switch (complexity) {
|
||||
case "Low":
|
||||
return "bg-gray-50 text-gray-600 border-gray-200";
|
||||
case "Medium":
|
||||
return "bg-blue-50 text-blue-600 border-blue-100";
|
||||
case "High":
|
||||
return "bg-purple-50 text-purple-600 border-purple-100";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="h-full hover:shadow-md transition-shadow"
|
||||
bodyStyle={{ display: "flex", flexDirection: "column", height: "100%" }}
|
||||
>
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className={`p-2 rounded-lg ${iconBg}`}>
|
||||
<Icon className={`h-6 w-6 ${iconColor}`} />
|
||||
</div>
|
||||
<span
|
||||
className={`px-2.5 py-0.5 rounded-full text-xs font-medium border ${getComplexityStyle()}`}
|
||||
>
|
||||
{complexity} Complexity
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-2">{title}</h3>
|
||||
<p className="text-sm text-gray-500 mb-6 flex-grow">{description}</p>
|
||||
|
||||
{inherits && (
|
||||
<div className="mb-4 text-xs">
|
||||
<span className="text-gray-500">Inherits from: </span>
|
||||
<span className="font-medium text-gray-700 bg-gray-100 px-2 py-0.5 rounded">
|
||||
{inherits}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-6">
|
||||
<span className="text-xs font-medium text-gray-500 uppercase tracking-wider block mb-2">
|
||||
Included Guardrails
|
||||
</span>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{guardrails.map((g) => (
|
||||
<span
|
||||
key={g}
|
||||
className="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-gray-50 text-gray-700 border border-gray-200"
|
||||
>
|
||||
{g}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
className="mt-auto"
|
||||
onClick={onUseTemplate}
|
||||
>
|
||||
Use Template
|
||||
</Button>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
interface PolicyTemplatesProps {
|
||||
onUseTemplate: (templateData: any) => void;
|
||||
accessToken: string | null;
|
||||
}
|
||||
|
||||
// Map icon names from JSON to actual icon components
|
||||
const iconMap: Record<string, React.ComponentType<React.SVGProps<SVGSVGElement>>> = {
|
||||
ShieldCheckIcon: ShieldCheckIcon,
|
||||
ShieldExclamationIcon: ShieldExclamationIcon,
|
||||
BeakerIcon: BeakerIcon,
|
||||
CurrencyDollarIcon: CurrencyDollarIcon,
|
||||
CheckCircleIcon: CheckCircleIcon,
|
||||
};
|
||||
|
||||
const PolicyTemplates: React.FC<PolicyTemplatesProps> = ({ onUseTemplate, accessToken }) => {
|
||||
const [templates, setTemplates] = useState<any[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTemplates = async () => {
|
||||
if (!accessToken) return;
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const data = await getPolicyTemplates(accessToken);
|
||||
setTemplates(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching policy templates:", error);
|
||||
message.error("Failed to fetch policy templates");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTemplates();
|
||||
}, [accessToken]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center py-20">
|
||||
<Spin size="large" tip="Loading policy templates..." />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-end">
|
||||
<div>
|
||||
<h2 className="text-lg font-medium text-gray-900">
|
||||
Policy Templates
|
||||
</h2>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
Start with a pre-configured policy template to quickly set up
|
||||
guardrails for your organization.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
{templates.map((template, index) => (
|
||||
<PolicyTemplateCard
|
||||
key={template.id || index}
|
||||
title={template.title}
|
||||
description={template.description}
|
||||
icon={iconMap[template.icon] || ShieldCheckIcon}
|
||||
iconColor={template.iconColor}
|
||||
iconBg={template.iconBg}
|
||||
guardrails={template.guardrails}
|
||||
inherits={template.inherits}
|
||||
complexity={template.complexity}
|
||||
onUseTemplate={() => onUseTemplate(template.templateData)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PolicyTemplates;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue