Repository navigation
FIX: keep an audit record when an in-flight target call is cancelled - #3796
Open
Aditya Malkar (adimalkar) wants to merge 1 commit into
Open
Aditya Malkar (adimalkar) wants to merge 1 commit into
Aditya Malkar (adimalkar) wants to merge 1 commit into
Conversation
Cancelling an attack after it entered the objective target left nothing in memory: CancelledError is a BaseException, so it skipped both the normalizer's request persistence and the attack's ON_ERROR result. - PromptNormalizer persists the converted request (without a response) when a send is cancelled while the target may have it, then re-raises. A send_context that never reached the target persists nothing, matching the Exception path. - AttackStrategy persists an UNDETERMINED AttackResult carrying the new AttackCancellation marker when it is cancelled after it started sending to the objective target, then re-raises. - Persistence failures are logged and never replace the cancellation. - Scenario resume treats cancelled rows as pending, like ERROR rows, so a resumed scenario re-runs objectives that were cancelled mid-flight. Fixes microsoft#3733
This branch has not been deployed
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.
Description
Fixes #3733.
On
main(f3a88daf), with in-memory SQLite, a target whose_send_prompt_to_target_asyncsignals entry and then blocks runsPromptSendingAttack.execute_async(objective="cancellation audit probe")as a task. I cancel the task once the target is entered.CancelledErrorpropagates, and memory holds 0 message pieces and 0 attack results. With this change the same run keeps[("user", "cancellation audit probe")]and oneAttackResultwith outcomeUNDETERMINED, pointing at that conversation, then still propagatesCancelledError.There were two separate gaps, since
CancelledErroris aBaseException:PromptNormalizer.send_prompt_asyncpersisted the request after the target returned or inexcept Exception, and cancellation skipped both. It now has anexcept asyncio.CancelledErrorbranch:Exceptionbranch: if asend_contextreports the target was never invoked, nothing is persisted.AttackStrategy.execute_with_context_asynconly reachesON_ERROR(which writes the error result) forException. It now handlesCancelledErrortoo:AttackResultand re-raises._ObjectiveTargetConversationLifecyclealready records those invocations; I addedinvoked.UNDETERMINED. It is not marked success, failure or error, and has no error fields.metadata.AttackCancellationinpyrit/executor/attack/core/attack_cancellation.py, modelled onAttackPreparationFailure(to_metadata/from_result).Scenario resume.
_get_completed_objective_hashes_asynccounts every non-ERRORrow as completed, includingUNDETERMINED. So without a change there, a resumed scenario would skip an objective that was cancelled mid-flight. I checked: with the exclusion removed, the updated Crescendo resume test fails with B's attack never run. Rows carryingAttackCancellationnow stay pending, likeERRORrows. As with anERRORrow today, the cancelled attempt stays inScenarioResult.attack_resultsnext to the resumed one, since supersession is per conversation and the resumed attempt uses a new one.Tests and Documentation
New tests:
tests/unit/prompt_normalizer/test_prompt_normalizer.py:send_contextnever reached the target persists nothing.CancelledError.tests/unit/executor/attack/single_turn/test_prompt_sending.py, cancellation at three points plus a failed write:UNDETERMINEDresult with the marker are kept, with no error fields.UNDETERMINEDresult are kept.CancelledError.Existing tests updated, because they asserted that cancellation leaves no trace:
test_crescendo_resilience.py::test_cancellation_runs_teardown_preserves_completed_turns_and_clears_retry_state: 9 pieces (4 turns plus the in-flight request) and one cancelledUNDETERMINEDresult.test_scenario_crescendo_resume.py::test_crescendo_scenario_cancellation_preserves_progress_and_resumes_only_incomplete_objective: the cancelled attempt at B is recorded. Resume still re-runs B, and the partial conversation now ends with the in-flightB prompt 5.test_github_copilot_target.py::test_normalizer_deletes_owned_session_when_creation_is_cancelled_after_allocation_async: cancellation lands inside_send_prompt_to_target_async(session allocation), so the request is persisted. TheExceptionpath does the same in that phase. The session-cleanup assertions are unchanged.The 5 behavioural tests fail on
mainand pass here.tests/unithas the same failures onmainand on this branch (55 failed / 89 errors locally, alllitellm-dependent or otherwise environmental), plus 7 new passing tests.ruffandty check pyrit(lockfile versions) report nothing new.