@@ -373,9 +373,13 @@ def text_fields(self, eql_schema: ecs.KqlSchema2Eql | endgame.EndgameSchema) ->
373373 def unique_fields (self ) -> list [str ]: # type: ignore[reportIncompatibleMethodOverride]
374374 return list ({str (f ) for f in self .ast if isinstance (f , eql .ast .Field )}) # type: ignore[reportUnknownVariableType]
375375
376- def auto_add_field (self , validation_checks_error : eql .EqlParseError , index_or_dataview : str ) -> None :
376+ def auto_add_field (
377+ self , validation_checks_error : eql .EqlParseError , index_or_dataview : str , field : str | None = None
378+ ) -> None :
377379 """Auto add a missing field to the schema."""
378- field_name = extract_error_field (self .query , validation_checks_error )
380+ field_name = field
381+ if not field :
382+ field_name = extract_error_field (self .query , validation_checks_error )
379383 if not field_name :
380384 raise ValueError ("No field name found" )
381385 field_type = ecs .get_all_flattened_schema ().get (field_name )
@@ -606,7 +610,7 @@ def validate(self, data: "QueryRuleData", meta: RuleMeta, max_attempts: int = 10
606610 )
607611 first_error : EQL_ERROR_TYPES | ValueError | None = None
608612 for t in ordered_targets :
609- exc = self .validate_query_text_with_schema (
613+ exc , field = self .validate_query_text_with_schema (
610614 t .query_text ,
611615 t .schema ,
612616 err_trailer = t .err_trailer ,
@@ -629,7 +633,7 @@ def validate(self, data: "QueryRuleData", meta: RuleMeta, max_attempts: int = 10
629633 and RULES_CONFIG .auto_gen_schema_file
630634 and data .index_or_dataview
631635 ):
632- self .auto_add_field (first_error , data .index_or_dataview [0 ]) # type: ignore[reportArgumentType]
636+ self .auto_add_field (first_error , data .index_or_dataview [0 ], field = field ) # type: ignore[reportArgumentType]
633637 continue
634638
635639 # Raise the enriched parse error (includes target trailer + metadata)
@@ -645,7 +649,7 @@ def validate_query_text_with_schema( # noqa: PLR0913
645649 min_stack_version : str ,
646650 beat_types : list [str ] | None = None ,
647651 integration_types : list [str ] | None = None ,
648- ) -> EQL_ERROR_TYPES | ValueError | None :
652+ ) -> tuple [ EQL_ERROR_TYPES | ValueError | None , str | None ] :
649653 """Validate the provided EQL query text against the schema (variant of validate_query_with_schema)."""
650654 try :
651655 config = set_eql_config (min_stack_version )
@@ -663,7 +667,7 @@ def validate_query_text_with_schema( # noqa: PLR0913
663667 and ("Unknown field" in message or "Field not recognized" in message )
664668 and f"?{ field } " in self .query
665669 ):
666- return None
670+ return None , field
667671 if "Unknown field" in message and beat_types :
668672 trailer_parts .insert (0 , "Try adding event.module or event.dataset to specify beats module" )
669673 elif "Field not recognized" in message and isinstance (schema , ecs .KqlSchema2Eql ):
@@ -691,10 +695,11 @@ def validate_query_text_with_schema( # noqa: PLR0913
691695 exc .source , # type: ignore[reportUnknownArgumentType]
692696 len (exc .caret .lstrip ()),
693697 trailer = trailer ,
694- )
698+ ), field
695699 except Exception as exc : # noqa: BLE001
696700 print (err_trailer )
697- return exc # type: ignore[reportReturnType]
701+ return exc , None # type: ignore[reportReturnType]
702+ return None , None
698703
699704 def validate_rule_type_configurations (self , data : EQLRuleData , meta : RuleMeta ) -> tuple [list [str ], bool ]:
700705 """Validate EQL rule type configurations (timestamp_field, event_category_override, tiebreaker_field).
@@ -929,20 +934,11 @@ def remote_validate_rule( # noqa: PLR0913
929934 return response
930935
931936
932- def extract_error_field (source : str , exc : eql .EqlParseError | kql .KqlParseError , max_attempts : int = 10 ) -> str | None :
937+ def extract_error_field (source : str , exc : eql .EqlParseError | kql .KqlParseError ) -> str | None :
933938 """Extract the field name from an EQL or KQL parse error."""
934- # If error reported in subquery and exc references exc.source rather than source, adjust source accordingly
935- if exc .source != source and len (exc .source .splitlines ()) > exc .line : # type: ignore[reportUnknownMemberType]
936- source = exc .source # type: ignore[reportUnknownMemberType]
937- lines = source .splitlines () # type: ignore[reportUnknownMemberType]
939+ lines = source .splitlines ()
938940 mod = - 1 if exc .line == len (lines ) else 0 # type: ignore[reportUnknownMemberType]
939941 line = lines [exc .line + mod ] # type: ignore[reportUnknownMemberType]
940- start : int = exc .column # type: ignore[reportUnknownMemberType]
941- # Handle cases where subqueries cause column alignment to be off
942- for _ in range (max_attempts ):
943- if line [start - 1 ].isalnum () or line [start - 1 ] == "." : # type: ignore[reportUnknownMemberType]
944- start -= 1 # type: ignore[reportUnknownMemberType]
945- else :
946- break
942+ start = exc .column # type: ignore[reportUnknownMemberType]
947943 stop = start + len (exc .caret .strip ()) # type: ignore[reportUnknownVariableType]
948944 return re .sub (r"^\W+|\W+$" , "" , line [start :stop ]) # type: ignore[reportUnknownArgumentType]
0 commit comments