Skip to content

Release Process

github-actions[bot] edited this page Nov 2, 2026 · 4 revisions

Release Process

Releases are automated by release-please. Nobody edits a version number or the changelog by hand, and nobody pushes tags.

Versioning

  • Semantic Versioning, with tags vX.Y.Z. Before 1.0, a breaking change bumps the minor version and a feature bumps the patch.
  • The version is derived from Conventional Commit messages on main. PRs are squash-merged, so it's the PR title that counts:
PR title Bump CHANGELOG section
feat: ... minor (patch before 1.0) ✨ Features
fix: ... patch 🐛 Bug Fixes
perf: ... patch ⚡ Performance
feat!: ..., or BREAKING CHANGE: in the body major (minor before 1.0) ⚠ Breaking changes
refactor:, docs:, revert: patch their own sections
build:, ci:, test:, chore: none on their own hidden
  • The PR title check enforces the format. A wrong type means a wrong version, so reviewers check it.
  • The version lives in pyproject.toml and .release-please-manifest.json; mitm_proxy.__version__ reads the installed metadata. CI fails if the two files disagree.

How a release happens

  1. Merge PRs to main as usual.
  2. On every push to main, release-please updates a single open Release PR (chore: release X.Y.Z). It bumps the version, writes the new CHANGELOG.md entry from the commit titles, and moves the image tag in contrib/. A follow-up job refreshes uv.lock on the same PR.
  3. Review the Release PR like any other: is the version right, and does the changelog read well? Fix a wording problem by editing the PR description under the version heading (release-please keeps that), or fix the original commit's PR title and rerun the Release workflow.
  4. The Release PR runs the wiki check in strict mode: any leftover <!-- guidance --> skeleton text in docs/wiki/ blocks the release.
  5. Merge it. release-please tags vX.Y.Z and publishes the GitHub Release with the changelog entry, and the release image is built and pushed: ghcr.io/metalayerlab/mitm-proxy:X.Y.Z, :X.Y, :X (from 1.0), and :latest.

Other images: :edge and :main-<sha> are built from every push to main, and :<branch> and :<branch>-<sha> from dev/** and feat/** branches. Branch images are deleted after 7 days.

Pre-releases and hotfixes

  • Pre-release: run the Release workflow after adding "prerelease": true and "prerelease-type": "rc" for the package in release-please-config.json, in a PR. Remove them again for the final release.
  • First release is 0.1.0, and feat: stays a patch bump until 1.0. Leave 0.x with the force below.
  • Force a version: a commit with Release-As: 1.0.0 in its body (an empty chore: commit is fine) makes the next Release PR use that version.
  • Hotfix: a fix: PR to main and a release as usual. There are no long-lived release branches.
  • Rebuild an old image: run the Docker image workflow manually with tag: vX.Y.Z. It builds that tag with today's Docker files and never moves :latest, unless you tick it.

Dependencies pinned to a git tag

Dependabot can't update a dependency pinned to a GitHub tag, such as "NAME @ git+https://github.com/OWNER/REPO@v1.2.3": it looks the bare name up on PyPI instead. The weekly Tag check workflow (python-tag-check.yml, Monday 05:00 UTC) does it: for each such pin, in [project] dependencies, optional dependencies, dependency groups or a [tool.uv.sources] tag =, it finds the repository's highest vX.Y.Z tag and opens one PR, chore(deps): bump NAME from vOLD to vNEW on tag-check/NAME, with the pin's line rewritten and uv lock --upgrade-package NAME. A major bump, or a minor one below 1.0, adds "(breaking)" to the title. Branch, commit and pre-release pins are listed in the job summary and never bumped. scripts/tag-check.py --dry-run shows what it would do.

  • Treat a Dependabot PR for such a name as suspect: it proposes whatever PyPI has under that name, which may be someone else's package. Close it.
  • interpose (the settings engine config.py uses) is one: its bumps come from the tag check, and dependabot.yml ignores the name.
  • Without the release App, CI doesn't run on these PRs: close and reopen one to run it. A private dependency needs the App, installed on that repository.

Setup note for maintainers: Release PRs opened with the default GITHUB_TOKEN don't trigger CI. The organisation's release GitHub App (RELEASE_APP_CLIENT_ID variable, RELEASE_APP_PRIVATE_KEY secret) fixes that; see template-python's README.

mitm-proxy

GitHub • Releases


📚 Getting Started

📖 Core Concepts

🔧 Configuration

🔒 Security

🆘 Help & Support

🧑‍💻 For Developers


🔑 Key Features

  • 🔍 Intercept only the hosts you list; tunnel the rest untouched
  • 🔀 HTTP/1.1 and HTTP/2 on both sides, bridged
  • 🧩 Python middleware: inspect, rewrite, answer or deny
  • 🔐 Its own root CA; origins always verified
  • 📈 Prometheus metrics and a read-only status API

🔗 Quick Links

Clone this wiki locally