Merge pull request #640 from christianlouis/refactor-filename-regex-constant-13933144971632372772

Refactor filename regex to shared constant
This commit is contained in:
Christian Krakau-Louis
2026-03-14 12:44:11 +01:00
committed by GitHub
3 changed files with 201 additions and 194 deletions
+4 -3
View File
@@ -14,6 +14,7 @@ from app.tasks.embed_metadata_into_pdf import embed_metadata_into_pdf
from app.tasks.retry_config import BaseTaskWithRetry from app.tasks.retry_config import BaseTaskWithRetry
from app.utils import log_task_progress from app.utils import log_task_progress
from app.utils.ai_provider import get_ai_provider from app.utils.ai_provider import get_ai_provider
from app.utils.filename_utils import VALID_FILENAME_RE
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -75,7 +76,7 @@ def extract_metadata_with_gpt(self, filename: str, cleaned_text: str, file_id: i
"Your task is to analyze the given text and return a well-structured JSON object.\n\n" "Your task is to analyze the given text and return a well-structured JSON object.\n\n"
"Extract and return the following fields:\n" "Extract and return the following fields:\n"
"1. **filename**: Machine-readable filename " "1. **filename**: Machine-readable filename "
"(YYYY-MM-DD_DescriptiveTitle, use only letters, numbers, periods, and underscores).\n" "(YYYY-MM-DD_DescriptiveTitle, use only letters, numbers, spaces, dashes, periods, and underscores).\n"
'2. **empfaenger**: The recipient, or "Unknown" if not found.\n' '2. **empfaenger**: The recipient, or "Unknown" if not found.\n'
'3. **absender**: The sender, or "Unknown" if not found.\n' '3. **absender**: The sender, or "Unknown" if not found.\n'
"4. **correspondent**: The entity or company that issued the document " "4. **correspondent**: The entity or company that issued the document "
@@ -148,12 +149,12 @@ def extract_metadata_with_gpt(self, filename: str, cleaned_text: str, file_id: i
suggested_filename = metadata.get("filename", "") suggested_filename = metadata.get("filename", "")
if suggested_filename: if suggested_filename:
# Check if filename contains only safe characters AND explicitly check for ".." # Check if filename contains only safe characters AND explicitly check for ".."
# Defense in depth: While the regex [\w\-\. ]+ already excludes / and \, # Defense in depth: While the regex VALID_FILENAME_PATTERN already excludes / and \,
# we explicitly reject ".." to guard against: # we explicitly reject ".." to guard against:
# 1. Potential locale-specific \w behavior # 1. Potential locale-specific \w behavior
# 2. Files literally named ".." which are valid but problematic # 2. Files literally named ".." which are valid but problematic
# 3. Future code changes that might relax the regex # 3. Future code changes that might relax the regex
if not re.match(r"^[\w\-\. ]+$", suggested_filename) or ".." in suggested_filename: if not VALID_FILENAME_RE.match(suggested_filename) or ".." in suggested_filename:
logger.warning(f"[{task_id}] Invalid filename format from GPT: '{suggested_filename}', using fallback") logger.warning(f"[{task_id}] Invalid filename format from GPT: '{suggested_filename}', using fallback")
# Reset to empty to trigger fallback to original filename # Reset to empty to trigger fallback to original filename
metadata["filename"] = "" metadata["filename"] = ""
+5
View File
@@ -8,6 +8,11 @@ from pathlib import Path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Pattern for valid filenames (alphanumeric, dash, underscore, period, and space)
# Used for validating GPT-provided filenames and other inputs
VALID_FILENAME_PATTERN = r"^[\w\-\. ]+$"
VALID_FILENAME_RE = re.compile(VALID_FILENAME_PATTERN)
def get_unique_filename(original_path: str, check_exists_func: Callable[[str], bool] | None = None) -> str: def get_unique_filename(original_path: str, check_exists_func: Callable[[str], bool] | None = None) -> str:
""" """
+4 -3
View File
@@ -212,9 +212,10 @@ class TestExtractMetadataFilenameValidation:
"""Test that invalid filename formats are rejected.""" """Test that invalid filename formats are rejected."""
import re import re
# Valid pattern from extract_metadata_with_gpt.py from app.utils.filename_utils import VALID_FILENAME_PATTERN
# TODO: Consider extracting this to a shared constant to avoid duplication
valid_pattern = r"^[\w\-\. ]+$" # Valid pattern from app.utils.filename_utils
valid_pattern = VALID_FILENAME_PATTERN
# Test valid filenames # Test valid filenames
valid_filenames = [ valid_filenames = [