fix(evaluations): results API returns list of vendors, not dict

The /api/results/ endpoint returns a LIST: [{name: crowdstrike, adversaries: [...]}]
Previous code called data.get() on the list → AttributeError crash on every import.

Fix: detect list vs dict response, extract the crowdstrike vendor entry first,
then get its adversaries list. Keeps legacy dict fallback just in case.
This commit is contained in:
kitos
2026-06-05 16:42:27 +02:00
parent 51d86e5436
commit c0cecab797
@@ -240,8 +240,24 @@ def fetch_results_for_adversary(adversary_name: str) -> list[dict[str, Any]]:
logger.error("Failed to fetch ATT&CK Evaluations results: %s", exc) logger.error("Failed to fetch ATT&CK Evaluations results: %s", exc)
raise raise
# Find the adversary in the response # The results endpoint returns a LIST of vendor objects:
# [{"name": "crowdstrike", "adversaries": [{"Adversary_Name": "apt3", ...}, ...]}, ...]
# (not a dict — hence the explicit vendor lookup below)
if isinstance(data, list):
vendor_entry = next(
(v for v in data if isinstance(v, dict) and v.get("name", "").lower() == _VENDOR),
None,
)
if not vendor_entry:
raise ValueError(
f"Vendor '{_VENDOR}' not found in results response. "
f"Available vendors: {[v.get('name') for v in data if isinstance(v, dict)]}"
)
adversaries = vendor_entry.get("adversaries", [])
else:
# Fallback for legacy dict-shaped response (just in case API changes again)
adversaries = data.get("adversaries", []) adversaries = data.get("adversaries", [])
target = next( target = next(
(a for a in adversaries if a.get("Adversary_Name", "").lower() == adversary_name.lower()), (a for a in adversaries if a.get("Adversary_Name", "").lower() == adversary_name.lower()),
None, None,