attacklm 0.9.2__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.
- attacklm-0.9.8/.github/workflows/ci.yml +33 -0
- attacklm-0.9.8/.github/workflows/release.yml +86 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/CHANGELOG.md +54 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/CONTRIBUTING.md +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/EVALUATION.md +6 -6
- {attacklm-0.9.2 → attacklm-0.9.8}/PKG-INFO +2 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/command_forms.py +3 -4
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_form.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/pipeline.example.yaml +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/pyproject.toml +6 -29
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/_eval_loader.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/balance_buckets.py +4 -4
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/build.py +8 -8
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/convert_to_gguf.py +12 -10
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_elastic_rules.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_mordor.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_sigma_defensive.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_splunk_content.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_threathunter_playbook.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/init_pipeline.py +23 -23
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/merge_adapter.py +3 -3
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/pipeline.py +4 -4
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/train_template.py +29 -7
- attacklm-0.9.8/src/attacklm/__version__.py +1 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/cli.py +12 -205
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_balance_buckets.py +21 -16
- attacklm-0.9.8/tests/test_cli.py +656 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_eval_loader.py +22 -7
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_eval_retention.py +1 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_init_pipeline.py +7 -2
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_memory_optimization.py +115 -1
- attacklm-0.9.2/.github/workflows/release.yml +0 -99
- attacklm-0.9.2/src/attacklm/__version__.py +0 -1
- {attacklm-0.9.2 → attacklm-0.9.8}/.gitignore +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/ATTRIBUTION.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/LICENSE +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/MANIFEST.in +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/Makefile +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/NOTICE +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/pyproject.toml +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/__init__.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/app.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/cli.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/presets.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/runner.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/__init__.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/main_menu.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_live.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/widgets/__init__.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/tests/test_gui.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/ATTRIBUTION.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/LEGAL.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/REMOVAL.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/bench/questions.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/bench/speed_context.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/acquisition_report.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/manifest.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/_index.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/defensive/detection_engineering/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/defensive/threat_hunting/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/defensive/incident_response/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/defensive/detection_engineering/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/defensive/detection_engineering/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/defensive/threat_hunting/data.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/golden/prompts.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/reference/prompts.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/opsec_aware.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/opsec_unaware.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/succinct.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/verbose.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/experiments/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/.gitattributes +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/data/manifest.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/dataset_infos.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/scripts/build_hf_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hf/scripts/push_to_hf.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/.gitkeep +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/hpo_state.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/logs/.gitkeep +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/blue-team.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/README.md +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero2_cpu_offload.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero3_cpu_offload.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero3_gpu_only.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/purple-team.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/presets/red-team.json +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/requirements.txt +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_cloud_attack_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_ics_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_phishing_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_red_team_tactics.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_replay_general.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_supply_chain_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_web_attack_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_wireless_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/audit_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/bucket_loader.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/clone_repos.sh +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/collect_reference.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/compare_scores.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/demo.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/device_utils.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/domain_bench.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/eval_retention.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/evolve_pairs.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/evolved_mixer.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_ai_tools_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_by_tactic.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_nist_ir.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_rta_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/filter_evolved.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/generate_synthetic_scarce.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/golden_vectors.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/hpo_runner.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/import_gguf.sh +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/import_to_lmstudio.sh +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/infer.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/mitre_tactic_lookup.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/package_dataset.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/parse_metasploit_to_jsonl.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/rebuild_manifest.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/register_ollama.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/reorganize_buckets.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/replay_mixer.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/score_candidates.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/setup_buckets.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/speed_bench.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/steering.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/scripts/train_all.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/__init__.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/_project_root.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_collect_reference.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_compare_scores.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_domain_bench.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_evolve_pairs.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_golden_vectors.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_replay_mixer.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_score_candidates.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_speed_bench.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_steering.py +0 -0
- {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_thinking_models.py +0 -0
- {attacklm-0.9.2 → 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,59 @@
|
|
|
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
|
+
|
|
20
|
+
## [0.9.3] — 2026-07-04 — Remove deprecated hyphenated commands, --compile + QLoRA guard
|
|
21
|
+
|
|
22
|
+
### Removed
|
|
23
|
+
- **Deprecated hyphenated commands**: All 22 `attacklm-*` console scripts removed from `pyproject.toml` and `cli.py` after the v0.8.x deprecation window. Use `attacklm <subcommand>` instead.
|
|
24
|
+
- `attacklm-train` → `attacklm train`
|
|
25
|
+
- `attacklm-train-all` → `attacklm train --all`
|
|
26
|
+
- `attacklm-train-lora` → `attacklm train`
|
|
27
|
+
- `attacklm-hpo` → `attacklm train --hpo`
|
|
28
|
+
- `attacklm-extract` → `attacklm init --extract-only`
|
|
29
|
+
- `attacklm-buckets` → `attacklm init --buckets-only`
|
|
30
|
+
- `attacklm-attribute` → `attacklm init --attribute-only`
|
|
31
|
+
- `attacklm-clone` → `attacklm init --clone-only`
|
|
32
|
+
- `attacklm-init` → `attacklm init`
|
|
33
|
+
- `attacklm-balance` → `attacklm balance`
|
|
34
|
+
- `attacklm-merge` → `attacklm build --merge-only`
|
|
35
|
+
- `attacklm-gguf` → `attacklm build --gguf-only`
|
|
36
|
+
- `attacklm-build` → `attacklm build`
|
|
37
|
+
- `attacklm-infer` → `attacklm infer`
|
|
38
|
+
- `attacklm-demo` → `attacklm demo`
|
|
39
|
+
- `attacklm-eval` → `attacklm eval`
|
|
40
|
+
- `attacklm-collect-ref` → `attacklm eval --collect-ref`
|
|
41
|
+
- `attacklm-score` → `attacklm eval --score`
|
|
42
|
+
- `attacklm-compare` → `attacklm eval --compare`
|
|
43
|
+
- `attacklm-golden` → `attacklm eval --golden`
|
|
44
|
+
- `attacklm-pipeline` → `attacklm pipeline`
|
|
45
|
+
- **Deprecated wrapper code**: Removed `_deprecated()` helper, `_DEPRECATED_MSG` constant, and all 19 `main_*` wrapper functions from `src/attacklm/cli.py`
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- **`--compile` + QLoRA incompatibility guard**: `train_template.py` now exits with a clear error if `--compile` is used with default 4-bit QLoRA (BitsAndBytes NF4). torch.compile is incompatible with quantized models. Users are directed to use `--use-galore` or `--use-deepspeed` for full-parameter training with compilation.
|
|
49
|
+
- **5 new tests** in `test_memory_optimization.py` verifying the compile+QLoRA guard and compatibility with GaLore, DeepSpeed, and Unsloth
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
- **All script references updated**: 30+ references across 10 script files, 5 extractors, GUI, and pipeline config updated from hyphenated to subcommand form
|
|
53
|
+
- **Documentation**: `CONTRIBUTING.md` and `EVALUATION.md` updated with new command forms
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
3
57
|
## [0.9.0] — 2026-07-01 — Memory optimization: DeepSpeed, torch.compile, LOMO
|
|
4
58
|
|
|
5
59
|
### Added
|
|
@@ -94,7 +94,7 @@ Buckets live in `data/datasets/buckets/<bucket_name>/` and contain a
|
|
|
94
94
|
uv pip install -e ".[all,dev]"
|
|
95
95
|
|
|
96
96
|
# Run a sanity check on the training pipeline
|
|
97
|
-
attacklm
|
|
97
|
+
attacklm train \
|
|
98
98
|
--dataset data/datasets/combined/combined_*.jsonl \
|
|
99
99
|
--output /tmp/test-output --dry-run
|
|
100
100
|
```
|
|
@@ -64,7 +64,7 @@ For each candidate, run these 4 patterns in order:
|
|
|
64
64
|
|
|
65
65
|
### Step 1: Golden Vectors (Pattern 2) — Fast Regression Gate
|
|
66
66
|
|
|
67
|
-
**
|
|
67
|
+
**Command**: `attacklm eval --golden ...`
|
|
68
68
|
|
|
69
69
|
**Duration**: < 2 minutes
|
|
70
70
|
|
|
@@ -77,7 +77,7 @@ For each candidate, run these 4 patterns in order:
|
|
|
77
77
|
|
|
78
78
|
### Step 2: Reference Scoring (Pattern 1) — Quality Comparison
|
|
79
79
|
|
|
80
|
-
**
|
|
80
|
+
**Command**: `attacklm eval --collect-ref ...` then `attacklm eval --compare ...`
|
|
81
81
|
|
|
82
82
|
**Duration**: ~15 minutes
|
|
83
83
|
|
|
@@ -87,7 +87,7 @@ For each candidate, run these 4 patterns in order:
|
|
|
87
87
|
|
|
88
88
|
### Step 3: Domain Benchmark (Pattern 3) — Capability Evaluation
|
|
89
89
|
|
|
90
|
-
**
|
|
90
|
+
**Command**: `attacklm eval --score ...`
|
|
91
91
|
|
|
92
92
|
**Duration**: ~10 minutes
|
|
93
93
|
|
|
@@ -100,7 +100,7 @@ For each candidate, run these 4 patterns in order:
|
|
|
100
100
|
|
|
101
101
|
### Step 4: Speed Benchmark (Pattern 4) — Performance Comparison
|
|
102
102
|
|
|
103
|
-
**
|
|
103
|
+
**Command**: `attacklm eval --speed ...` (or via `scripts/speed_bench.py`)
|
|
104
104
|
|
|
105
105
|
**Duration**: ~5 minutes
|
|
106
106
|
|
|
@@ -144,13 +144,13 @@ When iterating quickly (e.g., testing hyperparameter changes), run only:
|
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
146
|
# Fast gate: 2 minutes
|
|
147
|
-
|
|
147
|
+
attacklm eval --golden \
|
|
148
148
|
--base-model <model> --adapter <adapter> \
|
|
149
149
|
--golden data/golden/vectors.json \
|
|
150
150
|
--output /tmp/golden_check.json
|
|
151
151
|
|
|
152
152
|
# If PASS, run domain benchmark: 10 minutes
|
|
153
|
-
|
|
153
|
+
attacklm eval --score \
|
|
154
154
|
--base-model <model> --adapter <adapter> \
|
|
155
155
|
--questions data/bench/questions.jsonl \
|
|
156
156
|
--output /tmp/bench_check.json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: attacklm
|
|
3
|
-
Version: 0.9.
|
|
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
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Simpler command form screens for non-training AttackLM commands.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
instead of the old hyphenated commands.
|
|
3
|
+
Uses the unified 'attacklm <subcommand>' CLI format (v0.8.0+).
|
|
5
4
|
"""
|
|
6
5
|
|
|
7
6
|
from __future__ import annotations
|
|
@@ -329,7 +328,7 @@ class EvalFormScreen(_BaseCommandScreen):
|
|
|
329
328
|
|
|
330
329
|
|
|
331
330
|
class PipelineFormScreen(_BaseCommandScreen):
|
|
332
|
-
"""Run the training pipeline using 'attacklm
|
|
331
|
+
"""Run the training pipeline using 'attacklm pipeline'."""
|
|
333
332
|
|
|
334
333
|
def compose(self) -> ComposeResult:
|
|
335
334
|
with Container(id="cmd-container"):
|
|
@@ -345,7 +344,7 @@ class PipelineFormScreen(_BaseCommandScreen):
|
|
|
345
344
|
self.app.pop_screen()
|
|
346
345
|
elif event.button.id == "btn-run":
|
|
347
346
|
values = self._get_values()
|
|
348
|
-
cmd = ["attacklm
|
|
347
|
+
cmd = ["attacklm", "pipeline"]
|
|
349
348
|
if values.get("config"):
|
|
350
349
|
cmd.extend(["--config", values["config"]])
|
|
351
350
|
import asyncio
|
|
@@ -319,7 +319,7 @@ class TrainFormScreen(Screen):
|
|
|
319
319
|
return values
|
|
320
320
|
|
|
321
321
|
def _build_command(self, values: dict) -> list[str]:
|
|
322
|
-
"""Build the attacklm
|
|
322
|
+
"""Build the attacklm train command from form values."""
|
|
323
323
|
cmd = ["attacklm", "train"]
|
|
324
324
|
|
|
325
325
|
# Required
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# AttackLM Training Pipeline — Example Configuration
|
|
2
2
|
#
|
|
3
3
|
# Usage:
|
|
4
|
-
# attacklm
|
|
4
|
+
# attacklm pipeline --config pipeline.example.yaml
|
|
5
5
|
#
|
|
6
6
|
# Each job runs sequentially: train → merge → gguf → install.
|
|
7
7
|
# If a stage fails, the pipeline skips to the next job.
|
|
@@ -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
|
|
@@ -226,45 +227,21 @@ all-rocm = ["attacklm[train-rocm,extract,convert]"]
|
|
|
226
227
|
|
|
227
228
|
# ── Console script entry points ───────────────────────────────────────────────
|
|
228
229
|
#
|
|
229
|
-
# v0.8.0
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
# subcommand. They will be removed in v0.9.0.
|
|
230
|
+
# v0.8.0+ introduced the unified ``attacklm`` command (subcommand-based).
|
|
231
|
+
# The old hyphenated commands (attacklm-train, attacklm-merge, etc.) were
|
|
232
|
+
# deprecated in v0.8.x and removed in v0.9.3.
|
|
233
233
|
|
|
234
234
|
[project.scripts]
|
|
235
|
-
#
|
|
235
|
+
# Unified CLI (the only entry point since v0.9.3)
|
|
236
236
|
attacklm = "attacklm.cli:main"
|
|
237
237
|
|
|
238
|
-
# Deprecated (v0.8.x) — to be removed in v0.9.0
|
|
239
|
-
attacklm-train = "attacklm.cli:main_train"
|
|
240
|
-
attacklm-train-all = "attacklm.cli:main_train_all"
|
|
241
|
-
attacklm-hpo = "attacklm.cli:main_hpo"
|
|
242
|
-
attacklm-infer = "attacklm.cli:main_infer"
|
|
243
|
-
attacklm-merge = "attacklm.cli:main_merge"
|
|
244
|
-
attacklm-gguf = "attacklm.cli:main_gguf"
|
|
245
|
-
attacklm-demo = "attacklm.cli:main_demo"
|
|
246
|
-
attacklm-extract = "attacklm.cli:main_extract"
|
|
247
|
-
attacklm-buckets = "attacklm.cli:main_buckets"
|
|
248
|
-
attacklm-attribute = "attacklm.cli:main_attribute"
|
|
249
|
-
attacklm-clone = "attacklm.cli:main_clone"
|
|
250
|
-
attacklm-init = "attacklm.cli:main_init"
|
|
251
|
-
attacklm-balance = "attacklm.cli:main_balance"
|
|
252
|
-
attacklm-build = "attacklm.cli:main_build"
|
|
253
|
-
attacklm-train-lora = "attacklm.cli:main_train_lora"
|
|
254
|
-
attacklm-eval = "attacklm.cli:main_eval"
|
|
255
|
-
attacklm-collect-ref = "attacklm.cli:main_collect_ref"
|
|
256
|
-
attacklm-score = "attacklm.cli:main_score"
|
|
257
|
-
attacklm-compare = "attacklm.cli:main_compare"
|
|
258
|
-
attacklm-golden = "attacklm.cli:main_golden"
|
|
259
|
-
attacklm-pipeline = "attacklm.scripts.pipeline:main"
|
|
260
|
-
|
|
261
238
|
# ── Hatch build configuration ─────────────────────────────────────────────────
|
|
262
239
|
|
|
263
240
|
[tool.hatch.build.targets.wheel]
|
|
264
241
|
packages = ["src/attacklm"]
|
|
265
242
|
|
|
266
243
|
# Include scripts/ in the wheel so CLI entry points can find them.
|
|
267
|
-
# Without this,
|
|
244
|
+
# Without this, the unified ``attacklm`` command fails with "script not found"
|
|
268
245
|
# because _SCRIPTS_DIR resolves to site-packages/scripts/ which is empty.
|
|
269
246
|
# scripts/ is ~200KB of Python — negligible for the wheel.
|
|
270
247
|
[tool.hatch.build.targets.wheel.force-include]
|
|
@@ -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
|
-
|
|
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(("/", "./", "../", "~/"))
|
|
@@ -67,9 +67,9 @@ Write a balanced JSONL to data/datasets/balanced/:
|
|
|
67
67
|
python scripts/balance_buckets.py --profile 7b-128gb \\
|
|
68
68
|
--output data/datasets/balanced/balanced_7b-128gb.jsonl
|
|
69
69
|
|
|
70
|
-
Then pass that file to attacklm
|
|
70
|
+
Then pass that file to attacklm train:
|
|
71
71
|
|
|
72
|
-
attacklm
|
|
72
|
+
attacklm train --dataset data/datasets/balanced/balanced_7b-128gb.jsonl \\
|
|
73
73
|
--output models/attacklm-7b-128gb \\
|
|
74
74
|
--base-model huihui-ai/Qwen2.5-Coder-7B-Instruct-abliterated
|
|
75
75
|
|
|
@@ -104,7 +104,7 @@ from pathlib import Path
|
|
|
104
104
|
from typing import Iterable
|
|
105
105
|
|
|
106
106
|
# Reuse the existing bucket plumbing.
|
|
107
|
-
# When invoked as a console script (`attacklm
|
|
107
|
+
# When invoked as a console script (`attacklm balance`), the working
|
|
108
108
|
# directory may not be the project root, so we need to make sure
|
|
109
109
|
# sibling scripts in this directory are importable. Same pattern
|
|
110
110
|
# as scripts/train_template.py.
|
|
@@ -1025,7 +1025,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1025
1025
|
print(f"Wrote {len(selected):,} pairs ({size_mb:.1f} MB) to {args.output}")
|
|
1026
1026
|
print(
|
|
1027
1027
|
f"\nNext step:\n"
|
|
1028
|
-
f" attacklm
|
|
1028
|
+
f" attacklm train --dataset {args.output} \\\n"
|
|
1029
1029
|
f" --output models/attacklm-{args.profile.replace('-', '_')}_<timestamp> \\\n"
|
|
1030
1030
|
f" --base-model huihui-ai/Qwen2.5-Coder-3B-Instruct-abliterated"
|
|
1031
1031
|
)
|
|
@@ -7,12 +7,12 @@ manifest at models/built/{name}_{timestamp}/.
|
|
|
7
7
|
|
|
8
8
|
This replaces the 3-command shell pipeline:
|
|
9
9
|
|
|
10
|
-
attacklm-
|
|
11
|
-
&& attacklm-
|
|
10
|
+
attacklm build --merge-only -- --base X --adapter Y --output Z \\
|
|
11
|
+
&& attacklm build --gguf-only -- --input Z --install-lmstudio
|
|
12
12
|
|
|
13
13
|
with a single command:
|
|
14
14
|
|
|
15
|
-
attacklm
|
|
15
|
+
attacklm build --adapter models/attacklm-3b_16g \\
|
|
16
16
|
--base ./uncensored/ \\
|
|
17
17
|
--name attacklm-3b-16g \\
|
|
18
18
|
--install-lmstudio
|
|
@@ -29,24 +29,24 @@ orchestrator is just glue.
|
|
|
29
29
|
Usage:
|
|
30
30
|
|
|
31
31
|
# Full pipeline: merge + GGUF + LM Studio
|
|
32
|
-
attacklm
|
|
32
|
+
attacklm build --adapter models/attacklm-3b_16g \\
|
|
33
33
|
--base ./uncensored/ \\
|
|
34
34
|
--name attacklm-3b-16g
|
|
35
35
|
|
|
36
36
|
# Skip LM Studio install, drop the GGUF in models/gguf/ only
|
|
37
|
-
attacklm
|
|
37
|
+
attacklm build --adapter models/attacklm-3b_16g \\
|
|
38
38
|
--base ./uncensored/ \\
|
|
39
39
|
--name attacklm-3b-16g \\
|
|
40
40
|
--no-install-lmstudio
|
|
41
41
|
|
|
42
42
|
# Register with Ollama too
|
|
43
|
-
attacklm
|
|
43
|
+
attacklm build --adapter models/attacklm-3b_16g \\
|
|
44
44
|
--base ./uncensored/ \\
|
|
45
45
|
--name attacklm-3b-16g \\
|
|
46
46
|
--register-ollama
|
|
47
47
|
|
|
48
48
|
# Use an already-merged model (skip the merge step)
|
|
49
|
-
attacklm
|
|
49
|
+
attacklm build --merged models/merged/attacklm-3b-16g \\
|
|
50
50
|
--name attacklm-3b-16g
|
|
51
51
|
"""
|
|
52
52
|
|
|
@@ -106,7 +106,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
106
106
|
"--adapter",
|
|
107
107
|
type=Path,
|
|
108
108
|
default=None,
|
|
109
|
-
help="Path to the LoRA adapter directory (output of attacklm
|
|
109
|
+
help="Path to the LoRA adapter directory (output of ``attacklm train``).",
|
|
110
110
|
)
|
|
111
111
|
parser.add_argument(
|
|
112
112
|
"--merged",
|
|
@@ -7,13 +7,13 @@ Step 2: llama-quantize → Q4_K_M
|
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
# Convert all merged models:
|
|
10
|
-
attacklm-
|
|
10
|
+
attacklm build --gguf-only
|
|
11
11
|
|
|
12
12
|
# Convert a single model:
|
|
13
|
-
attacklm-
|
|
13
|
+
attacklm build --gguf-only -- --input models/merged/attacklm
|
|
14
14
|
|
|
15
15
|
# Convert and install to LM Studio:
|
|
16
|
-
attacklm-
|
|
16
|
+
attacklm build --gguf-only -- --install-lmstudio
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
import argparse
|
|
@@ -95,7 +95,7 @@ def _is_lora_adapter(model_dir: Path) -> bool:
|
|
|
95
95
|
over from a previous training run), so the old "needs config.json" guard
|
|
96
96
|
let it through and llama.cpp's converter then crashed on the wrong
|
|
97
97
|
architecture. This check is explicit: if adapter_config.json says
|
|
98
|
-
PEFT_TYPE_LORA, refuse with a pointer to attacklm-
|
|
98
|
+
PEFT_TYPE_LORA, refuse with a pointer to ``attacklm build --merge-only``.
|
|
99
99
|
"""
|
|
100
100
|
ac = model_dir / "adapter_config.json"
|
|
101
101
|
if not ac.exists():
|
|
@@ -204,7 +204,7 @@ def main() -> None:
|
|
|
204
204
|
# from a previous run, so the old "needs config.json" guard passed
|
|
205
205
|
# it through and llama.cpp's converter then crashed on the wrong
|
|
206
206
|
# architecture with `Failed to detect model architecture`. Detect
|
|
207
|
-
# PEFT adapters early and point users at attacklm-
|
|
207
|
+
# PEFT adapters early and point users at ``attacklm build --merge-only``.
|
|
208
208
|
if _is_lora_adapter(input_path):
|
|
209
209
|
# Try to read the auto-detected base from state.json (v0.1.6+)
|
|
210
210
|
# or adapter_config.json (v0.1.5 and earlier) so the hint
|
|
@@ -237,11 +237,11 @@ def main() -> None:
|
|
|
237
237
|
f" Need: a directory with config.json + *.safetensors (full merged weights)"
|
|
238
238
|
)
|
|
239
239
|
print(f"\nFix: merge the adapter into the base first, then convert.")
|
|
240
|
-
print(f" attacklm-
|
|
240
|
+
print(f" attacklm build --merge-only -- --adapter {args.input} \\")
|
|
241
241
|
print(f" --base {suggested_base} \\")
|
|
242
242
|
print(f" --output models/merged/{input_path.name}")
|
|
243
243
|
print(
|
|
244
|
-
f" attacklm-
|
|
244
|
+
f" attacklm build --gguf-only -- --input models/merged/{input_path.name}"
|
|
245
245
|
+ (" --install-lmstudio" if args.install_lmstudio else "")
|
|
246
246
|
)
|
|
247
247
|
sys.exit(1)
|
|
@@ -250,7 +250,9 @@ def main() -> None:
|
|
|
250
250
|
):
|
|
251
251
|
print(f"\nERROR: {args.input} is not a valid merged model directory")
|
|
252
252
|
print("Expected a directory containing config.json and *.safetensors")
|
|
253
|
-
print(
|
|
253
|
+
print(
|
|
254
|
+
"If this is a LoRA adapter, run ``attacklm build --merge-only`` first (see above)."
|
|
255
|
+
)
|
|
254
256
|
sys.exit(1)
|
|
255
257
|
models = [input_path]
|
|
256
258
|
else:
|
|
@@ -258,9 +260,9 @@ def main() -> None:
|
|
|
258
260
|
if not models:
|
|
259
261
|
print(f"\nERROR: No merged models found in {MERGED_DIR}")
|
|
260
262
|
print(
|
|
261
|
-
"Run: attacklm-
|
|
263
|
+
"Run: attacklm build --merge-only -- --adapter models/attacklm-single --output models/merged/attacklm"
|
|
262
264
|
)
|
|
263
|
-
print(" or: attacklm-
|
|
265
|
+
print(" or: attacklm build --merge-only -- --merge-all")
|
|
264
266
|
sys.exit(1)
|
|
265
267
|
|
|
266
268
|
GGUF_DIR.mkdir(parents=True, exist_ok=True)
|
|
@@ -278,7 +278,7 @@ def main() -> int:
|
|
|
278
278
|
|
|
279
279
|
if not RULES_DIR.exists():
|
|
280
280
|
print(f"Elastic rules directory not found: {RULES_DIR}", file=sys.stderr)
|
|
281
|
-
print("Run attacklm-
|
|
281
|
+
print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
|
|
282
282
|
return 1
|
|
283
283
|
|
|
284
284
|
toml_files = sorted(RULES_DIR.rglob("*.toml"))
|
|
@@ -331,7 +331,7 @@ def main() -> int:
|
|
|
331
331
|
scenarios = find_scenarios()
|
|
332
332
|
if not scenarios:
|
|
333
333
|
print(f"No Mordor scenarios found in {MORDOR_DIR}", file=sys.stderr)
|
|
334
|
-
print("Run attacklm-
|
|
334
|
+
print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
|
|
335
335
|
return 1
|
|
336
336
|
|
|
337
337
|
if args.max_files > 0:
|
|
@@ -239,7 +239,7 @@ def main() -> int:
|
|
|
239
239
|
|
|
240
240
|
if not RULES_DIR.exists():
|
|
241
241
|
print(f"Sigma rules directory not found: {RULES_DIR}", file=sys.stderr)
|
|
242
|
-
print("Run attacklm-
|
|
242
|
+
print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
|
|
243
243
|
return 1
|
|
244
244
|
|
|
245
245
|
yml_files = sorted(RULES_DIR.rglob("*.yml"))
|
|
@@ -240,7 +240,7 @@ def main() -> int:
|
|
|
240
240
|
print(
|
|
241
241
|
f"Splunk detections directory not found: {DETECTIONS_DIR}", file=sys.stderr
|
|
242
242
|
)
|
|
243
|
-
print("Run attacklm-
|
|
243
|
+
print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
|
|
244
244
|
return 1
|
|
245
245
|
|
|
246
246
|
yml_files = sorted(DETECTIONS_DIR.rglob("*.yml"))
|
|
@@ -230,7 +230,7 @@ def main() -> int:
|
|
|
230
230
|
|
|
231
231
|
if not PLAYBOOKS_DIR.exists():
|
|
232
232
|
print(f"Playbooks directory not found: {PLAYBOOKS_DIR}", file=sys.stderr)
|
|
233
|
-
print("Run attacklm-
|
|
233
|
+
print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
|
|
234
234
|
return 1
|
|
235
235
|
|
|
236
236
|
md_files = sorted(PLAYBOOKS_DIR.rglob("*.md"))
|