Skip to content

Commit a33f99f

Browse files
[BREAKING] FEAT add TAP to content harms scenario (microsoft#1378)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ceb2768 commit a33f99f

18 files changed

Lines changed: 574 additions & 350 deletions

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mypy:
1818

1919
docs-build:
2020
uv run jb build -W -v ./doc
21+
cp -r assets doc/_build/assets
2122
uv run ./build_scripts/generate_rss.py
2223

2324
# Because of import time, "auto" seemed to actually go slower than just using 4 processes

doc/code/scenarios/0_scenarios.ipynb

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@
220220
"Available Scenarios:\n",
221221
"================================================================================\n",
222222
"\u001b[1m\u001b[36m\n",
223-
" airt.content_harms\u001b[0m\n",
223+
" content_harms\u001b[0m\n",
224224
" Class: ContentHarms\n",
225225
" Description:\n",
226226
" Content Harms Scenario implementation for PyRIT. This scenario contains\n",
@@ -235,7 +235,7 @@
235235
" airt_hate, airt_fairness, airt_violence, airt_sexual, airt_harassment,\n",
236236
" airt_misinformation, airt_leakage\n",
237237
"\u001b[1m\u001b[36m\n",
238-
" airt.cyber\u001b[0m\n",
238+
" cyber\u001b[0m\n",
239239
" Class: Cyber\n",
240240
" Description:\n",
241241
" Cyber scenario implementation for PyRIT. This scenario tests how willing\n",
@@ -250,7 +250,67 @@
250250
" Default Datasets (1, max 4 per dataset):\n",
251251
" airt_malware\n",
252252
"\u001b[1m\u001b[36m\n",
253-
" airt.scam\u001b[0m\n",
253+
" jailbreak\u001b[0m\n",
254+
" Class: Jailbreak\n",
255+
" Description:\n",
256+
" Jailbreak scenario implementation for PyRIT. This scenario tests how\n",
257+
" vulnerable models are to jailbreak attacks by applying various\n",
258+
" single-turn jailbreak templates to a set of test prompts. The responses\n",
259+
" are scored to determine if the jailbreak was successful.\n",
260+
" Aggregate Strategies:\n",
261+
" - all\n",
262+
" Available Strategies (1):\n",
263+
" pyrit\n",
264+
" Default Strategy: all\n",
265+
" Default Datasets (1, max 4 per dataset):\n",
266+
" airt_harms\n",
267+
"\u001b[1m\u001b[36m\n",
268+
" leakage\u001b[0m\n",
269+
" Class: Leakage\n",
270+
" Description:\n",
271+
" Leakage scenario implementation for PyRIT. This scenario tests how\n",
272+
" susceptible models are to leaking training data, PII, intellectual\n",
273+
" property, or other confidential information. The LeakageScenario class\n",
274+
" contains different attack variations designed to extract sensitive\n",
275+
" information from models.\n",
276+
" Aggregate Strategies:\n",
277+
" - all, single_turn, multi_turn, ip, sensitive_data\n",
278+
" Available Strategies (4):\n",
279+
" first_letter, image, role_play, crescendo\n",
280+
" Default Strategy: all\n",
281+
" Default Datasets (1, max 4 per dataset):\n",
282+
" airt_leakage\n",
283+
"\u001b[1m\u001b[36m\n",
284+
" psychosocial\u001b[0m\n",
285+
" Class: Psychosocial\n",
286+
" Description:\n",
287+
" Psychosocial Harms Scenario implementation for PyRIT. This scenario\n",
288+
" contains various psychosocial harm-based checks that evaluate model\n",
289+
" behavior for responses that may harm the well-being or mental health of\n",
290+
" users. Examples include mistreating users in a mental health crisis or\n",
291+
" aiding them in self-harm. All datasets in this scenario share the\n",
292+
" unified 'psychosocial' harm category, but each dataset (e.g.,\n",
293+
" imminent_crisis, dependency) can have unique: - Multiturn attack\n",
294+
" strategies - Scoring rubrics - Seed objectives The scenario tests\n",
295+
" whether models: - Recognize mental health crises and respond\n",
296+
" appropriately - Avoid facilitating self-harm or harmful behaviors -\n",
297+
" Provide crisis resources and encourage professional help Example usage\n",
298+
" with custom configurations: # Define custom configurations per subharm\n",
299+
" category custom_configs = { \"airt_imminent_crisis\": SubharmConfig(\n",
300+
" crescendo_system_prompt_path=\"path/to/custom_escalation.yaml\",\n",
301+
" scoring_rubric_path=\"path/to/custom_rubric.yaml\", ), } scenario =\n",
302+
" Psychosocial(subharm_configs=custom_configs) await\n",
303+
" scenario.initialize_async( objective_target=target_llm,\n",
304+
" scenario_strategies=[PsychosocialStrategy.MULTI_TURN], )\n",
305+
" Aggregate Strategies:\n",
306+
" - all\n",
307+
" Available Strategies (2):\n",
308+
" imminent_crisis, licensed_therapist\n",
309+
" Default Strategy: all\n",
310+
" Default Datasets (1, max 4 per dataset):\n",
311+
" airt_imminent_crisis\n",
312+
"\u001b[1m\u001b[36m\n",
313+
" scam\u001b[0m\n",
254314
" Class: Scam\n",
255315
" Description:\n",
256316
" Scam scenario evaluates an endpoint's ability to generate scam-related\n",
@@ -264,11 +324,19 @@
264324
" Default Datasets (1, max 4 per dataset):\n",
265325
" airt_scams\n",
266326
"\u001b[1m\u001b[36m\n",
267-
" foundry.foundry\u001b[0m\n",
268-
" Class: FoundryScenario\n",
327+
" red_team_agent\u001b[0m\n",
328+
" Class: RedTeamAgent\n",
269329
" Description:\n",
270-
" Deprecated alias for Foundry. This class is deprecated and will be\n",
271-
" removed in version 0.13.0. Use `Foundry` instead.\n",
330+
" RedTeamAgent is a preconfigured scenario that automatically generates\n",
331+
" multiple AtomicAttack instances based on the specified attack\n",
332+
" strategies. It supports both single-turn attacks (with various\n",
333+
" converters) and multi-turn attacks (Crescendo, RedTeaming), making it\n",
334+
" easy to quickly test a target against multiple attack vectors. The\n",
335+
" scenario can expand difficulty levels (EASY, MODERATE, DIFFICULT) into\n",
336+
" their constituent attack strategies, or you can specify individual\n",
337+
" strategies directly. This scenario is designed for use with the Foundry\n",
338+
" AI Red Teaming Agent library, providing a consistent PyRIT contract for\n",
339+
" their integration.\n",
272340
" Aggregate Strategies:\n",
273341
" - all, easy, moderate, difficult\n",
274342
" Available Strategies (25):\n",
@@ -280,7 +348,7 @@
280348
" Default Datasets (1, max 4 per dataset):\n",
281349
" harmbench\n",
282350
"\u001b[1m\u001b[36m\n",
283-
" garak.encoding\u001b[0m\n",
351+
" encoding\u001b[0m\n",
284352
" Class: Encoding\n",
285353
" Description:\n",
286354
" Encoding Scenario implementation for PyRIT. This scenario tests how\n",
@@ -305,7 +373,7 @@
305373
"\n",
306374
"================================================================================\n",
307375
"\n",
308-
"Total scenarios: 5\n"
376+
"Total scenarios: 8\n"
309377
]
310378
},
311379
{

pyrit/scenario/core/atomic_attack.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ def __init__(
110110
self._seed_groups = seed_groups
111111
self._adversarial_chat = adversarial_chat
112112
self._objective_scorer = objective_scorer
113-
self._objective_scorer = objective_scorer
114113
self._memory_labels = memory_labels or {}
115114
self._attack_execute_params = attack_execute_params
116115

pyrit/scenario/core/scenario.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Scenario(ABC):
5353
def __init__(
5454
self,
5555
*,
56-
name: str,
56+
name: str = "",
5757
version: int,
5858
strategy_class: type[ScenarioStrategy],
5959
objective_scorer: Scorer,
@@ -104,7 +104,7 @@ def __init__(
104104
self._objective_scorer = objective_scorer
105105
self._objective_scorer_identifier = objective_scorer.get_identifier()
106106

107-
self._name = name
107+
self._name = name if name else type(self).__name__
108108
self._memory = CentralMemory.get_memory_instance()
109109
self._atomic_attacks: list[AtomicAttack] = []
110110
self._scenario_result_id: Optional[str] = str(scenario_result_id) if scenario_result_id else None

pyrit/scenario/core/scenario_strategy.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
from __future__ import annotations
1515

16-
from enum import Enum
17-
from typing import TYPE_CHECKING, TypeVar
16+
from enum import Enum, EnumMeta
17+
from typing import TYPE_CHECKING, Any, TypeVar
18+
19+
from pyrit.common.deprecation import print_deprecation_message
1820

1921
if TYPE_CHECKING:
2022
from collections.abc import Sequence
@@ -23,7 +25,34 @@
2325
T = TypeVar("T", bound="ScenarioStrategy")
2426

2527

26-
class ScenarioStrategy(Enum):
28+
class _DeprecatedEnumMeta(EnumMeta):
29+
"""
30+
Custom Enum metaclass that supports deprecated member aliases.
31+
32+
Subclasses of ScenarioStrategy can define deprecated member name mappings
33+
by setting ``__deprecated_members__`` on the class after definition.
34+
Each entry maps the old name to a ``(new_name, removed_in)`` tuple::
35+
36+
MyStrategy.__deprecated_members__ = {"OLD_NAME": ("NewName", "0.13.0")}
37+
38+
Accessing ``MyStrategy.OLD_NAME`` will emit a DeprecationWarning and return
39+
the same enum member as ``MyStrategy.NewName``.
40+
"""
41+
42+
def __getattr__(cls, name: str) -> Any:
43+
deprecated = cls.__dict__.get("__deprecated_members__")
44+
if deprecated and name in deprecated:
45+
new_name, removed_in = deprecated[name]
46+
print_deprecation_message(
47+
old_item=f"{cls.__name__}.{name}",
48+
new_item=f"{cls.__name__}.{new_name}",
49+
removed_in=removed_in,
50+
)
51+
return cls[new_name]
52+
raise AttributeError(name)
53+
54+
55+
class ScenarioStrategy(Enum, metaclass=_DeprecatedEnumMeta):
2756
"""
2857
Base class for attack strategies with tag-based categorization and aggregation.
2958

pyrit/scenario/scenarios/airt/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@
99
)
1010
from pyrit.scenario.scenarios.airt.cyber import Cyber, CyberStrategy
1111
from pyrit.scenario.scenarios.airt.jailbreak import Jailbreak, JailbreakStrategy
12-
from pyrit.scenario.scenarios.airt.leakage_scenario import LeakageScenario, LeakageStrategy
13-
from pyrit.scenario.scenarios.airt.psychosocial_scenario import PsychosocialScenario, PsychosocialStrategy
12+
from pyrit.scenario.scenarios.airt.leakage import Leakage, LeakageScenario, LeakageStrategy
13+
from pyrit.scenario.scenarios.airt.psychosocial import Psychosocial, PsychosocialScenario, PsychosocialStrategy
1414
from pyrit.scenario.scenarios.airt.scam import Scam, ScamStrategy
1515

1616
__all__ = [
1717
"ContentHarms",
1818
"ContentHarmsStrategy",
19+
"Psychosocial",
1920
"PsychosocialScenario",
2021
"PsychosocialStrategy",
2122
"Cyber",
2223
"CyberStrategy",
2324
"Jailbreak",
2425
"JailbreakStrategy",
26+
"Leakage",
2527
"LeakageScenario",
2628
"LeakageStrategy",
2729
"Scam",

0 commit comments

Comments
 (0)