From e75824dab3978a0c1b7cd347747db71731d71068 Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Fri, 13 Feb 2026 08:56:26 -0800 Subject: [PATCH] fix: address greptile feedback --- litellm/policy_templates_backup.json | 50 ++++++- .../litellm_content_filter/patterns.json | 34 +++-- .../management_endpoints/policy_endpoints.py | 140 ++++++------------ policy_templates.json | 50 ++++++- 4 files changed, 161 insertions(+), 113 deletions(-) diff --git a/litellm/policy_templates_backup.json b/litellm/policy_templates_backup.json index 8eff8ead40c..6541839611b 100644 --- a/litellm/policy_templates_backup.json +++ b/litellm/policy_templates_backup.json @@ -215,7 +215,55 @@ "financial-pii" ], "complexity": "Low", - "guardrailDefinitions": [], + "guardrailDefinitions": [ + { + "guardrail_name": "au-pii-tax-identifiers", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"pattern_type": "prebuilt", "pattern_name": "au_tfn", "action": "MASK"}, + {"pattern_type": "prebuilt", "pattern_name": "au_abn", "action": "MASK"}, + {"pattern_type": "prebuilt", "pattern_name": "au_medicare", "action": "MASK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Masks Australian Tax File Numbers, Business Numbers, and Medicare Numbers"} + }, + { + "guardrail_name": "credentials-api-keys", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"pattern_type": "prebuilt", "pattern_name": "aws_access_key", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "aws_secret_key", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "github_token", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "slack_token", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "generic_api_key", "action": "BLOCK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Blocks requests containing API keys and credentials (AWS, GitHub, Slack)"} + }, + { + "guardrail_name": "financial-pii", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"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"}, + {"pattern_type": "prebuilt", "pattern_name": "iban", "action": "MASK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Masks financial information including credit cards and bank account numbers"} + } + ], "templateData": { "policy_name": "baseline-pii-protection", "description": "Baseline PII protection for internal tools and testing. Focuses on credentials and high-risk identifiers only.", diff --git a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json index ee01f33023f..f4ad9c53a35 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json @@ -370,38 +370,40 @@ }, { "name": "au_tfn", - "display_name": "TFN - Australian Tax File Number", + "display_name": "TFN (Australian Tax File Number)", "pattern": "\\b\\d{8,9}\\b", - "category": "Australian PII Patterns", - "description": "Detects Australian Tax File Numbers (8 or 9 digits)" + "category": "PII Patterns", + "description": "Detects Australian Tax File Numbers (8-9 digits) only when near TFN/tax file context to avoid false positives on arbitrary numbers", + "keyword_pattern": "\\b(?:TFN|T\\.F\\.N\\.|tax\\s*file\\s*(?:number|no\\.?)|tax\\s*file\\s*#?|ATO\\s*number)\\b", + "allow_word_numbers": false }, { "name": "au_abn", - "display_name": "ABN - Australian Business Number", + "display_name": "ABN (Australian Business Number)", "pattern": "\\b\\d{2}\\s?\\d{3}\\s?\\d{3}\\s?\\d{3}\\b", - "category": "Australian PII Patterns", - "description": "Detects Australian Business Numbers (11 digits, optionally space-separated)" + "category": "PII Patterns", + "description": "Detects Australian Business Numbers (11 digits, optional spaces: XX XXX XXX XXX)" }, { "name": "au_medicare", - "display_name": "Australian Medicare Number", - "pattern": "\\b\\d{4}\\s?\\d{5}\\s?\\d(?:\\s?\\d)?\\b", - "category": "Australian PII Patterns", - "description": "Detects Australian Medicare numbers (10 digits + optional reference digit)" + "display_name": "Medicare Number (Australia)", + "pattern": "\\b(?:\\d{4}\\s?\\d{5}\\s?\\d{1}|\\d{11})\\b", + "category": "PII Patterns", + "description": "Detects Australian Medicare numbers (formatted XXXX XXXXX X or 11 consecutive digits)" }, { "name": "iban", - "display_name": "IBAN - International Bank Account Number", + "display_name": "IBAN (International Bank Account Number)", "pattern": "\\b[A-Z]{2}\\d{2}[A-Z0-9]{11,30}\\b", - "category": "Banking Patterns", - "description": "Detects International Bank Account Numbers (IBAN format: 2 country letters, 2 check digits, 11-30 alphanumeric)" + "category": "Payment Card Patterns", + "description": "Detects IBANs (2 letter country code + 2 check digits + 4 char bank code + 7 digit base + optional 0-16 alphanumeric)" }, { "name": "street_address", - "display_name": "Street Address (AU/US/UK)", - "pattern": "(?i)\\b\\d{1,5}(?:[-\\s]?\\d+)?\\s+[A-Z][a-z]*(?:\\s+[A-Z][a-z]*)*\\s+(?:Street|St\\.?|Road|Rd\\.?|Avenue|Ave\\.?|Drive|Dr\\.?|Court|Ct\\.?|Lane|Ln\\.?|Terrace|Tce\\.?|Way|Boulevard|Blvd\\.?)\\b(?:,?\\s*(?:[A-Z][a-z]*(?:\\s+[A-Z][a-z]*)*))*?(?:,?\\s*[A-Z]{2,3}\\s*\\d{4})?(?:,?\\s*[A-Z][a-z]*(?:\\s+[A-Z][a-z]*)*)?(?:,?\\s*Australia|USA|United States|UK)?", + "display_name": "Street Address", + "pattern": "\\b\\d{1,6}\\s+[A-Za-z0-9][A-Za-z0-9\\s.'-]*\\s+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Drive|Dr|Lane|Ln|Way|Court|Ct|Place|Pl|Circle|Cir)\\b", "category": "PII Patterns", - "description": "Detects street addresses in Australian, US, and UK formats" + "description": "Detects street addresses (number + street name + street type)" } ] } \ No newline at end of file diff --git a/litellm/proxy/management_endpoints/policy_endpoints.py b/litellm/proxy/management_endpoints/policy_endpoints.py index a7e2bae3268..ca6244459df 100644 --- a/litellm/proxy/management_endpoints/policy_endpoints.py +++ b/litellm/proxy/management_endpoints/policy_endpoints.py @@ -6,15 +6,12 @@ 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 +/policy/templates - Get policy templates (GitHub with local fallback) """ import json import os -from importlib.resources import files -from typing import Any, List -import httpx from fastapi import APIRouter, Depends, HTTPException, Request from litellm._logging import verbose_proxy_logger @@ -36,82 +33,6 @@ from litellm.types.proxy.policy_engine import ( router = APIRouter() -# Policy Templates GitHub URL -POLICY_TEMPLATES_GITHUB_URL = ( - "https://raw.githubusercontent.com/BerriAI/litellm/main/policy_templates.json" -) - - -def load_local_policy_templates() -> List[Any]: - """Load the local backup policy templates bundled with the package.""" - try: - content = json.loads( - files("litellm") - .joinpath("policy_templates_backup.json") - .read_text(encoding="utf-8") - ) - return content - except Exception as e: - verbose_proxy_logger.error(f"Failed to load local policy templates backup: {e}") - return [] - - -def fetch_remote_policy_templates(url: str, timeout: int = 5) -> List[Any]: - """ - Fetch policy templates from a remote URL. - - Returns the parsed JSON list. Falls back to local backup on any error. - """ - try: - response = httpx.get(url, timeout=timeout) - response.raise_for_status() - return response.json() - except Exception as e: - verbose_proxy_logger.warning( - f"Failed to fetch policy templates from {url}: {e}. " - "Falling back to local backup." - ) - return load_local_policy_templates() - - -def get_policy_templates_list() -> List[Any]: - """ - Get policy templates with GitHub fallback to local backup. - - 1. Try to fetch from GitHub URL (https://raw.githubusercontent.com/BerriAI/litellm/main/policy_templates.json) - 2. On any failure, fall back to local backup (litellm/policy_templates_backup.json) - 3. Validate that result is a non-empty list - - Set LITELLM_LOCAL_POLICY_TEMPLATES=true to always use local backup. - """ - # Check if we should use local only (LITELLM_LOCAL_POLICY_TEMPLATES=true) - use_local_only = os.getenv("LITELLM_LOCAL_POLICY_TEMPLATES", "").lower() == "true" - - if use_local_only: - verbose_proxy_logger.info( - "Using local policy templates (LITELLM_LOCAL_POLICY_TEMPLATES=true)" - ) - return load_local_policy_templates() - - # Fetch from GitHub (automatically falls back to local on any error) - templates = fetch_remote_policy_templates(POLICY_TEMPLATES_GITHUB_URL) - - # Validate it's a non-empty list - if not isinstance(templates, list): - verbose_proxy_logger.warning( - f"Policy templates is not a list (type={type(templates).__name__}). " - "Using local backup." - ) - return load_local_policy_templates() - - if len(templates) == 0: - verbose_proxy_logger.warning("Policy templates is empty. Using local backup.") - return load_local_policy_templates() - - verbose_proxy_logger.debug(f"Successfully loaded {len(templates)} policy templates") - return templates - - @router.post( "/policy/validate", tags=["policy management"], @@ -342,6 +263,24 @@ async def test_policy_matching( ) +POLICY_TEMPLATES_GITHUB_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/policy_templates.json" + + +def _load_policy_templates_from_local_backup() -> list: + """Load policy templates from local backup file (litellm/policy_templates_backup.json).""" + backup_path = os.path.join( + os.path.dirname(__file__), + "..", + "..", + "policy_templates_backup.json", + ) + path = os.path.abspath(backup_path) + if not os.path.exists(path): + return [] + with open(path, "r") as f: + return json.load(f) + + @router.get( "/policy/templates", tags=["policy management"], @@ -351,24 +290,35 @@ async def test_policy_matching( async def get_policy_templates( request: Request, user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), -) -> List[Any]: +) -> list: """ - Get available policy templates for quick policy setup. + Get policy templates for the UI (pre-configured guardrail combinations). - Returns a list of pre-configured policy templates that users can use - as a starting point for creating their own policies. - - Templates are fetched from GitHub by default, with fallback to local backup. - Set LITELLM_LOCAL_POLICY_TEMPLATES=true to always use local backup. + Fetches from GitHub with automatic fallback to local backup on failure. + Set LITELLM_LOCAL_POLICY_TEMPLATES=true to skip GitHub and use local backup only. """ + use_local = os.getenv("LITELLM_LOCAL_POLICY_TEMPLATES", "").strip().lower() in ( + "true", + "1", + "yes", + ) + if use_local: + return _load_policy_templates_from_local_backup() + try: - templates = get_policy_templates_list() - verbose_proxy_logger.debug(f"Loaded {len(templates)} policy templates") - return templates + from litellm.llms.custom_httpx.http_handler import get_async_httpx_client + from litellm.types.llms.custom_http import httpxSpecialProvider - 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)}", + async_client = get_async_httpx_client( + llm_provider=httpxSpecialProvider.UI, + params={"timeout": 10.0}, ) + response = await async_client.get(POLICY_TEMPLATES_GITHUB_URL) + if response.status_code == 200: + return response.json() + except Exception as e: + verbose_proxy_logger.debug( + "Failed to fetch policy templates from GitHub, using local backup: %s", e + ) + + return _load_policy_templates_from_local_backup() diff --git a/policy_templates.json b/policy_templates.json index 8eff8ead40c..6541839611b 100644 --- a/policy_templates.json +++ b/policy_templates.json @@ -215,7 +215,55 @@ "financial-pii" ], "complexity": "Low", - "guardrailDefinitions": [], + "guardrailDefinitions": [ + { + "guardrail_name": "au-pii-tax-identifiers", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"pattern_type": "prebuilt", "pattern_name": "au_tfn", "action": "MASK"}, + {"pattern_type": "prebuilt", "pattern_name": "au_abn", "action": "MASK"}, + {"pattern_type": "prebuilt", "pattern_name": "au_medicare", "action": "MASK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Masks Australian Tax File Numbers, Business Numbers, and Medicare Numbers"} + }, + { + "guardrail_name": "credentials-api-keys", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"pattern_type": "prebuilt", "pattern_name": "aws_access_key", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "aws_secret_key", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "github_token", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "slack_token", "action": "BLOCK"}, + {"pattern_type": "prebuilt", "pattern_name": "generic_api_key", "action": "BLOCK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Blocks requests containing API keys and credentials (AWS, GitHub, Slack)"} + }, + { + "guardrail_name": "financial-pii", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "patterns": [ + {"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"}, + {"pattern_type": "prebuilt", "pattern_name": "iban", "action": "MASK"} + ], + "pattern_redaction_format": "[{pattern_name}_REDACTED]" + }, + "guardrail_info": {"description": "Masks financial information including credit cards and bank account numbers"} + } + ], "templateData": { "policy_name": "baseline-pii-protection", "description": "Baseline PII protection for internal tools and testing. Focuses on credentials and high-risk identifiers only.",