address greptile review feedback (greploop iteration 1)

- Remove unused HTTPException import from test file
- Add keyword_pattern to eu_vat for contextual VAT matching
- Add allow_word_numbers: false to eu_passport_generic
- Add negative test cases for EU VAT false positives
- All 5 Greptile comments addressed
This commit is contained in:
Ishaan Jaffer 2026-02-16 14:57:26 -08:00
parent 4542f3256f
commit 87984ad488
4 changed files with 107 additions and 5 deletions

View file

@ -679,5 +679,97 @@
],
"guardrails_remove": []
}
},
{
"id": "gdpr-eu-pii-protection",
"title": "GDPR Art. 32 — EU PII Protection",
"description": "GDPR Article 32 compliance for EU personal data protection. Masks French national IDs (NIR/INSEE), EU IBANs, French phone numbers, EU VAT numbers, EU passport numbers, and email addresses. Suitable for applications processing EU citizen data requiring GDPR compliance.",
"region": "EU",
"icon": "ShieldCheckIcon",
"iconColor": "text-indigo-500",
"iconBg": "bg-indigo-50",
"guardrails": [
"gdpr-eu-national-identifiers",
"gdpr-eu-financial-data",
"gdpr-eu-contact-information",
"gdpr-eu-business-identifiers"
],
"complexity": "Medium",
"guardrailDefinitions": [
{
"guardrail_name": "gdpr-eu-national-identifiers",
"litellm_params": {
"guardrail": "litellm_content_filter",
"mode": "pre_call",
"patterns": [
{"pattern_type": "prebuilt", "pattern_name": "fr_nir", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "eu_passport_generic", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "passport_france", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "passport_germany", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "passport_netherlands", "action": "MASK"}
],
"pattern_redaction_format": "[{pattern_name}_REDACTED]"
},
"guardrail_info": {
"description": "Masks EU national identification numbers including French NIR/INSEE and EU passport numbers for GDPR compliance"
}
},
{
"guardrail_name": "gdpr-eu-financial-data",
"litellm_params": {
"guardrail": "litellm_content_filter",
"mode": "pre_call",
"patterns": [
{"pattern_type": "prebuilt", "pattern_name": "eu_iban_enhanced", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "iban", "action": "MASK"}
],
"pattern_redaction_format": "[IBAN_REDACTED]"
},
"guardrail_info": {
"description": "Masks EU bank account numbers (IBANs) to protect financial data under GDPR Article 32"
}
},
{
"guardrail_name": "gdpr-eu-contact-information",
"litellm_params": {
"guardrail": "litellm_content_filter",
"mode": "pre_call",
"patterns": [
{"pattern_type": "prebuilt", "pattern_name": "email", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "fr_phone", "action": "MASK"},
{"pattern_type": "prebuilt", "pattern_name": "fr_postal_code", "action": "MASK"}
],
"pattern_redaction_format": "[{pattern_name}_REDACTED]"
},
"guardrail_info": {
"description": "Masks contact information including emails, French phone numbers, and postal codes for EU data subjects"
}
},
{
"guardrail_name": "gdpr-eu-business-identifiers",
"litellm_params": {
"guardrail": "litellm_content_filter",
"mode": "pre_call",
"patterns": [
{"pattern_type": "prebuilt", "pattern_name": "eu_vat", "action": "MASK"}
],
"pattern_redaction_format": "[VAT_NUMBER_REDACTED]"
},
"guardrail_info": {
"description": "Masks EU VAT identification numbers to protect business entity information under GDPR"
}
}
],
"templateData": {
"policy_name": "gdpr-eu-pii-protection",
"description": "GDPR Article 32 compliance policy for EU personal data protection. Masks French national IDs, EU IBANs, phone numbers, VAT numbers, passports, and contact information.",
"guardrails_add": [
"gdpr-eu-national-identifiers",
"gdpr-eu-financial-data",
"gdpr-eu-contact-information",
"gdpr-eu-business-identifiers"
],
"guardrails_remove": []
}
}
]

View file

@ -415,7 +415,7 @@
{
"name": "fr_phone",
"display_name": "Phone Number (France)",
"pattern": "(?:\\+33|0033|0)[1-9][0-9]{8}\\b",
"pattern": "(?:(?:\\+33|0033)\\b|\\b0)[1-9][0-9]{8}\\b",
"category": "EU PII Patterns",
"description": "Detects French phone numbers in various formats (+33, 0033, or 0 prefix followed by 9 digits starting with 1-9)"
},
@ -424,14 +424,18 @@
"display_name": "VAT Number (EU)",
"pattern": "\\b(AT|BE|BG|CY|CZ|DE|DK|EE|EL|ES|FI|FR|HR|HU|IE|IT|LT|LU|LV|MT|NL|PL|PT|RO|SE|SI|SK)[0-9A-Z]{8,12}\\b",
"category": "EU PII Patterns",
"description": "Detects EU VAT identification numbers (2-letter country code + 8-12 alphanumeric characters covering all EU member states)"
"description": "Detects EU VAT identification numbers (2-letter country code + 8-12 alphanumeric characters covering all EU member states)",
"keyword_pattern": "\\b(?:VAT|V\\.A\\.T\\.|TVA|IVA|BTW|MWST|value\\s*added\\s*tax|tax\\s*number|tax\\s*id|fiscal\\s*number|fiscal\\s*code)\\b",
"allow_word_numbers": false
},
{
"name": "eu_passport_generic",
"display_name": "Passport Number (EU Generic)",
"pattern": "\\b[0-9]{2}[A-Z]{2}[0-9]{5}\\b",
"category": "EU PII Patterns",
"description": "Detects generic EU passport format (2 digits + 2 letters + 5 digits) - covers France and similar EU formats"
"description": "Detects generic EU passport format (2 digits + 2 letters + 5 digits) - covers France and similar EU formats",
"keyword_pattern": "\\b(?:passport|passeport|travel\\s*document|document\\s*number|reisepass|paspoort|paszport)\\b",
"allow_word_numbers": false
},
{
"name": "fr_postal_code",

View file

@ -57,6 +57,14 @@ class TestEUVAT:
assert pattern.search("DE123456789") is not None
assert pattern.search("IT12345678901") is not None
def test_common_words_not_matched(self):
"""Test that common English words starting with country codes are not matched"""
pattern = get_compiled_pattern("eu_vat")
# Common words that could false-positive without proper context
assert pattern.search("DEPARTMENT") is None
assert pattern.search("ITALY") is None
assert pattern.search("DECEMBER") is None
class TestEUPassportGeneric:
"""Test generic EU passport detection"""

View file

@ -10,8 +10,6 @@ import pytest
sys.path.insert(0, os.path.abspath("../../"))
from fastapi import HTTPException
from litellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.content_filter import (
ContentFilterGuardrail,
)