bug: strict validation for facet_filters list in core validators
- Dominant language
- Python
- Stars
- 451
- Forks
- 702
- Avg merge
- 22h 59m
- Merged PRs (30d)
- 91
Description
**Describe the bug**
The `validate_facet_filters` helper in `backend/apps/core/validators.py` is intended to accept a list of Algolia facet filters (strings in `key:value` format). however the current implementation is extremely permissive and silently accepts a wide range of invalid input such as:
* empty lists (`[]`)
* duplicate filters (`["type:project","type:project"]`)
* strings without a colon (`["nocolon"]`)
* filters with empty key or value (`["key:",":value"]`)
* non-string or blank entries
Because the validator does nothing in these cases, malformed data can be passed through to the Algolia proxy endpoint and ultimately cause confusing errors or unexpected search behaviour.
**To Reproduce**
Steps to reproduce the behaviour:
1. Call `validate_facet_filters` from Python with any of the invalid examples above.
2. No exception is raised.
3. Later, a request with the resulting filters may hit Algolia and return a 400 or produce an empty result set without clear explanation.
**Expected behavior**
`validate_facet_filters` should raise `ValidationError` for any input that is not a non-empty list of non-duplicate strings formatted as `key:value` with both key and value non-blank.
**Proposed Solution**
Enhance the validator with explicit checks:
```python
from django.core.exceptions import ValidationError
def validate_facet_filters(facet_filters: list) -> None:
"""Validate facet filters - list of 'key:value' strings."""
if not isinstance(facet_filters, list):
raise ValidationError("facet_filters must be a list")
# allow the caller to pass an empty list explicitly
if not facet_filters:
return
seen: set[str] = set()
for i, filter_str in enumerate(facet_filters):
if not isinstance(filter_str, str) or not filter_str.strip():
raise ValidationError(f"Filter at index {i} must be a non-empty string")
if ':' not in filter_str:
raise ValidationError(
f"Invalid filter format at index {i}: '{filter_str}'. "
"expected 'key:value'"
)
key, value = filter_str.split(':', 1)
if not key.strip() or not value.strip():
raise ValidationError(
f"Key and value may not be empty: '{filter_str}'"
)
lower = filter_str.lower()
if lower in seen:
raise ValidationError(f"Duplicate filter: '{filter_str}'")
seen.add(lower)
```
Add unit tests covering each invalid case and a valid example.
**Impact**
- Prevents malformed facet filters from reaching Algolia
- Improves developer experience when constructing search queries
- Avoids mysterious 400 errors in production
**Are you going to work on fixing this?**
- [x] Yes
- [ ] No
**Additional context**
No existing GitHub issue covers this. The only search result for "facet filter" is an unrelated feature request (#3177).
Contributor guide
Assessment
This issue has not been assessed yet.