@@ -61,8 +61,11 @@ class DomainStatistics:
6161 software : int
6262 campaigns : int
6363 mitigations : int
64+ assets : int
6465 datasources : int
65- assets : int = 0
66+ detectionstrategies : int
67+ analytics : int
68+ datacomponents : int
6669
6770 def format_output (self ) -> str :
6871 """
@@ -79,23 +82,26 @@ def format_output(self) -> str:
7982 (self .techniques , "Techniques" ),
8083 (self .subtechniques , "Sub-Techniques" ),
8184 (self .groups , "Groups" ),
82- (self .software , "Pieces of Software" ),
85+ (self .software , "Software" ),
8386 (self .campaigns , "Campaigns" ),
8487 (self .mitigations , "Mitigations" ),
8588 (self .assets , "Assets" ),
8689 (self .datasources , "Data Sources" ),
90+ (self .detectionstrategies , "Detection Strategies" ),
91+ (self .analytics , "Analytics" ),
92+ (self .datacomponents , "Data Components" ),
8793 ]
8894
8995 # Build parts list, only including items with count > 0
9096 parts = [f"{ count } { label } " for count , label in stats if count > 0 ]
9197
9298 # Join all parts with proper formatting
9399 if len (parts ) == 0 :
94- return f"- { self .name } : No objects"
100+ return f"* { self .name } : No objects"
95101 elif len (parts ) == 1 :
96- return f"- { self .name } : { parts [0 ]} "
102+ return f"* { self .name } : { parts [0 ]} "
97103 else :
98- return f"- { self .name } : { ', ' .join (parts [:- 1 ])} , and { parts [- 1 ]} "
104+ return f"* { self .name } : { ', ' .join (parts [:- 1 ])} , and { parts [- 1 ]} "
99105
100106
101107# TODO: Implement a custom decoder as well. Possible solution at this link
@@ -1079,23 +1085,11 @@ def _collect_domain_statistics(self, datastore: MemoryStore, domain_name: str) -
10791085 software = data .get_software (remove_revoked_deprecated = True )
10801086 campaigns = data .get_campaigns (remove_revoked_deprecated = True )
10811087 mitigations = data .get_mitigations (remove_revoked_deprecated = True )
1082-
1083- # Try to get datasources - may fail on test data with STIX version mismatches
1084- datasources = []
1085- try :
1086- datasources = data .get_datasources (remove_revoked_deprecated = True )
1087- except Exception :
1088- # Silently skip datasources if there are STIX version issues
1089- pass
1090-
1091- # ICS domain has assets
1092- assets = 0
1093- if domain_name == "ICS" :
1094- try :
1095- assets = len (data .get_assets (remove_revoked_deprecated = True ))
1096- except Exception :
1097- # Silently skip assets if there are STIX version issues
1098- pass
1088+ assets = data .get_assets (remove_revoked_deprecated = True )
1089+ datasources = data .get_datasources (remove_revoked_deprecated = True )
1090+ detectionstrategies = data .get_detectionstrategies (remove_revoked_deprecated = True )
1091+ analytics = data .get_analytics (remove_revoked_deprecated = True )
1092+ datacomponents = data .get_datacomponents (remove_revoked_deprecated = True )
10991093
11001094 return DomainStatistics (
11011095 name = domain_name ,
@@ -1106,8 +1100,11 @@ def _collect_domain_statistics(self, datastore: MemoryStore, domain_name: str) -
11061100 software = len (software ),
11071101 campaigns = len (campaigns ),
11081102 mitigations = len (mitigations ),
1103+ assets = len (assets ),
11091104 datasources = len (datasources ),
1110- assets = assets ,
1105+ detectionstrategies = len (detectionstrategies ),
1106+ analytics = len (analytics ),
1107+ datacomponents = len (datacomponents ),
11111108 )
11121109
11131110 def _collect_unique_object_counts (self , datastore_version : str ) -> dict [str , int ]:
@@ -1176,10 +1173,9 @@ def get_statistics_section(self, datastore_version: str = "new") -> str:
11761173 domain_stats .append (stats )
11771174
11781175 # Build the statistics section
1179- version_label = "New" if datastore_version == "new" else "Old"
1180- output = f"## { version_label } ATT&CK Version Statistics\n \n "
1176+ output = "## Statistics\n \n "
11811177 output += (
1182- f"This version of ATT&CK contains { unique_counts ['software' ]} Pieces of Software, "
1178+ f"This version of ATT&CK contains { unique_counts ['software' ]} Software, "
11831179 f"{ unique_counts ['groups' ]} Groups, and { unique_counts ['campaigns' ]} Campaigns.\n \n "
11841180 )
11851181 output += "Broken out by domain:\n \n "
@@ -1203,7 +1199,7 @@ def get_markdown_section_data(self, groupings, section: str, domain: str) -> str
12031199 placard_string = self .placard (stix_object = child , section = section , domain = domain )
12041200
12051201 if grouping ["parentInSection" ]:
1206- sectionString += f" * { placard_string } \n "
1202+ sectionString += f" * { placard_string } \n "
12071203 else :
12081204 sectionString += f"* { grouping ['parent' ]['name' ]} : { placard_string } \n "
12091205
@@ -1240,15 +1236,15 @@ def get_markdown_string(self) -> str:
12401236 logger .info ("Generating markdown output" )
12411237 content = ""
12421238
1243- if self .show_key :
1244- key_content = self .get_md_key ()
1245- content = f"{ key_content } \n \n "
1246-
12471239 # Add statistics section for the new version
12481240 logger .info ("Generating statistics section" )
12491241 stats_section = self .get_statistics_section (datastore_version = "new" )
12501242 content += stats_section
12511243
1244+ if self .show_key :
1245+ key_content = self .get_md_key ()
1246+ content += f"{ key_content } \n "
1247+
12521248 for object_type in self .types :
12531249 domains = ""
12541250
0 commit comments