Skip to content

Commit 4b36fbf

Browse files
authored
fix(issue-search): correctly parse negated contains filters (#105699)
Fixes SENTRY-44YF In some (very specific) queries, we fail to unpack issue search conditions correctly. More specifically, when we have a negation, plus a 'contains' filter, plus wildcards, we end up with one too many levels of nesting, leading to the error. We can unpack this condition to OR everything together and handle it correctly. My understanding is that a more thorough solution is to migrate the issue search to use snql. I opted for this solution since it is considerably simpler, and I don't see an easy way to do this migration. example: `!title:[*test*,*test2*]`
1 parent 0dc92ed commit 4b36fbf

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

src/sentry/search/events/filter.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -669,9 +669,19 @@ def convert_search_filter_to_snuba_query(
669669
# together. Otherwise just return the raw condition, so that it can be
670670
# used correctly in aggregates.
671671
if is_null_condition:
672-
return [is_null_condition, condition]
673-
else:
674-
return condition
672+
return [is_null_condition, *_flatten_conditions(condition)]
673+
return condition
674+
675+
676+
def _flatten_conditions(cond: list[Any]) -> list[Any]:
677+
"""
678+
Flatten nested legacy conditions into a flat list. A legacy condition is
679+
[lhs, op_string, rhs]. Wildcard processing can create nested lists that
680+
snuba_sdk.legacy.parse_condition cannot handle.
681+
"""
682+
if len(cond) == 3 and isinstance(cond[1], str):
683+
return [cond]
684+
return [c for item in cond if isinstance(item, list) for c in _flatten_conditions(item)]
675685

676686

677687
def format_search_filter(term, params):

tests/sentry/issues/endpoints/test_group_event_details.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,23 @@ def test_query_title(self) -> None:
403403
assert response.data["previousEventID"] is None
404404
assert response.data["nextEventID"] is None
405405

406+
def test_query_title_not_in_with_wildcards(self) -> None:
407+
event_e = self.store_event(
408+
data={
409+
"event_id": "e" * 32,
410+
"environment": "staging",
411+
"timestamp": before_now(minutes=1).isoformat(),
412+
"fingerprint": ["group-title-wildcard"],
413+
"message": "some other title",
414+
},
415+
project_id=self.project_1.id,
416+
)
417+
418+
url = f"/api/0/issues/{event_e.group.id}/events/recommended/"
419+
response = self.client.get(url, {"query": '!title:["*value1*", "*value2*"]'}, format="json")
420+
421+
assert response.status_code == 200, response.content
422+
406423
def test_query_issue_platform_title(self) -> None:
407424
issue_title = "king of england"
408425
occurrence, group_info = self.process_occurrence(

0 commit comments

Comments
 (0)