fix(backend): expose c2_task.source in GET /c2/tasks response

Serialize source as t.source.value (string) in list_simulation_tasks.
Updated test_c2_tasks_list shape assertion to include 'source' and
assert value is 'mimic' for execute-created tasks. Added test in
test_c2_import to assert source='import' in GET /c2/tasks after import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-06-10 20:24:22 +02:00
parent 184a2a16c9
commit 7d3d39639e
3 changed files with 22 additions and 1 deletions

View File

@@ -360,6 +360,7 @@ def list_simulation_tasks(sid: int):
"status": t.status, "status": t.status,
"completed": t.completed, "completed": t.completed,
"output": t.output, "output": t.output,
"source": t.source.value,
"mapping_applied": t.mapping_applied, "mapping_applied": t.mapping_applied,
"created_at": t.created_at.isoformat() if t.created_at else None, "created_at": t.created_at.isoformat() if t.created_at else None,
"completed_at": t.completed_at.isoformat() if t.completed_at else None, "completed_at": t.completed_at.isoformat() if t.completed_at else None,

View File

@@ -282,6 +282,25 @@ class TestImportHappyPath:
resp = _import(client, redteam_token, sim["id"], [100]) resp = _import(client, redteam_token, sim["id"], [100])
assert resp.status_code == 200 assert resp.status_code == 200
def test_source_field_is_import_in_tasks_listing(
self, monkeypatch, client: FlaskClient, admin_token: str
) -> None:
"""Imported tasks appear with source='import' in GET /c2/tasks response."""
_make_completed_get_task(monkeypatch)
eng = _make_engagement(client, admin_token)
_put_config(client, admin_token, eng["id"])
sim = _make_sim(client, admin_token, eng["id"])
_import(client, admin_token, sim["id"], [100])
resp = client.get(
f"/api/simulations/{sim['id']}/c2/tasks",
headers=_h(admin_token),
)
assert resp.status_code == 200
task = resp.get_json()["tasks"][0]
assert task["source"] == "import"
def test_no_transition_when_all_skipped( def test_no_transition_when_all_skipped(
self, app: Flask, monkeypatch, client: FlaskClient, admin_token: str self, app: Flask, monkeypatch, client: FlaskClient, admin_token: str
) -> None: ) -> None:

View File

@@ -117,8 +117,9 @@ class TestListTasksHappyPath:
task = resp.get_json()["tasks"][0] task = resp.get_json()["tasks"][0]
for field in ("id", "mythic_task_display_id", "callback_display_id", for field in ("id", "mythic_task_display_id", "callback_display_id",
"command", "params", "status", "completed", "output", "command", "params", "status", "completed", "output",
"mapping_applied", "created_at", "completed_at"): "source", "mapping_applied", "created_at", "completed_at"):
assert field in task, f"missing field: {field}" assert field in task, f"missing field: {field}"
assert task["source"] == "mimic"
def test_first_poll_returns_submitted( def test_first_poll_returns_submitted(
self, client: FlaskClient, admin_token: str self, client: FlaskClient, admin_token: str