Refactor filter configuration with regex validation

- Add regex validation utility for query strings
- Update filter_config_service to use regex validation
- Add comprehensive test coverage for regex validator
- Update exception handling for validation errors
- Update documentation for tasks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-01 18:17:12 +02:00
parent 445c2c5418
commit 60d9c5b340
6 changed files with 367 additions and 41 deletions

View File

@@ -256,6 +256,56 @@ class FilterInvalidRegexError(BadRequestError):
return {"pattern": self.pattern, "error": self.error}
class FilterRegexTooLongError(BadRequestError):
"""Raised when a regex pattern exceeds the maximum length."""
error_code: str = "filter_regex_too_long"
def __init__(self, pattern: str, max_length: int) -> None:
"""Initialize with the pattern and maximum allowed length.
Args:
pattern: The regex pattern that is too long.
max_length: The maximum allowed length.
"""
self.pattern = pattern
self.max_length = max_length
self.actual_length = len(pattern)
super().__init__(
f"Regex pattern exceeds maximum length of {max_length} characters: "
f"{self.actual_length} provided"
)
def get_error_metadata(self) -> dict[str, str | int | float | bool | None]:
return {
"pattern_length": self.actual_length,
"max_length": self.max_length,
}
class FilterRegexTimeoutError(BadRequestError):
"""Raised when a regex pattern compilation times out (possible ReDoS attack)."""
error_code: str = "filter_regex_timeout"
def __init__(self, pattern: str, timeout_seconds: int) -> None:
"""Initialize with the pattern and timeout value.
Args:
pattern: The regex pattern that timed out.
timeout_seconds: The timeout value in seconds.
"""
self.pattern = pattern
self.timeout_seconds = timeout_seconds
super().__init__(
f"Regex pattern compilation timed out after {timeout_seconds}s "
f"(possible ReDoS attack). Pattern is too complex or causes catastrophic backtracking."
)
def get_error_metadata(self) -> dict[str, str | int | float | bool | None]:
return {"timeout_seconds": self.timeout_seconds}
class JailNotFoundInConfigError(NotFoundError):
"""Raised when the requested jail name is not defined in any config file."""