diff --git a/pyrit/output/scenario_result/html.py b/pyrit/output/scenario_result/html.py index d939f36ab5..2b1ee1b014 100644 --- a/pyrit/output/scenario_result/html.py +++ b/pyrit/output/scenario_result/html.py @@ -104,12 +104,15 @@
{{ m.role }}{% if m.is_simulated %} (simulated){% endif %}
{% for p in m.pieces %} + {% set shown_value = p.original_value + if p.converted_value is undefined or p.converted_value is none + else p.converted_value %} {% if p.data_type == "reasoning" %}
{{ p.reasoning_summary }}
{% elif p.data_type == "text" %} -
{{ p.converted_value or p.original_value }}
+
{{ shown_value }}
{% else %} -
[{{ p.data_type }}] {{ p.converted_value or p.original_value }}
+
[{{ p.data_type }}] {{ shown_value }}
{% endif %} {% if p.response_error and p.response_error != "none" %}
error: {{ p.response_error }}
diff --git a/tests/unit/output/scenario_result/test_html.py b/tests/unit/output/scenario_result/test_html.py index ae4aecaa9a..2ac3342903 100644 --- a/tests/unit/output/scenario_result/test_html.py +++ b/tests/unit/output/scenario_result/test_html.py @@ -5,6 +5,7 @@ import uuid from typing import Any +import pytest from unit.mocks import make_scenario_result from pyrit.models import ( @@ -269,3 +270,48 @@ async def test_html_report_renders_role_aware_accounting(): assert "Target-facing attempts" in html assert "Orchestration attempts" in html + + +async def test_html_report_renders_explicit_empty_converted_text(): + payload = _payload() + payload["conversations"][0]["messages"][0]["pieces"][0] = { + "data_type": "text", + "original_value": "ORIGINAL_WAS_REMOVED", + "converted_value": "", + "response_error": None, + } + + html = await HtmlScenarioReportPrinter().render_async(payload) + + assert "ORIGINAL_WAS_REMOVED" not in html + assert '
' in html + + +async def test_html_report_renders_explicit_empty_converted_media(): + payload = _payload() + payload["conversations"][0]["messages"][0]["pieces"][0] = { + "data_type": "image_path", + "original_value": "media/original.png", + "converted_value": "", + "response_error": None, + } + + html = await HtmlScenarioReportPrinter().render_async(payload) + + assert "media/original.png" not in html + assert '
[image_path]
' in html + + +@pytest.mark.parametrize("piece_extra", [{"converted_value": None}, {}]) +async def test_html_report_falls_back_to_original_when_converted_value_missing(piece_extra: dict[str, Any]): + payload = _payload() + payload["conversations"][0]["messages"][0]["pieces"][0] = { + "data_type": "text", + "original_value": "only-original", + "response_error": None, + **piece_extra, + } + + html = await HtmlScenarioReportPrinter().render_async(payload) + + assert "only-original" in html