Releases of mitreattack-python are fully automated. When commits are pushed (or squash-merged) to main, Python Semantic Release (PSR) analyzes the commit messages and, if warranted, bumps the version, tags the release, creates a GitHub Release, and publishes the package to PyPI — all within the CI pipeline.
-
Commit messages drive versioning. We follow the Conventional Commits specification. PSR parses commit messages to determine the appropriate SemVer bump:
Commit prefix Version bump Example feat:Minor ( 0.X.0)feat: add analytics to excel outputfix:,perf:Patch ( 0.0.X)fix: handle missing data sourcesBREAKING CHANGEin footer, or!after typeMajor ( X.0.0)feat!: drop Python 3.10 supportbuild:,chore:,ci:,docs:,style:,refactor:,test:No release ci: update uv setup action -
PRs are squash-merged. Individual commits within a PR do not need to follow conventional commits — only the PR title matters, as it becomes the squash merge commit message. The
pr-title.ymlworkflow validates PR titles on open. -
On push to
main, the CI pipeline (.github/workflows/ci.yml) runs:- commitlint — validates the squash merge commit message
- lint — ruff check and format verification
- test — pytest with coverage
- release — PSR evaluates commits since the last tag, bumps version, tags, and creates a GitHub Release with build artifacts
- publish — uploads the package to PyPI via trusted publishing (OIDC)
No manual steps are needed. Simply merge a PR to main with a conventional commit title that includes a release-triggering prefix (feat:, fix:, or perf:). PSR will handle the rest.
If you want to validate locally before merging:
# Install dependencies (including dev tools)
just install
# Lint and format
just lint
# Run tests with coverage
just test-cov
# Build the package
just build
# (Optional) Validate wheel contents
uv run check-wheel-contents dist/
# (Optional) Dry run semantic release
just release-dry-runIf releasing for a new ATT&CK version, update mitreattack-python/release_info.py after the corresponding STIX releases are published:
- STIX 2.0 hashes come from mitre/cti
- STIX 2.1 hashes come from mitre-attack/attack-stix-data
Preview the update first:
uv run --extra dev python scripts/update_release_info.py 19.1 --dry-runApply it:
uv run --extra dev python scripts/update_release_info.py 19.1The updater refreshes:
LATEST_VERSIONSTIX20["enterprise"],STIX20["mobile"],STIX20["ics"]STIX21["enterprise"],STIX21["mobile"],STIX21["ics"]
Then verify:
uv run --extra dev ruff check scripts/update_release_info.py tests/test_release_info_updater.py mitreattack/release_info.pyThe GitHub release assets must exist before running the updater, so this step belongs after publishing and tagging mitre/cti and mitre-attack/attack-stix-data.
- All build, release, and publish steps are handled by GitHub Actions — no manual tagging or uploading.
- Version is tracked in
pyproject.toml(project.version) and synced todocs/conf.pyandmitreattack/__init__.pyby PSR. - Documentation builds are managed by ReadTheDocs, which watches the repository.