@@ -159,6 +159,29 @@ def get_simulated_index_template_mappings(elastic_client: Elasticsearch, name: s
159159 return template ["template" ]["mappings" ]["properties" ]
160160
161161
162+ def prune_mappings_of_unsupported_types (
163+ integration : str , stream : str , stream_mappings : dict [str , Any ], log : Callable [[str ], None ]
164+ ) -> dict [str , Any ]:
165+ """Prune fields with unsupported types (ES|QL) from the provided mappings."""
166+ nested_multifields = find_nested_multifields (stream_mappings )
167+ for field in nested_multifields :
168+ field_name = str (field ).split (".fields." )[0 ].replace ("." , ".properties." ) + ".fields"
169+ log (
170+ f"Warning: Nested multi-field `{ field } ` found in `{ integration } -{ stream } `. "
171+ f"Removing parent field from schema for ES|QL validation."
172+ )
173+ delete_nested_key_from_dict (stream_mappings , field_name )
174+ nested_flattened_fields = find_flattened_fields_with_subfields (stream_mappings )
175+ for field in nested_flattened_fields :
176+ field_name = str (field ).split (".fields." )[0 ].replace ("." , ".properties." ) + ".fields"
177+ log (
178+ f"Warning: flattened field `{ field } ` found in `{ integration } -{ stream } ` with sub fields. "
179+ f"Removing parent field from schema for ES|QL validation."
180+ )
181+ delete_nested_key_from_dict (stream_mappings , field_name )
182+ return stream_mappings
183+
184+
162185def prepare_integration_mappings ( # noqa: PLR0913
163186 rule_integrations : list [str ],
164187 event_dataset_integrations : list [EventDataset ],
@@ -199,22 +222,7 @@ def prepare_integration_mappings( # noqa: PLR0913
199222 for stream in package_schema :
200223 flat_schema = package_schema [stream ]
201224 stream_mappings = flat_schema_to_index_mapping (flat_schema )
202- nested_multifields = find_nested_multifields (stream_mappings )
203- for field in nested_multifields :
204- field_name = str (field ).split (".fields." )[0 ].replace ("." , ".properties." ) + ".fields"
205- log (
206- f"Warning: Nested multi-field `{ field } ` found in `{ integration } -{ stream } `. "
207- f"Removing parent field from schema for ES|QL validation."
208- )
209- delete_nested_key_from_dict (stream_mappings , field_name )
210- nested_flattened_fields = find_flattened_fields_with_subfields (stream_mappings )
211- for field in nested_flattened_fields :
212- field_name = str (field ).split (".fields." )[0 ].replace ("." , ".properties." ) + ".fields"
213- log (
214- f"Warning: flattened field `{ field } ` found in `{ integration } -{ stream } ` with sub fields. "
215- f"Removing parent field from schema for ES|QL validation."
216- )
217- delete_nested_key_from_dict (stream_mappings , field_name )
225+ stream_mappings = prune_mappings_of_unsupported_types (integration , stream , stream_mappings , log )
218226 utils .combine_dicts (integration_mappings , deepcopy (stream_mappings ))
219227 index_lookup [f"{ integration } -{ stream } " ] = stream_mappings
220228
@@ -285,17 +293,19 @@ def get_filtered_index_schema(
285293 filtered_index_lookup = {
286294 key .replace ("logs-endpoint." , "logs-endpoint.events." ): value for key , value in filtered_index_lookup .items ()
287295 }
288- # This overwrites any conflicts with non-ecs preferring what is defined in custom mappings
289- # This can be done safely as we have a specific non-ecs-index that will also be included with only non-ecs mappings
290- filtered_index_lookup .update (non_ecs_mapping )
291- filtered_index_lookup .update (custom_mapping )
292296
293297 # Reduce the combined mappings to only the matched indices (local schema validation source of truth)
294298 # Custom and non-ecs mappings are filtered before being sent to this function in prepare mappings
295299 combined_mappings : dict [str , Any ] = {}
296300 utils .combine_dicts (combined_mappings , deepcopy (ecs_schema ))
297301 for match in matches :
298- utils .combine_dicts (combined_mappings , deepcopy (filtered_index_lookup .get (match , {})))
302+ base = filtered_index_lookup .get (match , {})
303+ # Update filtered index with non-ecs and custom mappings
304+ # Need to user a merge here to not overwrite existing fields
305+ utils .combine_dicts (base , deepcopy (non_ecs_mapping .get (match , {})))
306+ utils .combine_dicts (base , deepcopy (custom_mapping .get (match , {})))
307+ filtered_index_lookup [match ] = base
308+ utils .combine_dicts (combined_mappings , deepcopy (base ))
299309
300310 # Reduce the index lookup to only the matched indices (remote/Kibana schema validation source of truth)
301311 filtered_index_mapping : dict [str , Any ] = {}
@@ -473,8 +483,12 @@ def prepare_mappings( # noqa: PLR0913
473483 index_mapping = utils .convert_to_nested_schema (index_mapping )
474484 non_ecs_mapping .update ({index : index_mapping })
475485
486+ # These need to be handled separately as we need to be able to validate non-ecs fields as a whole
487+ # and also at a per index level as custom schemas can override non-ecs fields and/or indices
476488 non_ecs_schema = ecs .flatten (non_ecs_schema )
477489 non_ecs_schema = utils .convert_to_nested_schema (non_ecs_schema )
490+ non_ecs_schema = prune_mappings_of_unsupported_types ("non-ecs" , "non-ecs" , non_ecs_schema , log )
491+ non_ecs_mapping = prune_mappings_of_unsupported_types ("non-ecs" , "non-ecs" , non_ecs_mapping , log )
478492
479493 # Load custom schema and convert to index mapping format (nested schema)
480494 custom_mapping : dict [str , Any ] = {}
@@ -484,6 +498,7 @@ def prepare_mappings( # noqa: PLR0913
484498 index_mapping = ecs .flatten (index_mapping )
485499 index_mapping = utils .convert_to_nested_schema (index_mapping )
486500 custom_mapping .update ({index : index_mapping })
501+ custom_mapping = prune_mappings_of_unsupported_types ("custom" , "custom" , custom_mapping , log )
487502
488503 # Load ECS in an index mapping format (nested schema)
489504 current_version = Version .parse (load_current_package_version (), optional_minor_and_patch = True )
@@ -499,5 +514,6 @@ def prepare_mappings( # noqa: PLR0913
499514 if (not integration_mappings or existing_mappings ) and not non_ecs_schema and not ecs_schema :
500515 raise ValueError ("No mappings found" )
501516 index_lookup .update ({"rule-non-ecs-index" : non_ecs_schema })
517+ utils .combine_dicts (combined_mappings , deepcopy (non_ecs_schema ))
502518
503519 return existing_mappings , index_lookup , combined_mappings
0 commit comments