Skip to content

Commit 86281ef

Browse files
committed
fix: handle missing tactic definitions in techniquesToDf and add unit tests
1 parent 7777619 commit 86281ef

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

mitreattack/attackToExcel/stixToDf.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def techniquesToDf(src, domain):
118118
for tactic in tactics:
119119
x_mitre_shortname = tactic["x_mitre_shortname"]
120120
tactic_names[x_mitre_shortname] = tactic["name"]
121+
missing_tactic_shortnames = set()
121122

122123
all_sub_techniques = src.query(
123124
[
@@ -150,7 +151,14 @@ def techniquesToDf(src, domain):
150151

151152
technique_tactic_names = []
152153
for shortname in tactic_shortnames:
153-
tactic_display_name = tactic_names[shortname]
154+
tactic_display_name = tactic_names.get(shortname)
155+
if not tactic_display_name:
156+
tactic_display_name = shortname.replace("-", " ").title()
157+
if shortname not in missing_tactic_shortnames:
158+
logger.warning(
159+
f"Could not find x-mitre-tactic object for shortname '{shortname}', using '{tactic_display_name}'"
160+
)
161+
missing_tactic_shortnames.add(shortname)
154162
technique_tactic_names.append(tactic_display_name)
155163
row["tactics"] = ", ".join(sorted(technique_tactic_names))
156164

tests/test_stix_to_df.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""Unit tests for STIX-to-dataframe conversion helpers."""
2+
3+
import stix2
4+
5+
from mitreattack.attackToExcel import stixToDf
6+
7+
8+
def test_techniques_to_df_handles_missing_tactic_definition(monkeypatch):
9+
"""TechniquesToDf should not fail when tactic shortnames are missing from x-mitre-tactic objects."""
10+
monkeypatch.setattr(stixToDf, "relationshipsToDf", lambda src, relatedType: {})
11+
monkeypatch.setattr(stixToDf, "_get_relationship_citations", lambda df, codex: [""] * len(df))
12+
13+
mem_store = stix2.MemoryStore(
14+
stix_data=[
15+
{
16+
"type": "attack-pattern",
17+
"spec_version": "2.0",
18+
"id": "attack-pattern--11111111-1111-4111-8111-111111111111",
19+
"created": "2020-01-01T00:00:00.000Z",
20+
"modified": "2020-01-01T00:00:00.000Z",
21+
"name": "Test Technique",
22+
"description": "Test",
23+
"kill_chain_phases": [
24+
{
25+
"kill_chain_name": "mitre-attack",
26+
"phase_name": "defense-evasion",
27+
}
28+
],
29+
"external_references": [
30+
{
31+
"source_name": "mitre-attack",
32+
"external_id": "T0001",
33+
"url": "https://example.com",
34+
}
35+
],
36+
"x_mitre_domains": ["enterprise-attack"],
37+
}
38+
]
39+
)
40+
41+
dataframes = stixToDf.techniquesToDf(mem_store, "enterprise-attack")
42+
techniques_df = dataframes["techniques"]
43+
44+
assert len(techniques_df) == 1
45+
assert techniques_df.iloc[0]["tactics"] == "Defense Evasion"

0 commit comments

Comments
 (0)