refactor(tasks): extract filename regex to shared constant

Move the valid filename regex pattern to a shared constant in `app/utils/filename_utils.py` and update both the task logic and security tests to use it. This eliminates duplication and ensures consistency across the codebase.

Changes:
- Defined `VALID_FILENAME_PATTERN` and `VALID_FILENAME_RE` in `app/utils/filename_utils.py`.
- Updated `app/tasks/extract_metadata_with_gpt.py` to use `VALID_FILENAME_RE`.
- Updated `tests/test_path_traversal_security.py` to use `VALID_FILENAME_PATTERN`.

This refactoring addresses the duplication mentioned in the TODO in `tests/test_path_traversal_security.py`.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-03-23 18:58:29 +00:00
parent 031b51b9b8
commit 6f510d5a2d
3 changed files with 201 additions and 194 deletions
+3 -2
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__)
@@ -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 = [