|
3 | 3 |
|
4 | 4 | """Adversarial target resolution validates without changing execution scopes.""" |
5 | 5 |
|
6 | | -from typing import Literal |
| 6 | +from typing import Any, Literal |
7 | 7 | from unittest.mock import AsyncMock, MagicMock, patch |
8 | 8 |
|
9 | 9 | import pytest |
|
23 | 23 | from pyrit.scenario.scenarios.adaptive.text_adaptive import TextAdaptive |
24 | 24 | from pyrit.scenario.scenarios.airt.rapid_response import RapidResponse |
25 | 25 | from pyrit.scenario.scenarios.garak.api_key import ApiKey |
| 26 | +from pyrit.scenario.scenarios.garak.exploitation import Exploitation |
| 27 | +from pyrit.scenario.scenarios.garak.package_hallucination import PackageHallucination |
26 | 28 | from pyrit.scenario.scenarios.garak.prompt_inject import PromptInject, PromptInjectDatasetConfiguration |
| 29 | +from pyrit.scenario.scenarios.garak.system_prompt_extraction import SystemPromptExtraction |
| 30 | +from pyrit.scenario.scenarios.garak.web_injection import WebInjection |
27 | 31 | from pyrit.score import TrueFalseScorer |
28 | 32 | from unit.mocks import MockPromptTarget |
29 | 33 |
|
@@ -183,3 +187,45 @@ def test_resolve_adversarial_target_rejects_invalid_selection_without_changing_s |
183 | 187 | with pytest.raises(ValueError, match=message): |
184 | 188 | ScenarioConfigurationResolver.resolve_adversarial_target(target_name=selection) |
185 | 189 | assert get_default_adversarial_target() is outer |
| 190 | + |
| 191 | + |
| 192 | +@pytest.mark.usefixtures("patch_central_database") |
| 193 | +@pytest.mark.parametrize("scenario_class", [SystemPromptExtraction, WebInjection, PackageHallucination]) |
| 194 | +@pytest.mark.parametrize("limit", [3, "all"]) |
| 195 | +def test_total_limit_is_rejected_when_the_scenario_ignores_it( |
| 196 | + *, scenario_class: type[Scenario], limit: DatasetLimit |
| 197 | +) -> None: |
| 198 | + with ( |
| 199 | + patch.object(Scenario, "_get_default_objective_scorer", return_value=MagicMock(spec=TrueFalseScorer)), |
| 200 | + pytest.raises(ValueError, match="doesn't use a dataset size limit"), |
| 201 | + ): |
| 202 | + ScenarioConfigurationResolver.resolve_configuration( |
| 203 | + scenario_name="test", scenario_class=scenario_class, max_dataset_size=limit |
| 204 | + ) |
| 205 | + |
| 206 | + |
| 207 | +@pytest.mark.usefixtures("patch_central_database") |
| 208 | +@pytest.mark.parametrize("scenario_class", [SystemPromptExtraction, WebInjection, PackageHallucination]) |
| 209 | +def test_dataset_names_still_reach_a_scenario_that_ignores_the_total_limit(scenario_class: type[Scenario]) -> None: |
| 210 | + with patch.object(Scenario, "_get_default_objective_scorer", return_value=MagicMock(spec=TrueFalseScorer)): |
| 211 | + names = scenario_class()._default_dataset_config.dataset_names |
| 212 | + resolved = ScenarioConfigurationResolver.resolve_configuration( |
| 213 | + scenario_name="test", scenario_class=scenario_class, dataset_names=names, max_dataset_size="default" |
| 214 | + ) |
| 215 | + assert resolved["dataset_config"].dataset_names == names |
| 216 | + |
| 217 | + |
| 218 | +@pytest.mark.usefixtures("patch_central_database") |
| 219 | +@pytest.mark.parametrize( |
| 220 | + "overrides", |
| 221 | + [ |
| 222 | + {"max_dataset_size": 3}, |
| 223 | + {"dataset_names": ["garak_exploitation_sql_injection"]}, |
| 224 | + {"dataset_filters": {"data_types": ["text"]}}, |
| 225 | + ], |
| 226 | +) |
| 227 | +def test_dataset_overrides_are_rejected_for_a_fixed_dataset_scenario(overrides: dict[str, Any]) -> None: |
| 228 | + with pytest.raises(ValueError, match="uses a fixed dataset"): |
| 229 | + ScenarioConfigurationResolver.resolve_configuration( |
| 230 | + scenario_name="garak.exploitation", scenario_class=Exploitation, **overrides |
| 231 | + ) |
0 commit comments