Source code for pyrit.identifiers.attack_identifier
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, Type
from pyrit.identifiers.converter_identifier import ConverterIdentifier
from pyrit.identifiers.identifier import Identifier
from pyrit.identifiers.scorer_identifier import ScorerIdentifier
from pyrit.identifiers.target_identifier import TargetIdentifier
[docs]
@dataclass(frozen=True)
class AttackIdentifier(Identifier):
"""
Typed identifier for an attack strategy instance.
Captures the configuration that makes one attack strategy meaningfully
different from another: the objective target, optional scorer, and converter
pipeline. These do not change between calls to ``execute_async``.
"""
objective_target_identifier: Optional[TargetIdentifier] = None
objective_scorer_identifier: Optional[ScorerIdentifier] = None
request_converter_identifiers: Optional[List[ConverterIdentifier]] = None
response_converter_identifiers: Optional[List[ConverterIdentifier]] = None
# Additional attack-specific params for subclass flexibility
attack_specific_params: Optional[Dict[str, Any]] = None
[docs]
@classmethod
def from_dict(cls: Type["AttackIdentifier"], data: dict[str, Any]) -> "AttackIdentifier":
"""
Deserialize an AttackIdentifier from a dictionary.
Handles nested sub-identifiers (target, scorer, converters) by
recursively calling their own ``from_dict`` implementations.
Args:
data: Dictionary containing the serialized identifier fields.
Returns:
AttackIdentifier: The deserialized identifier.
"""
data = dict(data)
if "objective_target_identifier" in data and isinstance(data["objective_target_identifier"], dict):
data["objective_target_identifier"] = TargetIdentifier.from_dict(data["objective_target_identifier"])
if "objective_scorer_identifier" in data and isinstance(data["objective_scorer_identifier"], dict):
data["objective_scorer_identifier"] = ScorerIdentifier.from_dict(data["objective_scorer_identifier"])
if "request_converter_identifiers" in data and data["request_converter_identifiers"] is not None:
data["request_converter_identifiers"] = [
ConverterIdentifier.from_dict(c) if isinstance(c, dict) else c
for c in data["request_converter_identifiers"]
]
if "response_converter_identifiers" in data and data["response_converter_identifiers"] is not None:
data["response_converter_identifiers"] = [
ConverterIdentifier.from_dict(c) if isinstance(c, dict) else c
for c in data["response_converter_identifiers"]
]
return super().from_dict(data)