attacklm 0.6.0__tar.gz → 0.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. {attacklm-0.6.0 → attacklm-0.6.2}/.github/workflows/release.yml +18 -0
  2. {attacklm-0.6.0 → attacklm-0.6.2}/CHANGELOG.md +13 -7
  3. {attacklm-0.6.0 → attacklm-0.6.2}/PKG-INFO +1 -1
  4. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/train_template.py +56 -50
  5. attacklm-0.6.2/src/attacklm/__version__.py +1 -0
  6. attacklm-0.6.0/src/attacklm/__version__.py +0 -1
  7. {attacklm-0.6.0 → attacklm-0.6.2}/.gitignore +0 -0
  8. {attacklm-0.6.0 → attacklm-0.6.2}/ATTRIBUTION.md +0 -0
  9. {attacklm-0.6.0 → attacklm-0.6.2}/CONTRIBUTING.md +0 -0
  10. {attacklm-0.6.0 → attacklm-0.6.2}/EVALUATION.md +0 -0
  11. {attacklm-0.6.0 → attacklm-0.6.2}/LICENSE +0 -0
  12. {attacklm-0.6.0 → attacklm-0.6.2}/MANIFEST.in +0 -0
  13. {attacklm-0.6.0 → attacklm-0.6.2}/Makefile +0 -0
  14. {attacklm-0.6.0 → attacklm-0.6.2}/NOTICE +0 -0
  15. {attacklm-0.6.0 → attacklm-0.6.2}/QA_BEFORE_RELEASES.md +0 -0
  16. {attacklm-0.6.0 → attacklm-0.6.2}/README.md +0 -0
  17. {attacklm-0.6.0 → attacklm-0.6.2}/REPLAY_PLAN.md +0 -0
  18. {attacklm-0.6.0 → attacklm-0.6.2}/data/ATTRIBUTION.md +0 -0
  19. {attacklm-0.6.0 → attacklm-0.6.2}/data/LEGAL.md +0 -0
  20. {attacklm-0.6.0 → attacklm-0.6.2}/data/REMOVAL.md +0 -0
  21. {attacklm-0.6.0 → attacklm-0.6.2}/data/bench/questions.jsonl +0 -0
  22. {attacklm-0.6.0 → attacklm-0.6.2}/data/bench/speed_context.txt +0 -0
  23. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/ATTRIBUTION.md +0 -0
  24. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/GEMINI_RESEARCH_2026-06-11.md +0 -0
  25. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/acquisition_report.json +0 -0
  26. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/manifest.json +0 -0
  27. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/README.md +0 -0
  28. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/_index.json +0 -0
  29. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  30. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  31. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  32. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  33. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  34. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  35. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  36. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  37. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  38. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  39. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  40. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  41. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  42. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  43. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  44. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  45. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  46. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  47. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  48. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  49. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  50. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  51. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  52. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  53. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  54. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  55. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  56. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  57. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  58. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  59. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  60. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  61. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  62. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  63. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  64. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  65. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  66. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  67. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  68. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  69. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  70. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  71. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  72. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  73. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  74. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  75. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  76. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  77. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  78. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  79. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  80. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  81. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  82. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  83. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  84. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  85. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  86. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  87. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  88. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  89. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  90. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  91. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  92. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  93. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  94. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  95. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  96. {attacklm-0.6.0 → attacklm-0.6.2}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  97. {attacklm-0.6.0 → attacklm-0.6.2}/data/golden/prompts.jsonl +0 -0
  98. {attacklm-0.6.0 → attacklm-0.6.2}/data/reference/prompts.jsonl +0 -0
  99. {attacklm-0.6.0 → attacklm-0.6.2}/data/steering/prompts/opsec_aware.txt +0 -0
  100. {attacklm-0.6.0 → attacklm-0.6.2}/data/steering/prompts/opsec_unaware.txt +0 -0
  101. {attacklm-0.6.0 → attacklm-0.6.2}/data/steering/prompts/succinct.txt +0 -0
  102. {attacklm-0.6.0 → attacklm-0.6.2}/data/steering/prompts/verbose.txt +0 -0
  103. {attacklm-0.6.0 → attacklm-0.6.2}/experiments/README.md +0 -0
  104. {attacklm-0.6.0 → attacklm-0.6.2}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  105. {attacklm-0.6.0 → attacklm-0.6.2}/hf/.gitattributes +0 -0
  106. {attacklm-0.6.0 → attacklm-0.6.2}/hf/README.md +0 -0
  107. {attacklm-0.6.0 → attacklm-0.6.2}/hf/data/manifest.json +0 -0
  108. {attacklm-0.6.0 → attacklm-0.6.2}/hf/dataset_infos.json +0 -0
  109. {attacklm-0.6.0 → attacklm-0.6.2}/hf/scripts/build_hf_dataset.py +0 -0
  110. {attacklm-0.6.0 → attacklm-0.6.2}/hf/scripts/push_to_hf.py +0 -0
  111. {attacklm-0.6.0 → attacklm-0.6.2}/hpo_runs/.gitkeep +0 -0
  112. {attacklm-0.6.0 → attacklm-0.6.2}/hpo_runs/hpo_state.json +0 -0
  113. {attacklm-0.6.0 → attacklm-0.6.2}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  114. {attacklm-0.6.0 → attacklm-0.6.2}/logs/.gitkeep +0 -0
  115. {attacklm-0.6.0 → attacklm-0.6.2}/notes/BLUE_TEAM_DESIGN_v0.5.0.md +0 -0
  116. {attacklm-0.6.0 → attacklm-0.6.2}/notes/EVAL_DESIGN_v0.4.0.md +0 -0
  117. {attacklm-0.6.0 → attacklm-0.6.2}/notes/STEERING_REVIEW_v0.4.0.md +0 -0
  118. {attacklm-0.6.0 → attacklm-0.6.2}/pipeline.example.yaml +0 -0
  119. {attacklm-0.6.0 → attacklm-0.6.2}/presets/blue-team.json +0 -0
  120. {attacklm-0.6.0 → attacklm-0.6.2}/presets/purple-team.json +0 -0
  121. {attacklm-0.6.0 → attacklm-0.6.2}/presets/red-team.json +0 -0
  122. {attacklm-0.6.0 → attacklm-0.6.2}/pyproject.toml +0 -0
  123. {attacklm-0.6.0 → attacklm-0.6.2}/requirements.txt +0 -0
  124. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/_eval_loader.py +0 -0
  125. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_cloud_attack_dataset.py +0 -0
  126. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_ics_dataset.py +0 -0
  127. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_phishing_dataset.py +0 -0
  128. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_red_team_tactics.py +0 -0
  129. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_replay_general.py +0 -0
  130. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_supply_chain_dataset.py +0 -0
  131. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_web_attack_dataset.py +0 -0
  132. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/acquire_wireless_dataset.py +0 -0
  133. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/add_attribution.py +0 -0
  134. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/audit_dataset.py +0 -0
  135. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/augment_attribution.py +0 -0
  136. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/balance_buckets.py +0 -0
  137. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/bucket_loader.py +0 -0
  138. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/build.py +0 -0
  139. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/classify_unrouted_modules.py +0 -0
  140. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/clone_repos.sh +0 -0
  141. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/collect_reference.py +0 -0
  142. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/compare_scores.py +0 -0
  143. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/convert_to_gguf.py +0 -0
  144. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/dedupe_and_import_llm.py +0 -0
  145. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/demo.py +0 -0
  146. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/device_utils.py +0 -0
  147. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/domain_bench.py +0 -0
  148. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/eval_retention.py +0 -0
  149. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  150. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  151. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_by_tactic.py +0 -0
  152. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  153. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_elastic_rules.py +0 -0
  154. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  155. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_mordor.py +0 -0
  156. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_nist_ir.py +0 -0
  157. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_rta_to_jsonl.py +0 -0
  158. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_sigma_defensive.py +0 -0
  159. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_splunk_content.py +0 -0
  160. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/extract_threathunter_playbook.py +0 -0
  161. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_dataset.py +0 -0
  162. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_dataset_deterministic.py +0 -0
  163. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_hybrid_dataset.py +0 -0
  164. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_metasploit_dataset.py +0 -0
  165. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_orchestrator.py +0 -0
  166. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_prompt_injection.py +0 -0
  167. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_source_layout.py +0 -0
  168. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/generate_synthetic_scarce.py +0 -0
  169. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/golden_vectors.py +0 -0
  170. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/hpo_runner.py +0 -0
  171. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/import_gguf.sh +0 -0
  172. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/import_to_lmstudio.sh +0 -0
  173. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/infer.py +0 -0
  174. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/init_pipeline.py +0 -0
  175. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/llm_generate_wrapper.py +0 -0
  176. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/merge_adapter.py +0 -0
  177. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/migrate_buckets_to_v021.py +0 -0
  178. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/migrate_v015_to_v020.py +0 -0
  179. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/mitre_tactic_lookup.py +0 -0
  180. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/parse_metasploit_to_jsonl.py +0 -0
  181. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/pipeline.py +0 -0
  182. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/rebuild_manifest.py +0 -0
  183. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/register_ollama.py +0 -0
  184. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/reorganize_buckets.py +0 -0
  185. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/replay_mixer.py +0 -0
  186. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/run_all_acquisitions.py +0 -0
  187. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/score_candidates.py +0 -0
  188. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/scrub_bpl_callback.py +0 -0
  189. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/setup_buckets.py +0 -0
  190. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/speed_bench.py +0 -0
  191. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/stamp_and_reorg.py +0 -0
  192. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/steering.py +0 -0
  193. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/train_all.py +0 -0
  194. {attacklm-0.6.0 → attacklm-0.6.2}/scripts/validate_per_category.py +0 -0
  195. {attacklm-0.6.0 → attacklm-0.6.2}/src/attacklm/__init__.py +0 -0
  196. {attacklm-0.6.0 → attacklm-0.6.2}/src/attacklm/_project_root.py +0 -0
  197. {attacklm-0.6.0 → attacklm-0.6.2}/src/attacklm/cli.py +0 -0
  198. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_balance_buckets.py +0 -0
  199. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_collect_reference.py +0 -0
  200. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_compare_scores.py +0 -0
  201. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_domain_bench.py +0 -0
  202. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_eval_loader.py +0 -0
  203. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_eval_retention.py +0 -0
  204. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_golden_vectors.py +0 -0
  205. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_init_pipeline.py +0 -0
  206. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_replay_mixer.py +0 -0
  207. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_score_candidates.py +0 -0
  208. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_speed_bench.py +0 -0
  209. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_steering.py +0 -0
  210. {attacklm-0.6.0 → attacklm-0.6.2}/tests/test_thinking_models.py +0 -0
  211. {attacklm-0.6.0 → attacklm-0.6.2}/uv.lock +0 -0
@@ -14,8 +14,26 @@ on:
14
14
  - "v*"
15
15
 
16
16
  jobs:
17
+ validate:
18
+ name: Validate version 🔍
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Check tag matches __version__.py
24
+ run: |
25
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
26
+ FILE_VERSION=$(python3 -c "exec(open('src/attacklm/__version__.py').read()); print(__version__)")
27
+ if [ "$TAG_VERSION" != "$FILE_VERSION" ]; then
28
+ echo "ERROR: Tag v${TAG_VERSION} does not match __version__.py (${FILE_VERSION})"
29
+ echo "Bump src/attacklm/__version__.py to ${TAG_VERSION} before pushing the tag."
30
+ exit 1
31
+ fi
32
+ echo "Version validated: v${TAG_VERSION} == __version__.py (${FILE_VERSION})"
33
+
17
34
  build:
18
35
  name: Build distribution 📦
36
+ needs: validate
19
37
  runs-on: ubuntu-latest
20
38
  steps:
21
39
  - uses: actions/checkout@v4
@@ -4,17 +4,23 @@ All notable changes to AttackLM are documented in this file. Versions follow [Se
4
4
 
5
5
  ---
6
6
 
7
- ## [0.6.0] — 2026-06-28 — Q-GaLore, Spectrum, PiSSA init
7
+ ## [0.6.1] — 2026-06-28 — Fix --use-galore API
8
8
 
9
- ### Added
9
+ ### Fixed
10
10
 
11
- - **Q-GaLore (default)**: INT4 quantized gradient projection matrices with stochastic rounding. Cuts optimizer memory ~4x vs vanilla GaLore. Enables 7B full-parameter training on 16GB GPUs. Paper: arXiv:2407.08296. Use `--galore-fp16` for vanilla GaLore.
12
- - **Spectrum**: SNR-based layer freezing. Computes signal-to-noise ratio per layer and freezes the lowest-SNR layers. `--spectrum` keeps top 50%, `--spectrum 0.25` keeps top 25%. Reduces VRAM proportionally. Compatible with any training method. Paper: arXiv:2406.06623.
13
- - **PiSSA init**: SVD-based LoRA initialization. `--pissa-init` initializes LoRA weights from the SVD of pre-trained weights instead of random Kaiming init. Faster convergence, lower final loss. Paper: arXiv:2404.02948.
11
+ - **`--use-galore` restored to vanilla GaLore** (FP16 projections). Q-GaLore is now `--use-qgalore` (separate flag). This preserves backward compatibility existing `--use-galore` commands continue to work.
12
+ - **Removed `--galore-fp16`** (redundant `--use-galore` is FP16 by default).
13
+ - **CI validation**: added version check job that fails the workflow if the git tag doesn't match `__version__.py`, preventing duplicate PyPI uploads.
14
14
 
15
- ### Changed
15
+ ---
16
+
17
+ ## [0.6.0] — 2026-06-28 — Q-GaLore, Spectrum, PiSSA init
18
+
19
+ ### Added
16
20
 
17
- - **Default change**: `--use-galore` now defaults to Q-GaLore (INT4). Use `--galore-fp16` for vanilla GaLore.
21
+ - **Q-GaLore** (`--use-qgalore`): INT4 quantized gradient projection matrices with stochastic rounding. Cuts optimizer memory ~4x vs vanilla GaLore. Enables 7B full-parameter training on 16GB GPUs. Requires `--use-galore`. Paper: arXiv:2407.08296.
22
+ - **Spectrum** (`--spectrum`): SNR-based layer freezing. Computes signal-to-noise ratio per layer and freezes the lowest-SNR layers. `--spectrum` keeps top 50%, `--spectrum 0.25` keeps top 25%. Reduces VRAM proportionally. Compatible with any training method. Paper: arXiv:2406.06623.
23
+ - **PiSSA init** (`--pissa-init`): SVD-based LoRA initialization. Initializes LoRA weights from the SVD of pre-trained weights instead of random Kaiming init. Faster convergence, lower final loss. Paper: arXiv:2404.02948.
18
24
 
19
25
  ---
20
26
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: QLoRA-fine-tuned Qwen2.5-Coder for offensive/defensive security and AI red-teaming
5
5
  Project-URL: Homepage, https://github.com/Veedubin/AttackLM
6
6
  Project-URL: Repository, https://github.com/Veedubin/AttackLM
@@ -389,17 +389,29 @@ Examples:
389
389
  action="store_true",
390
390
  default=False,
391
391
  help=(
392
- "Use Q-GaLore (Quantized Gradient Low-Rank Projection) for "
393
- "full-parameter fine-tuning. Q-GaLore quantizes gradient "
394
- "projection matrices to INT4 with stochastic rounding, "
395
- "enabling 7B full-parameter training on 16GB GPUs. "
396
- "Mutually exclusive with --use-unsloth. "
392
+ "Use GaLore (Gradient Low-Rank Projection) for full-parameter "
393
+ "fine-tuning. GaLore projects gradients into a low-rank space "
394
+ "during optimization, enabling full-parameter learning on "
395
+ "consumer GPUs without LoRA adapters. Mutually exclusive with "
396
+ "--use-unsloth (GaLore trains ALL parameters, no LoRA needed). "
397
397
  "Requires 'uv pip install attacklm[galore]'. "
398
- "Default: Q-GaLore (INT4 projections + 8-bit optimizer). "
399
- "Use --galore-fp16 for vanilla GaLore (FP16 projections). "
398
+ "Default: 8-bit optimizer + per-layer hooks (fits 3B on 16GB). "
399
+ "Use --use-qgalore for INT4 projections (fits 7B on 16GB). "
400
400
  "Use --galore-32bit for full-precision (needs ~20GB+ for 3B)."
401
401
  ),
402
402
  )
403
+ parser.add_argument(
404
+ "--use-qgalore",
405
+ action="store_true",
406
+ default=False,
407
+ help=(
408
+ "Use Q-GaLore: INT4 quantized gradient projection matrices "
409
+ "with stochastic rounding. Cuts optimizer memory by ~4x vs "
410
+ "vanilla GaLore, enabling 7B full-parameter training on 16GB. "
411
+ "Mutually exclusive with --use-galore and --use-unsloth. "
412
+ "Paper: arXiv:2407.08296."
413
+ ),
414
+ )
403
415
  parser.add_argument(
404
416
  "--galore-32bit",
405
417
  action="store_true",
@@ -433,19 +445,6 @@ Examples:
433
445
  "scales with rank². Only meaningful with --use-galore."
434
446
  ),
435
447
  )
436
- parser.add_argument(
437
- "--galore-fp16",
438
- action="store_true",
439
- default=False,
440
- help=(
441
- "Use vanilla GaLore with FP16 projection matrices instead of "
442
- "the default Q-GaLore (INT4 quantized projections). "
443
- "Q-GaLore cuts optimizer memory by ~4x vs vanilla GaLore, "
444
- "enabling 7B models on 16GB. Use --galore-fp16 if you need "
445
- "maximum precision (e.g., for a rented A100 with plenty of VRAM). "
446
- "Only meaningful with --use-galore."
447
- ),
448
- )
449
448
  parser.add_argument(
450
449
  "--spectrum",
451
450
  type=float,
@@ -483,6 +482,11 @@ Examples:
483
482
  # ---------------------------------------------------------------------------
484
483
 
485
484
 
485
+ def _is_galore(args) -> bool:
486
+ """True if either --use-galore or --use-qgalore is active."""
487
+ return args.use_galore or args.use_qgalore
488
+
489
+
486
490
  def _resolve_model_path(model_id_or_path: str) -> str:
487
491
  """Resolve a user-supplied base-model argument to something `from_pretrained`
488
492
  can actually load.
@@ -1631,7 +1635,7 @@ def main() -> None:
1631
1635
  )
1632
1636
  _galore_display = (
1633
1637
  f"ON (full-parameter, rank={args.galore_rank}, update_proj_gap=200, scale=0.25)"
1634
- if args.use_galore
1638
+ if _is_galore(args)
1635
1639
  else "OFF"
1636
1640
  )
1637
1641
 
@@ -1641,13 +1645,13 @@ def main() -> None:
1641
1645
  _plan.add_row("Model", args.base_model)
1642
1646
  if args.use_unsloth:
1643
1647
  _plan.add_row("Quantization", "4-bit (Unsloth internal)")
1644
- elif args.use_galore:
1648
+ elif _is_galore(args):
1645
1649
  _plan.add_row("Quantization", "NONE (bf16 full-parameter for GaLore)")
1646
1650
  elif not args.moe_safe_target:
1647
1651
  _plan.add_row("Quantization", "4-bit NF4 (double quant)")
1648
1652
  else:
1649
1653
  _plan.add_row("Quantization", "NONE (bf16 full-precision for MoE)")
1650
- if args.use_galore:
1654
+ if _is_galore(args):
1651
1655
  _plan.add_row("Training mode", "GaLore full-parameter (no LoRA)")
1652
1656
  else:
1653
1657
  _plan.add_row("LoRA rank", str(args.lora_r))
@@ -1700,7 +1704,7 @@ def main() -> None:
1700
1704
  "~4-5 GB (batch=2, len=2048) / ~3-4 GB (batch=1, len=1024)",
1701
1705
  )
1702
1706
  _dry_tbl.add_row("Note", "13B model fits in 16GB with Unsloth QLoRA")
1703
- if args.use_galore:
1707
+ if _is_galore(args):
1704
1708
  _dry_tbl.add_row(
1705
1709
  "Est. VRAM (GaLore)",
1706
1710
  "~10-12 GB (3B) / ~14-16 GB (7B), batch=1, len=2048",
@@ -1799,13 +1803,13 @@ def main() -> None:
1799
1803
  except Exception as e:
1800
1804
  console.print(f" [dim](Skipped state.json write: {e})[/dim]")
1801
1805
 
1802
- # --- Mutual exclusivity: GaLore vs Unsloth ---
1803
- if args.use_galore and args.use_unsloth:
1806
+ # --- Mutual exclusivity: GaLore/Q-GaLore vs Unsloth ---
1807
+ if (args.use_galore or args.use_qgalore) and args.use_unsloth:
1804
1808
  console.print(
1805
- "[red]ERROR:[/red] --use-galore and --use-unsloth are mutually exclusive.\n"
1806
- " GaLore is full-parameter training (no LoRA adapters).\n"
1809
+ "[red]ERROR:[/red] --use-galore/--use-qgalore and --use-unsloth are mutually exclusive.\n"
1810
+ " GaLore/Q-GaLore is full-parameter training (no LoRA adapters).\n"
1807
1811
  " Unsloth is optimized QLoRA (LoRA adapters on quantized base).\n"
1808
- " Choose one: --use-galore OR --use-unsloth, not both."
1812
+ " Choose one: --use-galore/--use-qgalore OR --use-unsloth, not both."
1809
1813
  )
1810
1814
  sys.exit(1)
1811
1815
 
@@ -1830,7 +1834,7 @@ def main() -> None:
1830
1834
 
1831
1835
  # --- GaLore: import galore-torch for full-parameter training ---
1832
1836
  _galore_available = False
1833
- if args.use_galore:
1837
+ if _is_galore(args):
1834
1838
  try:
1835
1839
  # Fix: bitsandbytes calls torch.utils._pytree.register_constant()
1836
1840
  # on Enum subclasses, which is deprecated in PyTorch 2.12+.
@@ -1864,7 +1868,7 @@ def main() -> None:
1864
1868
 
1865
1869
  # --multi-gpu + --use-galore: auto-enable 32-bit (per-layer hooks
1866
1870
  # are incompatible with DDP's gradient all-reduce).
1867
- if args.multi_gpu and args.use_galore and not args.galore_32bit:
1871
+ if args.multi_gpu and _is_galore(args) and not args.galore_32bit:
1868
1872
  console.print(
1869
1873
  " [yellow]GaLore:[/yellow] --multi-gpu detected — auto-enabling "
1870
1874
  "--galore-32bit (per-layer weight updates are incompatible with DDP)"
@@ -1920,7 +1924,9 @@ def main() -> None:
1920
1924
  # load_in_4bit parameter. We skip BitsAndBytes entirely.
1921
1925
  # --use-galore: GaLore is full-parameter training — no quantization
1922
1926
  # needed. Model is loaded in bf16/fp16 for full-parameter updates.
1923
- skip_quantization = args.moe_safe_target or args.use_unsloth or args.use_galore
1927
+ skip_quantization = (
1928
+ args.moe_safe_target or args.use_unsloth or args.use_galore or args.use_qgalore
1929
+ )
1924
1930
 
1925
1931
  if skip_quantization:
1926
1932
  bnb_config = None # No quantization for MoE-safe or Unsloth mode
@@ -2084,7 +2090,7 @@ def main() -> None:
2084
2090
  # trust_remote_code=False — the model is architecturally
2085
2091
  # identical to standard Qwen2.5-Coder, just abliterated weights.
2086
2092
  # The standard Qwen2ForCausalLM class respects torch_dtype.
2087
- if args.use_galore:
2093
+ if _is_galore(args):
2088
2094
  # Standard models (Qwen, Llama, etc.) load in bf16 with
2089
2095
  # dtype= directly. No config patching needed.
2090
2096
  # Note: huihui-ai abliterated models have custom code
@@ -2277,8 +2283,8 @@ def main() -> None:
2277
2283
  sys.exit(1)
2278
2284
 
2279
2285
  # --- Apply LoRA (or skip for GaLore full-parameter training) ---
2280
- if args.use_galore and _galore_available:
2281
- # GaLore: full-parameter training — no LoRA adapter needed.
2286
+ if _is_galore(args) and _galore_available:
2287
+ # GaLore/Q-GaLore: full-parameter training — no LoRA adapter needed.
2282
2288
  # GaLore projects gradients into a low-rank space during optimization,
2283
2289
  # so ALL model parameters are trained directly. No PEFT wrapping.
2284
2290
  print("GaLore: full-parameter training (no LoRA adapter)")
@@ -3304,17 +3310,17 @@ def main() -> None:
3304
3310
  hpo_callbacks.append(HPOMetricsCSVCallback(args.hpo_metrics_csv, hpo_label))
3305
3311
  print(f"\n HPO metrics CSV: {args.hpo_metrics_csv} (label={hpo_label})")
3306
3312
 
3307
- # --- Q-GaLore / GaLore: full-parameter training with gradient projection ---
3308
- # Q-GaLore (default): INT4 quantized projection matrices + stochastic
3309
- # rounding + layer-adaptive SVD skipping. Cuts optimizer memory ~4x vs
3310
- # vanilla GaLore. Enables 7B on 16GB.
3311
- # Vanilla GaLore (--galore-fp16): FP16 projection matrices.
3312
- # Paper: arXiv:2407.08296
3313
- if args.use_galore and _galore_available:
3313
+ # --- GaLore / Q-GaLore: full-parameter training with gradient projection ---
3314
+ # GaLore (--use-galore): FP16 projection matrices, 8-bit optimizer.
3315
+ # Fits 3B on 16GB, 7B on 24GB.
3316
+ # Q-GaLore (--use-qgalore): INT4 quantized projection matrices with
3317
+ # stochastic rounding. Cuts optimizer memory ~4x vs vanilla GaLore.
3318
+ # Enables 7B on 16GB. Paper: arXiv:2407.08296.
3319
+ if _is_galore(args) and _galore_available:
3314
3320
  from transformers import Trainer
3315
3321
 
3316
3322
  _use_32bit = args.galore_32bit
3317
- _use_qgalore = not args.galore_fp16 # Q-GaLore is the default
3323
+ _use_qgalore = args.use_qgalore
3318
3324
  _galore_rank = args.galore_rank
3319
3325
 
3320
3326
  if _use_qgalore:
@@ -3669,7 +3675,7 @@ def main() -> None:
3669
3675
  # use train_result.metrics["epoch"] for that because HF rounds it
3670
3676
  # to an int and we want the fractional value from log_history.
3671
3677
 
3672
- if args.use_galore and _galore_available:
3678
+ if _is_galore(args) and _galore_available:
3673
3679
  print(f"\nSaving GaLore full-parameter model to: {args.output}")
3674
3680
  else:
3675
3681
  print(f"\nSaving best LoRA adapter to: {args.output}")
@@ -3682,7 +3688,7 @@ def main() -> None:
3682
3688
  best_ckpt = Path(args.output) / "checkpoint-best"
3683
3689
  if best_ckpt.exists() and (best_ckpt / "model.safetensors").exists():
3684
3690
  print(f" Loading best checkpoint from: {best_ckpt}")
3685
- if args.use_galore and _galore_available:
3691
+ if (args.use_galore or args.use_qgalore) and _galore_available:
3686
3692
  # GaLore: full model, reload from checkpoint
3687
3693
  model = AutoModelForCausalLM.from_pretrained(
3688
3694
  str(best_ckpt),
@@ -3703,7 +3709,7 @@ def main() -> None:
3703
3709
  "base_model": args.base_model,
3704
3710
  "dataset": args.dataset,
3705
3711
  "training_mode": "galore_full_parameter"
3706
- if (args.use_galore and _galore_available)
3712
+ if (_is_galore(args) and _galore_available)
3707
3713
  else "qlora",
3708
3714
  "lora_r": args.lora_r,
3709
3715
  "lora_alpha": args.lora_alpha,
@@ -3728,7 +3734,7 @@ def main() -> None:
3728
3734
  if not skip_quantization
3729
3735
  else (
3730
3736
  "none (bf16 full-parameter for GaLore)"
3731
- if (args.use_galore and _galore_available)
3737
+ if (_is_galore(args) and _galore_available)
3732
3738
  else "none (bf16 full-precision for MoE)"
3733
3739
  ),
3734
3740
  "epochs": args.epochs,
@@ -3738,13 +3744,13 @@ def main() -> None:
3738
3744
  "packing": args.packing,
3739
3745
  "compute_dtype": compute_type,
3740
3746
  "optimizer": "galore_adamw"
3741
- if (args.use_galore and _galore_available)
3747
+ if (_is_galore(args) and _galore_available)
3742
3748
  else args.optim,
3743
3749
  "final_loss": final_loss,
3744
3750
  "training_time_seconds": round(elapsed, 2),
3745
3751
  "num_examples": len(dataset),
3746
3752
  }
3747
- if args.use_galore and _galore_available:
3753
+ if _is_galore(args) and _galore_available:
3748
3754
  config["galore_rank"] = 128
3749
3755
  config["galore_update_proj_gap"] = 200
3750
3756
  config["galore_scale"] = 0.25
@@ -3894,7 +3900,7 @@ def main() -> None:
3894
3900
  )
3895
3901
  summary_tbl.add_row("Config written to", config_path)
3896
3902
 
3897
- if args.use_galore and _galore_available:
3903
+ if _is_galore(args) and _galore_available:
3898
3904
  code = f"""from transformers import AutoModelForCausalLM, AutoTokenizer
3899
3905
 
3900
3906
  model = AutoModelForCausalLM.from_pretrained("{args.output}", device_map="auto")
@@ -0,0 +1 @@
1
+ __version__ = "0.6.2"
@@ -1 +0,0 @@
1
- __version__ = "0.6.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes