MAINT: Migrating AttackResult to Pydantic#1899
Merged
Merged
Conversation
Move AttackResult, AttackOutcome, and StrategyResult into a new pyrit.models.results sub-package, mirroring the pyrit.models.messages reorganization. The old pyrit/models/attack_result.py and pyrit/models/strategy_result.py modules become silent backward-compat shims that re-export from the new location, so existing deep-path imports keep working. Classes remain @DataClass for now; the Pydantic v2 conversion lands in a follow-up once Score (Phase 5) is merged. Also add a .gitignore negation so the new package dir is not caught by the existing runtime 'results/' ignore rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts: # pyrit/models/attack_result.py
Complete the Phase 6 Pydantic conversion: StrategyResult and AttackResult (relocated into pyrit.models.results) are now Pydantic v2 BaseModels with extra='forbid', naive-timestamp coercion, and a deprecated attack_identifier kwarg/property that promotes to atomic_attack_identifier. to_dict/from_dict are retained as deprecated shims preserving the legacy wire shape. The before- validators copy the input dict so model_validate never mutates caller payloads. De-dataclass all StrategyResult/AttackResult subclasses so their Pydantic __init__ works correctly: Crescendo/TAP/Sequential attack results, Workflow/XPIA results, and PromptGenerator/GCG/Fuzzer/Anecdoctor results. Context classes remain dataclasses. field(default_factory=...) becomes pydantic Field(...). Fix tests that relied on the old dataclass accepting type-invalid values, and add pre-existing None-guards in crescendo/tree_of_attacks surfaced by ty once these files entered the changed-file set. Add conversion tests covering silent shims, extra='forbid', timestamp coercion, to_dict/from_dict deprecation, deep- copy independence, and combined validator / no-mutation behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use plain AwareDatetime (matching Score/MessagePiece) instead of a custom _coerce_naive_timestamp model_validator. Naive timestamps from the DB are already normalized to UTC by AttackResultEntry.get_attack_result via _ensure_utc before the constructor runs, so the model can stay strict. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
romanlutz
approved these changes
Jun 3, 2026
Address review feedback on AttackResult and GCGResult: replace the Optional[...] type annotations with the modern union syntax (X | None) mandated by the PyRIT style guide. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The bare results/ pattern matched a directory named results at any depth, which swallowed the new pyrit/models/results/ source package and required a !pyrit/models/results/ negation. Anchor it as /results/ so it only ignores the top-level runtime output dir (memory results_path), and drop the negation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
romanlutz
added a commit
to romanlutz/PyRIT
that referenced
this pull request
Jun 4, 2026
Merge 26 commits from main, including: - MAINT Breaking: Convert ScenarioResult to Pydantic (microsoft#1908) - MAINT: Migrating Seed classes to Pydantic (microsoft#1898) - MAINT: Migrating AttackResult to Pydantic (microsoft#1899) - MAINT: Bump ty-pre-commit v0.0.32 -> 0.0.43 (microsoft#1919) - FEAT: Realtime streaming session support and server-side barge-in attack (microsoft#1766) - FEAT text adaptive scenario (microsoft#1760) - FIX: Integration Test Fixes (microsoft#1907) - DOC: Scoring Docs Refactor (microsoft#1892) - Various dependency bumps Conflicts (15 files) resolved by taking main's version + re-running ruff --fix to re-apply PEP 604 typing modernization on the incoming code (177 violations auto-fixed). All resolved files re-staged. Local verification: - ruff check: All checks passed - ruff format: clean - pytest tests/unit -n 8: 9550 passed, 6 skipped Known issue (pre-existing on main, not caused by this merge): - ty 0.0.43 enabled missing-override-decorator rule, which flags hundreds of pre-existing methods across the codebase. Main's own CI is currently failing on this. Our PR will inherit the same failure since touched files come into pre-commit scope. Fixing this rule globally is a separate, large mechanical change orthogonal to typing modernization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This converts AttackResult to a Pydantic BaseModel. It is phase 6 of the pyrit.models refactor:
https://gist.github.com/rlundeen2/3e8daa8e12a11b4b6e52587b3c9b1dca