Skip to content

Commit 4f3ca56

Browse files
Copilotthomaspatzke
andcommitted
Move prefix extraction to finalize_query_default to fix data model compat
The prefix extraction in finish_query was breaking finalize_query_data_model because it altered the query format that data model handling expected. Now finish_query keeps the simple format (\n| rex...\n| eval...\n| search <query>) and stores the deferred condition field names on state. finalize_query_default uses those field names to extract non-deferred leading conditions and place them before the deferred pipeline commands. Co-authored-by: thomaspatzke <1845601+thomaspatzke@users.noreply.github.com> Agent-Logs-Url: https://github.com/SigmaHQ/pySigma-backend-splunk/sessions/a4e1c291-7dee-4028-96db-41812064da2a
1 parent 46fea1f commit 4f3ca56

1 file changed

Lines changed: 43 additions & 39 deletions

File tree

sigma/backends/splunk/splunk.py

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -347,49 +347,19 @@ def finish_query(
347347

348348
if deferred_regex_or_expressions:
349349
# Collect all condition field names created by deferred OR
350-
# regex expressions before resetting, so we can identify
351-
# which leading query parts don't depend on them.
352-
deferred_condition_fields = (
350+
# regex expressions before resetting, so finalize methods
351+
# can identify which query parts don't depend on them.
352+
state.processing_state["deferred_or_condition_fields"] = (
353353
SplunkDeferredORRegularExpression.get_all_condition_fields()
354354
)
355355
SplunkDeferredORRegularExpression.reset()
356356
state.deferred[:] = remaining_deferred
357-
358-
# Extract leading field=value conditions that don't reference
359-
# any deferred condition field so they are placed before the
360-
# deferred rex/eval pipeline commands instead of ending up
361-
# inside the trailing "| search" clause.
362-
prefix_parts = []
363-
pos = 0
364-
while pos < len(query):
365-
m = self._field_eq_val_re.match(query, pos)
366-
if m and m.group(1) not in deferred_condition_fields:
367-
prefix_parts.append(m.group().strip())
368-
pos = m.end()
369-
else:
370-
break
371-
372-
if prefix_parts:
373-
prefix = " ".join(prefix_parts)
374-
remaining_query = query[pos:]
375-
query = (
376-
prefix
377-
+ self.deferred_start
378-
+ self.deferred_separator.join(
379-
deferred_regex_or_expressions
380-
)
381-
+ "\n| search "
382-
+ remaining_query
383-
)
384-
else:
385-
query = (
386-
self.deferred_start
387-
+ self.deferred_separator.join(
388-
deferred_regex_or_expressions
389-
)
390-
+ "\n| search "
391-
+ query
392-
)
357+
query = (
358+
self.deferred_start
359+
+ self.deferred_separator.join(deferred_regex_or_expressions)
360+
+ "\n| search "
361+
+ query
362+
)
393363

394364
return super().finish_query(rule, query, state)
395365

@@ -400,6 +370,40 @@ def finalize_query_default(
400370
index: int,
401371
state: ConversionState,
402372
) -> str:
373+
# When OR-ed regex expressions are deferred, extract leading field=value
374+
# conditions that don't depend on any deferred eval field and place them
375+
# before the deferred rex/eval pipeline commands. This ensures conditions
376+
# like index/source are at the beginning of the query for efficient
377+
# initial data retrieval.
378+
deferred_condition_fields = state.processing_state.get(
379+
"deferred_or_condition_fields"
380+
)
381+
search_marker = "\n| search "
382+
if deferred_condition_fields and search_marker in query:
383+
marker_idx = query.index(search_marker)
384+
deferred_part = query[:marker_idx]
385+
search_query = query[marker_idx + len(search_marker) :]
386+
387+
prefix_parts = []
388+
pos = 0
389+
while pos < len(search_query):
390+
m = self._field_eq_val_re.match(search_query, pos)
391+
if m and m.group(1) not in deferred_condition_fields:
392+
prefix_parts.append(m.group().strip())
393+
pos = m.end()
394+
else:
395+
break
396+
397+
if prefix_parts:
398+
prefix = " ".join(prefix_parts)
399+
remaining_query = search_query[pos:]
400+
query = (
401+
prefix
402+
+ deferred_part
403+
+ search_marker
404+
+ remaining_query
405+
)
406+
403407
if isinstance(rule, SigmaRule) and rule.fields:
404408
return query + " | table " + ",".join(rule.fields)
405409
return query

0 commit comments

Comments
 (0)