attacklm 0.9.4__tar.gz → 0.9.8__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 (219) hide show
  1. attacklm-0.9.8/.github/workflows/ci.yml +33 -0
  2. attacklm-0.9.8/.github/workflows/release.yml +86 -0
  3. {attacklm-0.9.4 → attacklm-0.9.8}/CHANGELOG.md +17 -0
  4. {attacklm-0.9.4 → attacklm-0.9.8}/PKG-INFO +2 -1
  5. {attacklm-0.9.4 → attacklm-0.9.8}/pyproject.toml +1 -0
  6. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/_eval_loader.py +1 -1
  7. attacklm-0.9.8/src/attacklm/__version__.py +1 -0
  8. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_balance_buckets.py +21 -16
  9. attacklm-0.9.8/tests/test_cli.py +656 -0
  10. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_eval_loader.py +22 -7
  11. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_eval_retention.py +1 -1
  12. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_memory_optimization.py +8 -1
  13. attacklm-0.9.4/.github/workflows/release.yml +0 -99
  14. attacklm-0.9.4/src/attacklm/__version__.py +0 -1
  15. {attacklm-0.9.4 → attacklm-0.9.8}/.gitignore +0 -0
  16. {attacklm-0.9.4 → attacklm-0.9.8}/ATTRIBUTION.md +0 -0
  17. {attacklm-0.9.4 → attacklm-0.9.8}/CONTRIBUTING.md +0 -0
  18. {attacklm-0.9.4 → attacklm-0.9.8}/EVALUATION.md +0 -0
  19. {attacklm-0.9.4 → attacklm-0.9.8}/LICENSE +0 -0
  20. {attacklm-0.9.4 → attacklm-0.9.8}/MANIFEST.in +0 -0
  21. {attacklm-0.9.4 → attacklm-0.9.8}/Makefile +0 -0
  22. {attacklm-0.9.4 → attacklm-0.9.8}/NOTICE +0 -0
  23. {attacklm-0.9.4 → attacklm-0.9.8}/README.md +0 -0
  24. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/README.md +0 -0
  25. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/pyproject.toml +0 -0
  26. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/__init__.py +0 -0
  27. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/app.py +0 -0
  28. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/cli.py +0 -0
  29. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/presets.py +0 -0
  30. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/runner.py +0 -0
  31. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/__init__.py +0 -0
  32. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/command_forms.py +0 -0
  33. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/main_menu.py +0 -0
  34. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_form.py +0 -0
  35. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_live.py +0 -0
  36. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/widgets/__init__.py +0 -0
  37. {attacklm-0.9.4 → attacklm-0.9.8}/attacklm-gui/tests/test_gui.py +0 -0
  38. {attacklm-0.9.4 → attacklm-0.9.8}/data/ATTRIBUTION.md +0 -0
  39. {attacklm-0.9.4 → attacklm-0.9.8}/data/LEGAL.md +0 -0
  40. {attacklm-0.9.4 → attacklm-0.9.8}/data/REMOVAL.md +0 -0
  41. {attacklm-0.9.4 → attacklm-0.9.8}/data/bench/questions.jsonl +0 -0
  42. {attacklm-0.9.4 → attacklm-0.9.8}/data/bench/speed_context.txt +0 -0
  43. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/acquisition_report.json +0 -0
  44. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/manifest.json +0 -0
  45. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/README.md +0 -0
  46. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/_index.json +0 -0
  47. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  48. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  49. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  50. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  51. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  52. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  53. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  54. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  55. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  56. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  57. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  58. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  59. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  60. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  61. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  62. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  63. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/defensive/detection_engineering/data.jsonl +0 -0
  64. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  65. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  66. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  67. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  68. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  69. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  70. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  71. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  72. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  73. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  74. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  75. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  76. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  77. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  78. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  79. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  80. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  81. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  82. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  83. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  84. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  85. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  86. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  87. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  88. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  89. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  90. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  91. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  92. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  93. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/defensive/threat_hunting/data.jsonl +0 -0
  94. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  95. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  96. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/defensive/incident_response/data.jsonl +0 -0
  97. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  98. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  99. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  100. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  101. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  102. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  103. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  104. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  105. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  106. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  107. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  108. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  109. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  110. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  111. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  112. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  113. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  114. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/defensive/detection_engineering/data.jsonl +0 -0
  115. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  116. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  117. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/defensive/detection_engineering/data.jsonl +0 -0
  118. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  119. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  120. {attacklm-0.9.4 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/defensive/threat_hunting/data.jsonl +0 -0
  121. {attacklm-0.9.4 → attacklm-0.9.8}/data/golden/prompts.jsonl +0 -0
  122. {attacklm-0.9.4 → attacklm-0.9.8}/data/reference/prompts.jsonl +0 -0
  123. {attacklm-0.9.4 → attacklm-0.9.8}/data/steering/prompts/opsec_aware.txt +0 -0
  124. {attacklm-0.9.4 → attacklm-0.9.8}/data/steering/prompts/opsec_unaware.txt +0 -0
  125. {attacklm-0.9.4 → attacklm-0.9.8}/data/steering/prompts/succinct.txt +0 -0
  126. {attacklm-0.9.4 → attacklm-0.9.8}/data/steering/prompts/verbose.txt +0 -0
  127. {attacklm-0.9.4 → attacklm-0.9.8}/experiments/README.md +0 -0
  128. {attacklm-0.9.4 → attacklm-0.9.8}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  129. {attacklm-0.9.4 → attacklm-0.9.8}/hf/.gitattributes +0 -0
  130. {attacklm-0.9.4 → attacklm-0.9.8}/hf/README.md +0 -0
  131. {attacklm-0.9.4 → attacklm-0.9.8}/hf/data/manifest.json +0 -0
  132. {attacklm-0.9.4 → attacklm-0.9.8}/hf/dataset_infos.json +0 -0
  133. {attacklm-0.9.4 → attacklm-0.9.8}/hf/scripts/build_hf_dataset.py +0 -0
  134. {attacklm-0.9.4 → attacklm-0.9.8}/hf/scripts/push_to_hf.py +0 -0
  135. {attacklm-0.9.4 → attacklm-0.9.8}/hpo_runs/.gitkeep +0 -0
  136. {attacklm-0.9.4 → attacklm-0.9.8}/hpo_runs/hpo_state.json +0 -0
  137. {attacklm-0.9.4 → attacklm-0.9.8}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  138. {attacklm-0.9.4 → attacklm-0.9.8}/logs/.gitkeep +0 -0
  139. {attacklm-0.9.4 → attacklm-0.9.8}/pipeline.example.yaml +0 -0
  140. {attacklm-0.9.4 → attacklm-0.9.8}/presets/blue-team.json +0 -0
  141. {attacklm-0.9.4 → attacklm-0.9.8}/presets/deepspeed/README.md +0 -0
  142. {attacklm-0.9.4 → attacklm-0.9.8}/presets/deepspeed/zero2_cpu_offload.json +0 -0
  143. {attacklm-0.9.4 → attacklm-0.9.8}/presets/deepspeed/zero3_cpu_offload.json +0 -0
  144. {attacklm-0.9.4 → attacklm-0.9.8}/presets/deepspeed/zero3_gpu_only.json +0 -0
  145. {attacklm-0.9.4 → attacklm-0.9.8}/presets/purple-team.json +0 -0
  146. {attacklm-0.9.4 → attacklm-0.9.8}/presets/red-team.json +0 -0
  147. {attacklm-0.9.4 → attacklm-0.9.8}/requirements.txt +0 -0
  148. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_cloud_attack_dataset.py +0 -0
  149. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_ics_dataset.py +0 -0
  150. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_phishing_dataset.py +0 -0
  151. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_red_team_tactics.py +0 -0
  152. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_replay_general.py +0 -0
  153. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_supply_chain_dataset.py +0 -0
  154. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_web_attack_dataset.py +0 -0
  155. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/acquire_wireless_dataset.py +0 -0
  156. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/audit_dataset.py +0 -0
  157. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/balance_buckets.py +0 -0
  158. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/bucket_loader.py +0 -0
  159. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/build.py +0 -0
  160. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/clone_repos.sh +0 -0
  161. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/collect_reference.py +0 -0
  162. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/compare_scores.py +0 -0
  163. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/convert_to_gguf.py +0 -0
  164. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/demo.py +0 -0
  165. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/device_utils.py +0 -0
  166. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/domain_bench.py +0 -0
  167. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/eval_retention.py +0 -0
  168. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/evolve_pairs.py +0 -0
  169. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/evolved_mixer.py +0 -0
  170. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  171. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  172. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_by_tactic.py +0 -0
  173. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  174. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_elastic_rules.py +0 -0
  175. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  176. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_mordor.py +0 -0
  177. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_nist_ir.py +0 -0
  178. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_rta_to_jsonl.py +0 -0
  179. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_sigma_defensive.py +0 -0
  180. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_splunk_content.py +0 -0
  181. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/extract_threathunter_playbook.py +0 -0
  182. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/filter_evolved.py +0 -0
  183. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/generate_synthetic_scarce.py +0 -0
  184. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/golden_vectors.py +0 -0
  185. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/hpo_runner.py +0 -0
  186. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/import_gguf.sh +0 -0
  187. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/import_to_lmstudio.sh +0 -0
  188. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/infer.py +0 -0
  189. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/init_pipeline.py +0 -0
  190. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/merge_adapter.py +0 -0
  191. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/mitre_tactic_lookup.py +0 -0
  192. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/package_dataset.py +0 -0
  193. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/parse_metasploit_to_jsonl.py +0 -0
  194. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/pipeline.py +0 -0
  195. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/rebuild_manifest.py +0 -0
  196. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/register_ollama.py +0 -0
  197. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/reorganize_buckets.py +0 -0
  198. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/replay_mixer.py +0 -0
  199. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/score_candidates.py +0 -0
  200. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/setup_buckets.py +0 -0
  201. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/speed_bench.py +0 -0
  202. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/steering.py +0 -0
  203. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/train_all.py +0 -0
  204. {attacklm-0.9.4 → attacklm-0.9.8}/scripts/train_template.py +0 -0
  205. {attacklm-0.9.4 → attacklm-0.9.8}/src/attacklm/__init__.py +0 -0
  206. {attacklm-0.9.4 → attacklm-0.9.8}/src/attacklm/_project_root.py +0 -0
  207. {attacklm-0.9.4 → attacklm-0.9.8}/src/attacklm/cli.py +0 -0
  208. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_collect_reference.py +0 -0
  209. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_compare_scores.py +0 -0
  210. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_domain_bench.py +0 -0
  211. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_evolve_pairs.py +0 -0
  212. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_golden_vectors.py +0 -0
  213. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_init_pipeline.py +0 -0
  214. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_replay_mixer.py +0 -0
  215. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_score_candidates.py +0 -0
  216. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_speed_bench.py +0 -0
  217. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_steering.py +0 -0
  218. {attacklm-0.9.4 → attacklm-0.9.8}/tests/test_thinking_models.py +0 -0
  219. {attacklm-0.9.4 → attacklm-0.9.8}/uv.lock +0 -0
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+
22
+ - name: Install dependencies
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e ".[dev,extract]"
26
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
27
+
28
+ - name: Run tests
29
+ run: pytest tests/ -v
30
+
31
+ - name: Lint
32
+ run: ruff check src/ tests/ scripts/
33
+ continue-on-error: true
@@ -0,0 +1,86 @@
1
+ # AttackLM — Publish to PyPI
2
+ #
3
+ # Trigger: push a tag matching v* (e.g., git tag v0.9.4 && git push origin v0.9.4)
4
+ #
5
+ # Uses PyPI Trusted Publishing (OIDC). The repository is configured as a
6
+ # trusted publisher on PyPI with environment name "pypi".
7
+ # No API tokens or passwords are stored in GitHub secrets.
8
+
9
+ name: Release
10
+
11
+ on:
12
+ push:
13
+ tags: ["v*"]
14
+
15
+ jobs:
16
+ validate:
17
+ name: Validate version
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Validate version
23
+ run: |
24
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
25
+ PKG_VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' src/attacklm/__version__.py)
26
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
27
+ echo "Tag v${TAG_VERSION} != package __version__ ${PKG_VERSION}"
28
+ exit 1
29
+ fi
30
+ echo "Version $PKG_VERSION validated"
31
+
32
+ test:
33
+ name: Run tests
34
+ needs: validate
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+
39
+ - uses: actions/setup-python@v5
40
+ with:
41
+ python-version: "3.13"
42
+
43
+ - name: Install
44
+ run: |
45
+ pip install -e ".[dev,extract]"
46
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
47
+
48
+ - name: Test
49
+ run: pytest tests/ -v
50
+
51
+ build:
52
+ name: Build distribution
53
+ needs: test
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - uses: actions/setup-python@v5
59
+ with:
60
+ python-version: "3.13"
61
+
62
+ - name: Install build
63
+ run: pip install build
64
+
65
+ - name: Build
66
+ run: python -m build
67
+
68
+ - uses: actions/upload-artifact@v4
69
+ with:
70
+ name: dist
71
+ path: dist/
72
+
73
+ publish:
74
+ name: Publish to PyPI
75
+ needs: build
76
+ runs-on: ubuntu-latest
77
+ environment: pypi
78
+ permissions:
79
+ id-token: write
80
+ steps:
81
+ - uses: actions/download-artifact@v4
82
+ with:
83
+ name: dist
84
+ path: dist/
85
+
86
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.5] — 2026-07-05 — CI/CD, test fixes, CLI tests, GitHub Releases
4
+
5
+ ### Added
6
+ - **GitHub Actions CI**: `.github/workflows/ci.yml` — runs on push/PR to main, matrix across Python 3.11/3.12/3.13, full test suite + ruff lint
7
+ - **PyPI publish workflow**: `.github/workflows/release.yml` — OIDC Trusted Publishing, validate → test → build → publish pipeline on tag push
8
+ - **CLI subcommand tests**: `tests/test_cli.py` — 33 tests covering all 8 subcommands (train, init, balance, build, infer, eval, demo, gui) plus edge cases
9
+ - **GitHub Releases**: Created releases for v0.8.3 through v0.9.4 with full CHANGELOG notes
10
+
11
+ ### Fixed
12
+ - **11 test failures resolved** (414 tests passing, up from 333):
13
+ - `test_eval_loader.py`: Fixed mock structure (transformers.utils, peft), missing adapter_path arg, CWD pollution, empty string handling
14
+ - `test_eval_retention.py`: Fixed CWD capture in test_adapter_relative_path
15
+ - `test_memory_optimization.py`: Added transformers mock before train_template import
16
+ - `_eval_loader.py`: Empty model_id_or_path now raises ValueError
17
+
18
+ ---
19
+
3
20
  ## [0.9.3] — 2026-07-04 — Remove deprecated hyphenated commands, --compile + QLoRA guard
4
21
 
5
22
  ### Removed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.9.4
3
+ Version: 0.9.8
4
4
  Summary: A high-performance fine-tuning pipeline (QLoRA, GaLore, Q-GaLore, Spectrum, PiSSA, DeepSpeed) for creating MITRE ATT&CK-grounded security AI assistants
5
5
  Project-URL: Homepage, https://github.com/Veedubin/AttackLM
6
6
  Project-URL: Repository, https://github.com/Veedubin/AttackLM
@@ -94,6 +94,7 @@ Provides-Extra: dev
94
94
  Requires-Dist: ipython; extra == 'dev'
95
95
  Requires-Dist: mypy; extra == 'dev'
96
96
  Requires-Dist: pytest; extra == 'dev'
97
+ Requires-Dist: rich; extra == 'dev'
97
98
  Requires-Dist: ruff; extra == 'dev'
98
99
  Requires-Dist: scipy>=1.11; extra == 'dev'
99
100
  Provides-Extra: eval
@@ -209,6 +209,7 @@ dev = [
209
209
  "mypy",
210
210
  "ipython",
211
211
  "scipy>=1.11", # needed for eval tests (Spearman correlation)
212
+ "rich", # needed by train_template.py (imported in tests)
212
213
  ]
213
214
  eval = [
214
215
  "scipy>=1.11", # for Spearman correlation in golden_vectors.py
@@ -50,7 +50,7 @@ def resolve_model_path(model_id_or_path: str) -> str:
50
50
  Otherwise, return it as-is (assumed to be an HF Hub model ID).
51
51
  """
52
52
  if not model_id_or_path:
53
- return model_id_or_path
53
+ raise ValueError("model_id_or_path must not be empty")
54
54
  p = model_id_or_path.rstrip("/")
55
55
  is_path = (
56
56
  p.startswith(("/", "./", "../", "~/"))
@@ -0,0 +1 @@
1
+ __version__ = "0.9.8"
@@ -203,25 +203,30 @@ class TestOutputPathResolution(unittest.TestCase):
203
203
 
204
204
  def test_no_timestamp_with_completed_dir_refuses(self):
205
205
  """--no-timestamp refuses to clobber a completed run."""
206
- # models/attacklm-3b_16g is a real completed run in the repo
207
- with self.assertRaises(FileExistsError) as ctx:
208
- self.train_template.resolve_output_path(
209
- "models/attacklm-3b_16g",
210
- no_timestamp=True,
211
- force=False,
212
- )
213
- self.assertIn("Refusing to clobber", str(ctx.exception))
206
+ with tempfile.TemporaryDirectory() as tmp:
207
+ model_dir = Path(tmp) / "completed_model"
208
+ model_dir.mkdir()
209
+ (model_dir / "state.json").write_text('{"completed": true}')
210
+ with self.assertRaises(FileExistsError) as ctx:
211
+ self.train_template.resolve_output_path(
212
+ str(model_dir),
213
+ no_timestamp=True,
214
+ force=False,
215
+ )
216
+ self.assertIn("Refusing to clobber", str(ctx.exception))
214
217
 
215
218
  def test_no_timestamp_with_force_allows(self):
216
219
  """--no-timestamp + --force on a completed run is allowed."""
217
- out = self.train_template.resolve_output_path(
218
- "models/attacklm-3b_16g",
219
- no_timestamp=True,
220
- force=True,
221
- )
222
- self.assertTrue(
223
- out.endswith("models/attacklm-3b_16g") or "attacklm-3b_16g" in out
224
- )
220
+ with tempfile.TemporaryDirectory() as tmp:
221
+ model_dir = Path(tmp) / "completed_model"
222
+ model_dir.mkdir()
223
+ (model_dir / "state.json").write_text('{"completed": true}')
224
+ out = self.train_template.resolve_output_path(
225
+ str(model_dir),
226
+ no_timestamp=True,
227
+ force=True,
228
+ )
229
+ self.assertTrue(out.endswith("completed_model") or "completed_model" in out)
225
230
 
226
231
 
227
232
  class TestCapResolution(unittest.TestCase):