name: CI on: push: branches: - '**' - '!dependabot/**' - '!*-patch-*' pull_request: merge_group: workflow_dispatch: permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e lint filename-matching: uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e filename_matching mypy: uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e mypy individual-coverage: uses: mhils/workflows/.github/workflows/python-tox.yml@v10 with: cmd: tox -e individual_coverage test: strategy: fail-fast: false matrix: include: - os: ubuntu-latest py: "3.13-dev" - os: windows-latest py: "3.13-dev" - os: macos-latest py: "3.13-dev" - os: ubuntu-latest py: "3.12" - os: ubuntu-latest py: "3.11" - os: ubuntu-latest py: "3.10" runs-on: ${{ matrix.os }} steps: - run: printenv - uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.py }} - run: pip install tox - run: tox -e py if: matrix.os != 'ubuntu-latest' - name: Run tox -e py (without internet) run: | # install dependencies (requires internet connectivity) tox -e py --notest # run tests with loopback only. We need to sudo for unshare, which means we need an absolute path for tox. sudo unshare --net -- sh -c "ip link set lo up; $(which tox) -e py" if: matrix.os == 'ubuntu-latest' - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.xml test-old-dependencies: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: pip install tox-uv - run: tox -e old-dependencies build: strategy: fail-fast: false matrix: include: - image: macos-14 platform: macos-arm64 - image: macos-12 platform: macos-x86_64 - image: windows-2019 platform: windows - image: ubuntu-20.04 # Oldest available version so we get oldest glibc possible. platform: linux runs-on: ${{ matrix.image }} steps: - uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: pip install .[dev] # pyinstaller 5.9 does not like pyproject.toml + editable installs. - if: startsWith(matrix.platform, 'macos') && github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/')) id: keychain uses: apple-actions/import-codesign-certs@63fff01cd422d4b7b855d40ca1e9d34d2de9427d with: keychain: ${{ runner.temp }}/temp p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - if: startsWith(matrix.platform, 'macos') && github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/')) run: | python -u release/build.py macos-app \ --keychain "${{ runner.temp }}/temp.keychain" \ --team-id "S8XHQB96PW" \ --apple-id "${{ secrets.APPLE_ID }}" \ --password "${{ secrets.APPLE_APP_PASSWORD }}" # Linux - if: matrix.platform == 'linux' run: python -u release/build.py standalone-binaries wheel # Windows - if: matrix.platform == 'windows' run: python -u release/build.py standalone-binaries - uses: actions/upload-artifact@v4 with: name: binaries.${{ matrix.platform }} path: release/dist build-wheel: uses: mhils/workflows/.github/workflows/python-build.yml@v10 with: python-version-file: .github/python-version.txt artifact: binaries.wheel build-windows-installer: runs-on: windows-latest if: github.repository == 'mitmproxy/mitmproxy' && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/') ) steps: - uses: actions/checkout@v4 with: persist-credentials: false fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: pip install .[dev] # pyinstaller 5.9 does not like pyproject.toml + editable installs. - run: python -u release/build.py installbuilder-installer msix-installer env: CI_BUILD_KEY: ${{ secrets.CI_BUILD_KEY }} - uses: actions/upload-artifact@v4 with: name: binaries.windows-installer path: release/dist test-web-ui: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-node@v4 with: node-version-file: .github/node-version.txt - name: Cache Node.js modules uses: actions/cache@v4 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.OS }}-node- ${{ runner.OS }}- - working-directory: ./web run: npm ci - working-directory: ./web run: npm test - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./web/coverage/coverage-final.json test-docker: runs-on: ubuntu-latest needs: build-wheel steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/download-artifact@v4 with: name: binaries.wheel path: release/docker - name: Build container run: docker build --tag localtesting release/docker - name: Test container run: docker run --rm -v $PWD/release:/release localtesting mitmdump -s /release/selftest.py docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: | wget -q https://github.com/gohugoio/hugo/releases/download/v0.92.1/hugo_extended_0.92.1_Linux-64bit.deb echo "a9440adfd3ecce40089def287dee4e42ffae252ba08c77d1ac575b880a079ce6 hugo_extended_0.92.1_Linux-64bit.deb" | sha256sum -c sudo dpkg -i hugo*.deb - run: pip install -e .[dev] - run: ./docs/build.py - uses: actions/upload-artifact@v4 with: name: docs path: docs/public # For releases, also build the archive version of the docs. - if: startsWith(github.ref, 'refs/tags/') run: ./docs/build.py env: DOCS_ARCHIVE: true - if: startsWith(github.ref, 'refs/tags/') uses: actions/upload-artifact@v4 with: name: docs-archive path: docs/public check: if: always() needs: - lint - filename-matching - mypy - individual-coverage - test - test-docker - test-old-dependencies - test-web-ui - build - build-wheel - build-windows-installer - docs uses: mhils/workflows/.github/workflows/alls-green.yml@v10 with: jobs: ${{ toJSON(needs) }} allowed-skips: build-windows-installer # Separate from everything else because slow. deploy-docker: if: github.repository == 'mitmproxy/mitmproxy' && ( github.ref == 'refs/heads/main' || github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/') ) permissions: id-token: write attestations: write packages: write environment: deploy-docker needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/download-artifact@v4 with: name: binaries.wheel path: release/docker - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v1.6.0 - name: Login to Docker Hub uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: mitmbot password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 env: DOCKER_METADATA_ANNOTATIONS_LEVELS: index with: images: | mitmproxy/mitmproxy ghcr.io/mitmproxy/mitmproxy tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=raw,value=dev,enable=${{ github.ref == 'refs/heads/main' }} type=raw,value=citest,enable=${{ github.ref == 'refs/heads/citest' }} - name: Build and push id: push uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: context: release/docker platforms: linux/amd64,linux/arm64 push: true provenance: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} annotations: ${{ steps.meta.outputs.annotations }} - uses: actions/attest-build-provenance@v1 with: subject-name: ghcr.io/${{ github.repository }} subject-digest: ${{ steps.push.outputs.digest }} deploy: # This action has access to our AWS keys, so we are extra careful here. # In particular, we don't blindly `pip install` anything to minimize the risk of supply chain attacks. if: github.repository == 'mitmproxy/mitmproxy' && (startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/tags/')) environment: ${{ (github.ref == 'refs/heads/citest' || startsWith(github.ref, 'refs/tags/')) && 'deploy-release' || 'deploy-snapshot' }} needs: check runs-on: ubuntu-latest permissions: id-token: write attestations: write env: # PyPI and MSFT keys are only available for the deploy-release environment # The AWS access key for snapshots is scoped to branches/* as well. TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: us-west-2 MSFT_APP_ID: 9NWNDLQMNZD7 MSFT_TENANT_ID: ${{ secrets.MSFT_TENANT_ID }} MSFT_CLIENT_ID: ${{ secrets.MSFT_CLIENT_ID }} MSFT_CLIENT_SECRET: ${{ secrets.MSFT_CLIENT_SECRET }} R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }} R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} steps: - uses: actions/checkout@v4 with: persist-credentials: false - uses: actions/setup-python@v5 with: python-version-file: .github/python-version.txt - run: sudo apt-get update - run: sudo apt-get install -y awscli - if: startsWith(github.ref, 'refs/tags/') run: sudo apt-get install -y twine - uses: actions/download-artifact@v4 with: name: docs path: docs/public - if: startsWith(github.ref, 'refs/tags/') uses: actions/download-artifact@v4 with: name: docs-archive path: docs/archive - uses: actions/download-artifact@v4 with: pattern: binaries.* merge-multiple: true path: release/dist - id: provenance uses: actions/attest-build-provenance@v1 with: subject-path: 'release/dist/*' - run: | REF=${{ github.ref_name }} mv ${{ steps.provenance.outputs.bundle-path }} release/dist/mitmproxy-${REF#v}.sigstore - run: ls docs/public - run: ls release/dist - run: ./release/deploy.py - name: Deploy to Microsoft Store (test flight) if: github.ref == 'refs/heads/citest' run: ./release/deploy-microsoft-store.py release/dist/*.msix env: MSFT_APP_FLIGHT: 174ca570-8cae-4444-9858-c07293f1f13a - name: Deploy to Microsoft Store if: startsWith(github.ref, 'refs/tags/') run: ./release/deploy-microsoft-store.py release/dist/*.msix