@@ -367,16 +367,60 @@ def analyticsToDf(src):
367367 analytics = src .query ([Filter ("type" , "=" , "x-mitre-analytic" )])
368368 analytics = remove_revoked_deprecated (analytics )
369369
370+ # Detection strategies (needed for analytics to detection strategies relationship)
371+ detection_strategies = src .query ([Filter ("type" , "=" , "x-mitre-detection-strategy" )])
372+ detection_strategies = remove_revoked_deprecated (detection_strategies )
373+
370374 dataframes = {}
371375 if analytics :
372376 analytic_rows = []
377+ logsource_rows = []
378+ analytic_to_ds_rows = []
379+
380+ # analytics to detection strategies
381+ analytic_to_ds_map = {}
382+ for ds in detection_strategies :
383+ for analytic_id in ds .get ("x_mitre_analytic_refs" , []):
384+ analytic_to_ds_map .setdefault (analytic_id , []).append (
385+ {"detection_strategy_id" : ds ["id" ], "detection_strategy_name" : ds .get ("name" , "" )}
386+ )
387+
373388 for analytic in tqdm (analytics , desc = "parsing analytics" ):
374389 analytic_rows .append (parseBaseStix (analytic ))
375390
391+ # log-source relationship table rows
392+ for logsrc in analytic .get ("x_mitre_log_source_references" , []):
393+ data_comp_id = logsrc .get ("x_mitre_data_component_ref" , "" )
394+ data_comp = src .get (data_comp_id )
395+ data_comp_name = data_comp .get ("name" , "" ) if data_comp else ""
396+
397+ logsource_rows .append (
398+ {
399+ "analytic_id" : analytic ["id" ],
400+ "analytic_name" : analytic ["external_references" ][0 ]["external_id" ],
401+ "data_component_id" : data_comp_id ,
402+ "data_component_name" : data_comp_name ,
403+ "log_source_name" : logsrc .get ("name" , "" ),
404+ "channel" : logsrc .get ("channel" , "" ),
405+ }
406+ )
407+
408+ # detection strategies relationship table rows
409+ for ds_info in analytic_to_ds_map .get (analytic ["id" ], []):
410+ analytic_to_ds_rows .append (
411+ {
412+ "analytic_id" : analytic ["id" ],
413+ "analytic_name" : analytic ["external_references" ][0 ]["external_id" ],
414+ "detection_strategy_id" : ds_info ["detection_strategy_id" ],
415+ "detection_strategy_name" : ds_info ["detection_strategy_name" ],
416+ }
417+ )
418+
419+ dataframes ["analytics" ] = pd .DataFrame (analytic_rows ).sort_values ("name" )
420+ dataframes ["analytic-logsource" ] = pd .DataFrame (logsource_rows )
421+ dataframes ["analytic-detectionstrategy" ] = pd .DataFrame (analytic_to_ds_rows )
422+
376423 citations = get_citations (analytics )
377- dataframes = {
378- "analytics" : pd .DataFrame (analytic_rows ).sort_values ("name" ),
379- }
380424 if not citations .empty :
381425 dataframes ["citations" ] = citations .sort_values ("reference" )
382426
@@ -398,20 +442,36 @@ def detectionstrategiesToDf(src):
398442 dataframes = {}
399443 if detection_strategies :
400444 detection_strategy_rows = []
445+ rel_rows = []
401446 for detection_strategy in tqdm (detection_strategies , desc = "parsing detection strategies" ):
402- detection_strategy_rows .append (parseBaseStix (detection_strategy ))
447+ row = parseBaseStix (detection_strategy )
448+ row ["analytic_refs" ] = "; " .join (detection_strategy .get ("x_mitre_analytic_refs" , []))
449+ detection_strategy_rows .append (row )
450+
451+ # analytics relationship table rows
452+ for analytic_id in detection_strategy .get ("x_mitre_analytic_refs" , []):
453+ analytic_obj = src .get (analytic_id )
454+
455+ rel_rows .append (
456+ {
457+ "detection_strategy_id" : detection_strategy ["id" ],
458+ "detection_strategy_name" : detection_strategy .get ("name" , "" ),
459+ "analytic_id" : analytic_id ,
460+ "analytic_name" : analytic_obj ["external_references" ][0 ]["external_id" ],
461+ }
462+ )
463+
464+ # Build main dataframes
465+ dataframes ["detectionstrategies" ] = pd .DataFrame (detection_strategy_rows ).sort_values ("name" )
466+
467+ dataframes ["detectionstrategies-analytic" ] = pd .DataFrame (rel_rows )
403468
404469 citations = get_citations (detection_strategies )
405- dataframes = {
406- "detectionstrategies" : pd .DataFrame (detection_strategy_rows ).sort_values ("name" ),
407- }
408470 if not citations .empty :
409- if "citations" in dataframes : # append to existing citations from references
410- dataframes ["citations" ] = citations .sort_values ("reference" )
471+ dataframes ["citations" ] = citations .sort_values ("reference" )
411472
412473 else :
413474 logger .warning ("No detection strategies found - nothing to parse" )
414-
415475 return dataframes
416476
417477
0 commit comments