From 7d3d39639e7586212e9a31f92cdf00b6e1bb21ce Mon Sep 17 00:00:00 2001 From: Knacky Date: Wed, 10 Jun 2026 20:24:22 +0200 Subject: [PATCH] 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 --- backend/app/api/c2.py | 1 + backend/tests/test_c2_import.py | 19 +++++++++++++++++++ backend/tests/test_c2_tasks_list.py | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/backend/app/api/c2.py b/backend/app/api/c2.py index 1ce764a..54eb19e 100644 --- a/backend/app/api/c2.py +++ b/backend/app/api/c2.py @@ -360,6 +360,7 @@ def list_simulation_tasks(sid: int): "status": t.status, "completed": t.completed, "output": t.output, + "source": t.source.value, "mapping_applied": t.mapping_applied, "created_at": t.created_at.isoformat() if t.created_at else None, "completed_at": t.completed_at.isoformat() if t.completed_at else None, diff --git a/backend/tests/test_c2_import.py b/backend/tests/test_c2_import.py index 9f289c8..e385530 100644 --- a/backend/tests/test_c2_import.py +++ b/backend/tests/test_c2_import.py @@ -282,6 +282,25 @@ class TestImportHappyPath: resp = _import(client, redteam_token, sim["id"], [100]) 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( self, app: Flask, monkeypatch, client: FlaskClient, admin_token: str ) -> None: diff --git a/backend/tests/test_c2_tasks_list.py b/backend/tests/test_c2_tasks_list.py index be68c8e..e231545 100644 --- a/backend/tests/test_c2_tasks_list.py +++ b/backend/tests/test_c2_tasks_list.py @@ -117,8 +117,9 @@ class TestListTasksHappyPath: task = resp.get_json()["tasks"][0] for field in ("id", "mythic_task_display_id", "callback_display_id", "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 task["source"] == "mimic" def test_first_poll_returns_submitted( self, client: FlaskClient, admin_token: str