[WIP] Replace duck-typing with typed AttackResult model - #522
Conversation
|
@claude[agent] check the CI Checks / Commit messages and the reviews of co-pilot in this pull request |
Checked both. Copilot/code-quality reviews (10 threads) — all were the same finding: "Signature mismatch in overriding method. This method requires 2 positional arguments, whereas overridden CI / Commit Messages — this job runs Two ways to get this green: force-push the rewritten history yourself, or merge with Squash and merge so the compliant PR title becomes the commit message. |
|
Copilot resolve the merge conflicts in this pull request. Also fix the CI Checks |
Merge conflicts resolved in 908dfd1 ( Conflict — Extra fix — the merge surfaced a broken hunk that landed on Verified: CI / Commit Messages — still red, and I can't fix it from here. |
|
@claude[agent] fix the tests |
I dug into the failing jobs and there's no test to fix — nothing in this PR is broken. Unit tests are green on all 9 matrix combos (3.10–3.13 × ubuntu/macos/windows), as are Offline Integration, E2E, Linting and Formatting, and Build Documentation. The two red test jobs are Integration Tests (Ollama, fast) and (Ollama, slow), and every failure is an HTTP error from the hosted backend, not an assertion:
All of these come out of Verified locally on 908dfd1: Commit Messages is still red for the reason in my earlier comment: Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
…ith typed AttackResult model Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/deaf3dc3-bcfa-454b-9c60-a71e88c03c25 Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
…xtraction logic, restore final_results normalization Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/deaf3dc3-bcfa-454b-9c60-a71e88c03c25 Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
…AttackResult.to_row() Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/deaf3dc3-bcfa-454b-9c60-a71e88c03c25 Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Aligns every technique's run() with the abstract BaseAttack.run(self, **kwargs) signature, resolving the code-quality "signature mismatch in overriding method" findings. Agent-Logs-Url: https://github.com/AISecurityLab/hackagent/sessions/65e0b415-3263-4a6b-872b-63d711c474f1 Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Co-authored-by: franconicola <51865029+franconicola@users.noreply.github.com>
Keep main's record_run_audit_failure handling in the evaluation pipeline while falling back to the typed normalized_results rows. Move the misplaced _record_failure call in Tracker._add_trace into the trace-creation except block where its 'e' is bound.
908dfd1 to
7b1d455
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR migrates the attack-technique result contract away from orchestrator-level duck-typing (_normalize_attack_results) toward a shared, typed AttackResult model, with corresponding technique updates and unit tests to enforce the new return type.
Changes:
- Introduces
hackagent.attacks.types.AttackResult(+ helpers) and updates techniques to returnlist[AttackResult]. - Removes
_normalize_attack_results()from the orchestrator and updates orchestration/evaluation boundaries to convert typed results back to legacy dict rows when needed. - Updates/extends unit tests across techniques to assert typed return values and validate round-trip conversions.
Reviewed changes
Copilot reviewed 36 out of 39 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/attacks/test_error_propagation.py | Updates normalization tests to exercise rows_to_attack_results / attack_results_to_rows and adds round-trip coverage. |
| tests/unit/attacks/tap/test_attack.py | Asserts TAP run() returns AttackResult. |
| tests/unit/attacks/static_template/test_attack.py | Updates expectations for static_template run() to return typed results and metadata. |
| tests/unit/attacks/rag/test_attack.py | Updates assertions to read results from AttackResult.metadata / AttackResult.evaluations. |
| tests/unit/attacks/pap/test_attack.py | Asserts PAP run() returns AttackResult. |
| tests/unit/attacks/pair/test_attack.py | Asserts PAIR run() returns AttackResult. |
| tests/unit/attacks/mml/test_attack.py | Updates assertions to typed AttackResult and metadata semantics. |
| tests/unit/attacks/indirect_prompt_injection/test_attack_return_type.py | New test asserting indirect-prompt-injection returns list[AttackResult] and validates error cases. |
| tests/unit/attacks/indirect_prompt_injection/init.py | Package init for new indirect-prompt-injection unit tests. |
| tests/unit/attacks/h4rm3l/test_attack.py | Asserts h4rm3l run() returns AttackResult. |
| tests/unit/attacks/flipattack/test_attack.py | Asserts FlipAttack run() returns AttackResult. |
| tests/unit/attacks/fc/test_attack.py | Adds tests asserting FC/tFC run() returns AttackResult. |
| tests/unit/attacks/cipherchat/test_attack.py | Asserts CipherChat run() returns AttackResult. |
| tests/unit/attacks/bon/test_attack.py | Asserts BoN run() returns AttackResult. |
| tests/unit/attacks/baseline/test_attack_return_type.py | New test asserting Baseline returns list[AttackResult]. |
| tests/unit/attacks/baseline/init.py | Package init for new baseline unit tests. |
| tests/unit/attacks/autodan_turbo/test_attack.py | Asserts AutoDAN-Turbo run() returns AttackResult. |
| tests/unit/attacks/advprefix/test_attack_return_type.py | New test asserting AdvPrefix returns list[AttackResult]. |
| tests/unit/attacks/advprefix/init.py | Package init for new advprefix unit tests. |
| hackagent/router/tracking/tracker.py | Adjusts trace failure recording to occur only on actual trace creation failure. |
| hackagent/attacks/types.py | Adds typed AttackResult/Evaluation models plus conversion helpers for legacy row shapes. |
| hackagent/attacks/techniques/tap/attack.py | Updates TAP run() signature/return type and converts pipeline output to typed results. |
| hackagent/attacks/techniques/static_template/attack.py | Updates static_template run() to return typed results instead of {evaluated, summary}. |
| hackagent/attacks/techniques/rag/attack.py | Updates RAG run() to return typed results. |
| hackagent/attacks/techniques/pap/attack.py | Updates PAP run() to return typed results. |
| hackagent/attacks/techniques/pair/attack.py | Updates PAIR run() to return typed results. |
| hackagent/attacks/techniques/mml/attack.py | Updates MML run() to return typed results. |
| hackagent/attacks/techniques/indirect_prompt_injection/attack.py | Updates indirect-prompt-injection run() to return typed results. |
| hackagent/attacks/techniques/h4rm3l/attack.py | Updates h4rm3l run() to return typed results. |
| hackagent/attacks/techniques/flipattack/attack.py | Updates FlipAttack run() to return typed results. |
| hackagent/attacks/techniques/fc/attack.py | Updates FC/tFC run() to return typed results. |
| hackagent/attacks/techniques/cipherchat/attack.py | Updates CipherChat run() to return typed results. |
| hackagent/attacks/techniques/bon/attack.py | Updates BoN run() to return typed results. |
| hackagent/attacks/techniques/baseline/attack.py | Updates Baseline run() to return typed results. |
| hackagent/attacks/techniques/base.py | Updates abstract technique base run() return type to List[AttackResult]. |
| hackagent/attacks/techniques/autodan_turbo/attack.py | Updates AutoDAN-Turbo run() to return typed results. |
| hackagent/attacks/techniques/advprefix/attack.py | Updates AdvPrefix run() to return typed results. |
| hackagent/attacks/orchestrator.py | Removes _normalize_attack_results, adds typed conversion boundary, and updates aggregation logic. |
| hackagent/attacks/base.py | Updates the other BaseAttack interface to return List[AttackResult]. |
Comments suppressed due to low confidence (3)
hackagent/attacks/orchestrator.py:1568
- To keep
_execute_local_attack()'sList[AttackResult]return type truthful, the batched sequential path should normalizeattack_impl.run()output toAttackResult(not just flatten legacy dict wrappers).
batch_results = flatten_run_result(
attack_impl.run(**batch_params)
)
hackagent/attacks/orchestrator.py:1602
- Same as the sequential batching path: the per-goal worker path returns
flatten_run_result(...)but the function signature and downstream code expectAttackResultinstances. Normalize per-goal outputs withrows_to_attack_results()so types are consistent and callers don't receive heterogeneous row shapes.
goal_params = {**attack_params, "goals": [goal]}
goal_results = flatten_run_result(
local_impl.run(**goal_params)
)
hackagent/attacks/orchestrator.py:1663
- The non-batched execution path also returns
flatten_run_result(...), which can yield dict rows and violates the method'sList[AttackResult]return type. Normalize withrows_to_attack_results()to ensure orchestrator always hands back typed results.
results = flatten_run_result(attack_impl.run(**attack_params))
logger.info(f"{self.attack_type} attack completed")
return results
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| elif isinstance(item, dict): | ||
| try: | ||
| evaluations.append(Evaluation(**item)) | ||
| except (TypeError, ValueError): | ||
| # Legacy/technique-specific evaluation shape (e.g. | ||
| # fields like "classification") that doesn't match | ||
| # the Evaluation schema: preserve it verbatim. | ||
| evaluations.append(Evaluation(metadata=dict(item))) |
| from hackagent.attacks.types import ( | ||
| AttackResult, | ||
| attack_results_to_rows, | ||
| flatten_run_result, | ||
| ) |
Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.
_normalize_attack_results()duck-typing with a typedAttackResultmodel #399