From 87b9b7318773ebc4ec942b1f8cee0e55e9609e8f Mon Sep 17 00:00:00 2001 From: Krrish Dholakia Date: Fri, 13 Feb 2026 08:44:43 -0800 Subject: [PATCH] fix: address greptile feedback --- .../litellm_content_filter/patterns.json | 10 +++ .../management_endpoints/policy_endpoints.py | 67 +++++++++++++++++++ .../proxy/policy_engine/policy_templates.json | 47 +++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 litellm/proxy/policy_engine/policy_templates.json 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 1eff7804b42..30d8c1e09e3 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json +++ b/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/patterns.json @@ -367,6 +367,16 @@ "pattern": "\\b\\d{1,2}\\.\\d{3}\\.\\d{3}-[\\dXx]\\b", "category": "Brazilian PII Patterns", "description": "Detects Brazilian RG identity card numbers (common pattern for SP, RJ, MG states)" + }, + { + "name": "au_tfn", + "display_name": "TFN (Australian Tax File Number)", + "pattern": "\\b\\d{8,9}\\b", + "category": "PII Patterns", + "action": "MASK", + "description": "Detects Australian TFN with contextual keywords (8–9 digits; matches only near TFN/tax file number context)", + "keyword_pattern": "(?:\\b(?:TFN|T\\.F\\.N\\.|tax\\s+file\\s+number|tax\\s+file\\s+no\\.?|Australian\\s+TFN)\\b)", + "allow_word_numbers": true } ] } \ 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 f9487dc2e59..0c502d3fa19 100644 --- a/litellm/proxy/management_endpoints/policy_endpoints.py +++ b/litellm/proxy/management_endpoints/policy_endpoints.py @@ -6,14 +6,20 @@ 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 - List policy templates (from GitHub with local fallback) """ +import json +import os + from fastapi import APIRouter, Depends, HTTPException, Request from litellm._logging import verbose_proxy_logger +from litellm.llms.custom_httpx.http_handler import get_async_httpx_client from litellm.proxy._types import UserAPIKeyAuth from litellm.proxy.auth.user_api_key_auth import user_api_key_auth from litellm.proxy.management_helpers.utils import management_endpoint_wrapper +from litellm.types.llms.custom_http import httpxSpecialProvider from litellm.types.proxy.policy_engine import ( PolicyGuardrailsResponse, PolicyInfoResponse, @@ -257,3 +263,64 @@ async def test_policy_matching( matching_policies=matching_policy_names, resolved_guardrails=resolved_guardrails, ) + + +# GitHub raw URL for policy templates (with local fallback) +_POLICY_TEMPLATES_GITHUB_URL = ( + "https://raw.githubusercontent.com/litellm/litellm/main/litellm/proxy/policy_engine/policy_templates.json" +) + + +@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 policy templates (pre-configured guardrail combinations). + + Fetches templates from GitHub with local fallback. Uses async HTTP to avoid + blocking the event loop under concurrent load. + """ + # Try GitHub first using async client (do not use sync httpx.get in async context) + try: + client = get_async_httpx_client( + llm_provider=httpxSpecialProvider.UI, + params={"timeout": 5.0}, + ) + response = await client.get(_POLICY_TEMPLATES_GITHUB_URL) + response.raise_for_status() + return response.json() + except Exception as e: + verbose_proxy_logger.debug( + "Failed to fetch policy templates from GitHub (%s), using local fallback: %s", + _POLICY_TEMPLATES_GITHUB_URL, + e, + ) + + # Local fallback: bundled policy_templates.json in policy_engine + fallback_path = os.path.join( + os.path.dirname(__file__), + "..", + "policy_engine", + "policy_templates.json", + ) + try: + with open(fallback_path, "r") as f: + return json.load(f) + except FileNotFoundError: + verbose_proxy_logger.warning( + "Policy templates fallback file not found: %s", fallback_path + ) + return {"templates": []} + except json.JSONDecodeError as e: + verbose_proxy_logger.exception("Invalid JSON in policy_templates.json: %s", e) + raise HTTPException( + status_code=500, + detail="Invalid policy templates configuration", + ) diff --git a/litellm/proxy/policy_engine/policy_templates.json b/litellm/proxy/policy_engine/policy_templates.json new file mode 100644 index 00000000000..3fcae2153f0 --- /dev/null +++ b/litellm/proxy/policy_engine/policy_templates.json @@ -0,0 +1,47 @@ +{ + "templates": [ + { + "id": "baseline-pii-protection", + "name": "Baseline PII Protection", + "description": "Base policy that adds common PII and content guardrails for all requests.", + "guardrailDefinitions": [ + { + "guardrail_name": "pii_blocker", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "default_on": true + }, + "guardrail_info": { + "description": "Blocks or masks PII (e.g. SSN, email, phone) in requests and responses." + } + }, + { + "guardrail_name": "phi_blocker", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "default_on": true + }, + "guardrail_info": { + "description": "Blocks or masks protected health information (PHI)." + } + }, + { + "guardrail_name": "prompt_injection", + "litellm_params": { + "guardrail": "litellm_content_filter", + "mode": "pre_call", + "default_on": true + }, + "guardrail_info": { + "description": "Detects and blocks prompt injection attempts." + } + } + ], + "templateData": { + "guardrails_add": ["pii_blocker", "phi_blocker", "prompt_injection"] + } + } + ] +}