refactor(export): switch render output to fixed 7-column schema (Scénario, Test, ...)

All three renderers (MD, CSV, PDF) now emit a uniform 7-column table with
French headers matching the RT↔SOC handoff contract locked in SPEC.md fdab324.

Helpers added:
- _format_execution(sim): canonical 3-part concat (executed_at / commands / execution_result)
- _MD_HEADERS / _HTML_HEADERS / _CSV_HEADERS unified to the same 7 FR strings

Helpers removed (no longer called):
- _tactic_names() — MITRE tactics dropped from export
- _enrich_sim_techniques() — MITRE techniques dropped from export

Fields dropped from export: status, techniques, tactic_ids, prerequisites, id,
created_at, updated_at (intentional — focused RT↔SOC handoff, see SPEC §Export).

_csv_safe() still applied to all 7 user-controlled cells including Exécution concat.

Tests updated: 255 passed, ruff clean, mypy clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-06-08 19:15:49 +02:00
parent fdab324217
commit 7335b9f2c6
3 changed files with 218 additions and 256 deletions

View File

@@ -60,8 +60,11 @@ def test_export_markdown_admin_returns_md_with_engagement_header_and_all_simulat
assert "text/markdown" in resp.content_type
body = resp.data.decode()
assert "Op Alpha" in body
# Both simulation names appear as cells in the 7-column table
assert "Lateral Movement" in body
assert "Persistence Check" in body
# Table uses French column headers
assert "Scénario" in body
def test_export_markdown_redteam_ok(
@@ -122,10 +125,13 @@ def test_export_csv_columns_match_contract(
rows = list(csv_mod.reader(io.StringIO(resp.data.decode())))
expected_headers = [
"id", "name", "status", "techniques", "tactics", "description",
"commands", "prerequisites", "executed_at", "execution_result",
"log_source", "logs", "soc_comment", "incident_number",
"created_at", "updated_at",
"Scénario",
"Test",
"Source de log",
"Commentaires SOC",
"Exécution",
"Logs remontés au SIEM",
"Cyber incident",
]
assert rows[0] == expected_headers
@@ -156,7 +162,7 @@ def test_export_csv_escapes_special_characters(
rows = list(csv_mod.reader(io.StringIO(body)))
assert len(rows) == 2 # header + 1 sim
name_col = rows[1][1]
name_col = rows[1][0] # col 0 = Scénario
assert "quoted" in name_col