feat(heatmap): expose technique name + real status on every layer
The Coverage Matrix heatmap only ever showed the bare MITRE ID on each cell (name only via hover tooltip), and colored cells from a continuous score -> hex gradient with no discrete status concept — unlike the Techniques page, which showed ID+name inline with a fixed 5-color status palette. Unifying the two pages' visual style requires both pieces of data to exist server-side. - Adds "name" to all 4 layer builders (coverage/threat-actor/detection- rules/campaign) — harmless extra field for Navigator exports, lets the frontend show it inline. - Adds "status" (the real TechniqueStatus value) to the coverage and threat-actor layers specifically — the only two backed by an actual TechniqueStatus concept; detection-rules/campaign scores don't correspond to one and don't get this field.
This commit is contained in:
@@ -353,6 +353,17 @@ def build_coverage_layer(
|
||||
layer["techniques"].append({
|
||||
# Literal argument value
|
||||
"techniqueID": tech.mitre_id,
|
||||
# Technique display name — not part of the official ATT&CK
|
||||
# Navigator schema, but harmless extra data for Navigator
|
||||
# imports and lets Aegis's own heatmap UI show names inline
|
||||
# instead of only ID + hover tooltip.
|
||||
"name": tech.name,
|
||||
# Only the coverage layer has a real TechniqueStatus concept —
|
||||
# exposed so the frontend can color cells by the exact same
|
||||
# discrete status palette the Techniques page uses, instead of
|
||||
# a continuous score-derived hex. The other 3 layer types don't
|
||||
# set this (their score doesn't correspond to a TechniqueStatus).
|
||||
"status": tech.status_global.value,
|
||||
# Literal argument value
|
||||
"tactic": _format_tactic(tech.tactic),
|
||||
# Literal argument value
|
||||
@@ -491,6 +502,11 @@ def build_threat_actor_layer(
|
||||
)
|
||||
layer["techniques"].append({
|
||||
"techniqueID": tech.mitre_id,
|
||||
"name": tech.name,
|
||||
# Every appended row here is an actor-used technique (non-actor
|
||||
# ones are skipped above), so status_global is meaningful here
|
||||
# too — see the coverage layer's "status" field for why.
|
||||
"status": tech.status_global.value,
|
||||
"tactic": _format_tactic(tech.tactic),
|
||||
"color": _score_to_color(score),
|
||||
"score": score,
|
||||
@@ -586,6 +602,7 @@ def build_detection_rules_layer(
|
||||
layer["techniques"].append({
|
||||
# Literal argument value
|
||||
"techniqueID": tech.mitre_id,
|
||||
"name": tech.name,
|
||||
# Literal argument value
|
||||
"tactic": _format_tactic(tech.tactic),
|
||||
# Literal argument value
|
||||
@@ -754,6 +771,7 @@ def build_campaign_layer(
|
||||
layer["techniques"].append({
|
||||
# Literal argument value
|
||||
"techniqueID": mitre_id,
|
||||
"name": tech.name,
|
||||
# Literal argument value
|
||||
"tactic": _format_tactic(tech.tactic),
|
||||
# Literal argument value
|
||||
|
||||
Reference in New Issue
Block a user