Skip to content

Commit 0989c79

Browse files
FIX propagate params in attack executor functions (microsoft#1187)
1 parent 4fdbbd4 commit 0989c79

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

pyrit/executor/attack/core/attack_executor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ async def execute_single_turn_attacks_async(
195195
prepended_conversations: Optional[List[List[Message]]] = None,
196196
memory_labels: Optional[Dict[str, str]] = None,
197197
return_partial_on_failure: bool = False,
198+
**attack_params,
198199
) -> AttackExecutorResult[AttackStrategyResultT]:
199200
"""
200201
Execute a batch of single-turn attacks with multiple objectives.
@@ -217,6 +218,7 @@ async def execute_single_turn_attacks_async(
217218
return_partial_on_failure (bool): If True, returns AttackExecutorResult with completed results
218219
even when some objectives don't complete execution. If False, raises the first exception encountered.
219220
Defaults to False (raise on failure).
221+
**attack_params: Additional parameters specific to the attack strategy.
220222
221223
Returns:
222224
AttackExecutorResult[AttackStrategyResultT]: Result container with completed results and
@@ -262,6 +264,7 @@ async def execute_with_semaphore(
262264
prepended_conversation=prepended_conversation,
263265
seed_group=seed_group,
264266
memory_labels=memory_labels or {},
267+
**attack_params,
265268
)
266269

267270
# Create tasks for each objective with its corresponding parameters
@@ -293,6 +296,7 @@ async def execute_multi_turn_attacks_async(
293296
prepended_conversations: Optional[List[List[Message]]] = None,
294297
memory_labels: Optional[Dict[str, str]] = None,
295298
return_partial_on_failure: bool = False,
299+
**attack_params,
296300
) -> AttackExecutorResult[AttackStrategyResultT]:
297301
"""
298302
Execute a batch of multi-turn attacks with multiple objectives.
@@ -315,6 +319,7 @@ async def execute_multi_turn_attacks_async(
315319
return_partial_on_failure (bool): If True, returns AttackExecutorResult with completed results
316320
even when some objectives don't complete execution. If False, raises the first exception encountered.
317321
Defaults to False (raise on failure).
322+
**attack_params: Additional parameters specific to the attack strategy.
318323
319324
Returns:
320325
AttackExecutorResult[AttackStrategyResultT]: Result container with completed results and
@@ -358,6 +363,7 @@ async def execute_with_semaphore(
358363
prepended_conversation=prepended_conversation,
359364
custom_prompt=custom_prompt,
360365
memory_labels=memory_labels or {},
366+
**attack_params,
361367
)
362368

363369
# Create tasks for each objective with its corresponding parameters

pyrit/scenarios/atomic_attack.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,11 @@ def _validate_parameters(
213213
)
214214

215215
async def run_async(
216-
self, *, max_concurrency: int = 1, return_partial_on_failure: bool = True
216+
self,
217+
*,
218+
max_concurrency: int = 1,
219+
return_partial_on_failure: bool = True,
220+
**attack_params,
217221
) -> AttackExecutorResult[AttackResult]:
218222
"""
219223
Execute the atomic attack against all objectives in the dataset.
@@ -236,6 +240,7 @@ async def run_async(
236240
return_partial_on_failure (bool): If True, returns partial results even when
237241
some objectives don't complete execution. If False, raises an exception on
238242
any execution failure. Defaults to True.
243+
**attack_params: Additional parameters to pass to the attack strategy.
239244
240245
Returns:
241246
AttackExecutorResult[AttackResult]: Result containing completed attack results and
@@ -268,6 +273,7 @@ async def run_async(
268273
prepended_conversations=prepended_conversations,
269274
memory_labels=merged_memory_labels,
270275
return_partial_on_failure=return_partial_on_failure,
276+
**self._attack_execute_params,
271277
)
272278
elif self._context_type == "multi_turn":
273279
results = await executor.execute_multi_turn_attacks_async(
@@ -277,6 +283,7 @@ async def run_async(
277283
prepended_conversations=prepended_conversations,
278284
memory_labels=merged_memory_labels,
279285
return_partial_on_failure=return_partial_on_failure,
286+
**self._attack_execute_params,
280287
)
281288
else:
282289
# Fall back to generic execute_multi_objective_attack_async

tests/unit/executor/attack/core/test_attack_executor.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,28 @@ async def test_execute_single_turn_validates_prepended_conversations_length(self
835835
prepended_conversations=prepended_conversations,
836836
)
837837

838+
@pytest.mark.asyncio
839+
async def test_execute_single_turn_with_attack_execute_params(self, mock_single_turn_attack_strategy):
840+
executor = AttackExecutor(max_concurrency=1)
841+
objectives = ["Obj1", "Obj2", "Obj3"]
842+
843+
mock_single_turn_attack_strategy.execute_async.return_value = MagicMock()
844+
845+
await executor.execute_single_turn_attacks_async(
846+
attack=mock_single_turn_attack_strategy,
847+
objectives=objectives,
848+
custom_param="test_value",
849+
batch_size=10,
850+
another_param=42,
851+
)
852+
853+
# Verify all calls included the custom params
854+
assert mock_single_turn_attack_strategy.execute_async.call_count == 3
855+
for call in mock_single_turn_attack_strategy.execute_async.call_args_list:
856+
assert call.kwargs["custom_param"] == "test_value"
857+
assert call.kwargs["batch_size"] == 10
858+
assert call.kwargs["another_param"] == 42
859+
838860

839861
@pytest.mark.usefixtures("patch_central_database")
840862
class TestExecuteMultiTurnAttacksAsync:
@@ -1028,6 +1050,28 @@ async def track_execution(objective, **kwargs):
10281050

10291051
assert max_concurrent <= 2
10301052

1053+
@pytest.mark.asyncio
1054+
async def test_execute_multi_turn_with_attack_execute_params(self, mock_multi_turn_attack_strategy):
1055+
executor = AttackExecutor(max_concurrency=1)
1056+
objectives = ["Obj1", "Obj2", "Obj3"]
1057+
1058+
mock_multi_turn_attack_strategy.execute_async.return_value = MagicMock()
1059+
1060+
await executor.execute_multi_turn_attacks_async(
1061+
attack=mock_multi_turn_attack_strategy,
1062+
objectives=objectives,
1063+
custom_param="test_value",
1064+
max_turns=5,
1065+
temperature=0.7,
1066+
)
1067+
1068+
# Verify all calls included the custom params
1069+
assert mock_multi_turn_attack_strategy.execute_async.call_count == 3
1070+
for call in mock_multi_turn_attack_strategy.execute_async.call_args_list:
1071+
assert call.kwargs["custom_param"] == "test_value"
1072+
assert call.kwargs["max_turns"] == 5
1073+
assert call.kwargs["temperature"] == 0.7
1074+
10311075

10321076
@pytest.mark.usefixtures("patch_central_database")
10331077
class TestValidateAttackBatchParameters:

0 commit comments

Comments
 (0)