| name: CI |
| on: |
| pull_request: {} |
| push: |
| branches: |
| - main |
| - '*.*.x' |
| |
| permissions: |
| contents: read |
| |
| concurrency: |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} |
| cancel-in-progress: true |
| |
| env: |
| CARGO_INCREMENTAL: 0 |
| |
| jobs: |
| linux: |
| runs-on: ubuntu-latest |
| strategy: |
| fail-fast: false |
| matrix: |
| PYTHON: |
| - {VERSION: "3.8", NOXSESSION: "flake"} |
| - {VERSION: "3.14", NOXSESSION: "flake"} |
| - {VERSION: "3.14", NOXSESSION: "rust"} |
| - {VERSION: "3.12", NOXSESSION: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1"}} |
| - {VERSION: "3.14t", NOXSESSION: "rust,tests"} |
| - {VERSION: "pypy-3.11", NOXSESSION: "tests-nocoverage"} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "0"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.6.1"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.0.19"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.3.6"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.4.4"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.5.5"}} |
| - {VERSION: "3.14", NOXSESSION: "tests-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1"}} |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", OPENSSL: {TYPE: "libressl", VERSION: "4.1.2"}} |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", OPENSSL: {TYPE: "libressl", VERSION: "4.2.1"}} |
| # Latest commit on the BoringSSL main branch, as of Feb 06, 2026. |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", OPENSSL: {TYPE: "boringssl", VERSION: "514abb73bb80130000b46cf589190c967c6647cd"}} |
| # Latest tag of AWS-LC main branch, as of Jan 23, 2026. |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", OPENSSL: {TYPE: "aws-lc", VERSION: "v1.67.0"}} |
| # Latest commit on the OpenSSL master branch, as of Sep 04, 2025. |
| - {VERSION: "3.14", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "ceb45f64bde3d299c7ef529e5cd5372e4a421366"}} |
| # Builds with various Rust versions. Includes MSRV and next |
| # potential future MSRV. |
| # noclippy due to: https://github.com/PyO3/pyo3/issues/5768 |
| - {VERSION: "3.14", NOXSESSION: "rust-noclippy,tests", RUST: "1.83.0"} |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", RUST: "beta"} |
| - {VERSION: "3.14", NOXSESSION: "rust,tests", RUST: "nightly"} |
| - {VERSION: "3.14", NOXSESSION: "tests-rust-debug"} |
| # Not actually an MSRV, just for coverage on this |
| - {VERSION: "3.14", NOXSESSION: "tests", RUST: "1.87", OPENSSL: {TYPE: "openssl", VERSION: "3.6.1"}} |
| - {VERSION: "3.14", NOXSESSION: "tests", RUST: "1.87", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.6.1"}} |
| timeout-minutes: 15 |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Setup python |
| id: setup-python |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 |
| with: |
| python-version: ${{ matrix.PYTHON.VERSION }} |
| cache: pip |
| cache-dependency-path: ci-constraints-requirements.txt |
| timeout-minutes: 3 |
| - name: Setup rust |
| uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 |
| with: |
| toolchain: ${{ matrix.PYTHON.RUST }} |
| components: rustfmt,clippy |
| if: matrix.PYTHON.RUST |
| |
| - run: rustup component add llvm-tools-preview |
| if: matrix.PYTHON.NOXSESSION != 'flake' && matrix.PYTHON.NOXSESSION != 'docs' |
| - name: Clone test vectors |
| timeout-minutes: 2 |
| uses: ./.github/actions/fetch-vectors |
| if: matrix.PYTHON.NOXSESSION != 'flake' && matrix.PYTHON.NOXSESSION != 'docs' && matrix.PYTHON.NOXSESSION != 'rust' |
| - name: Compute config hash and set config vars |
| run: | |
| DEFAULT_CONFIG_FLAGS="shared no-ssl2 no-ssl3" |
| CONFIG_FLAGS="$DEFAULT_CONFIG_FLAGS $CONFIG_FLAGS" |
| OPENSSL_HASH=$(echo "${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-$CONFIG_FLAGS" | sha1sum | sed 's/ .*$//') |
| echo "CONFIG_FLAGS=${CONFIG_FLAGS}" >> $GITHUB_ENV |
| echo "OPENSSL_HASH=${OPENSSL_HASH}" >> $GITHUB_ENV |
| echo "OSSL_INFO=${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${CONFIG_FLAGS}" >> $GITHUB_ENV |
| echo "OSSL_PATH=${{ github.workspace }}/osslcache/${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${OPENSSL_HASH}" >> $GITHUB_ENV |
| env: |
| CONFIG_FLAGS: ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }} |
| if: matrix.PYTHON.OPENSSL |
| - name: Load OpenSSL cache |
| uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 |
| id: ossl-cache |
| timeout-minutes: 2 |
| with: |
| path: ${{ github.workspace }}/osslcache |
| # When altering the openssl build process you may need to increment |
| # the value on the end of this cache key so that you can prevent it |
| # from fetching the cache and skipping the build step. |
| key: "${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${{ env.OPENSSL_HASH }}-${{ hashFiles('.github/bin/build_openssl.sh') }}-0" |
| if: matrix.PYTHON.OPENSSL |
| - name: Build custom OpenSSL/LibreSSL |
| run: .github/bin/build_openssl.sh |
| env: |
| TYPE: ${{ matrix.PYTHON.OPENSSL.TYPE }} |
| VERSION: ${{ matrix.PYTHON.OPENSSL.VERSION }} |
| if: matrix.PYTHON.OPENSSL && steps.ossl-cache.outputs.cache-hit != 'true' |
| - name: Set CFLAGS/LDFLAGS |
| run: | |
| echo "OPENSSL_DIR=${OSSL_PATH}" >> $GITHUB_ENV |
| echo "CFLAGS=${CFLAGS} -Werror=implicit-function-declaration" >> $GITHUB_ENV |
| echo "RUSTFLAGS=-Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib -Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib64" >> $GITHUB_ENV |
| if: matrix.PYTHON.OPENSSL |
| - run: cargo install bindgen-cli |
| if: matrix.PYTHON.OPENSSL.TYPE == 'boringssl' || matrix.PYTHON.OPENSSL.TYPE == 'aws-lc' |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| with: |
| # We have both the Python version from the matrix and from the |
| # setup-python step because the latter doesn't distinguish |
| # pypy3-3.8 and pypy3-3.9 -- both of them show up as 7.3.11. |
| key: "${{ matrix.PYTHON.VERSION }}-${{ steps.setup-python.outputs.python-version }}-${{ matrix.PYTHON.NOXSESSION }}-${{ env.OPENSSL_HASH }}-0" |
| |
| - run: python -m pip install -c ci-constraints-requirements.txt 'nox[uv]' 'tomli; python_version < "3.11"' |
| - name: Create nox environment |
| run: | |
| nox -v --install-only |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| # Needed until https://github.com/PyO3/pyo3/issues/5093 |
| PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1 |
| - name: Tests |
| run: | |
| nox --no-install -- --color=yes --wycheproof-root=wycheproof --x509-limbo-root=x509-limbo ${{ matrix.PYTHON.NOXARGS }} |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| COLUMNS: 80 |
| CRYPTOGRAPHY_OPENSSL_NO_LEGACY: ${{ matrix.PYTHON.OPENSSL.NO_LEGACY }} |
| |
| - uses: ./.github/actions/upload-coverage |
| |
| distros: |
| runs-on: ${{ matrix.IMAGE.RUNNER }} |
| container: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} |
| strategy: |
| fail-fast: false |
| matrix: |
| IMAGE: |
| - {IMAGE: "bookworm", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "trixie", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "sid", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "ubuntu-jammy", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "ubuntu-noble", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "ubuntu-rolling", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "fedora", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "centos-stream9", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "centos-stream9-fips", NOXSESSION: "tests", RUNNER: "ubuntu-latest", FIPS: true} |
| - {IMAGE: "centos-stream10", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "centos-stream10-fips", NOXSESSION: "tests", RUNNER: "ubuntu-latest", FIPS: true} |
| |
| - {IMAGE: "ubuntu-rolling:aarch64", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-arm"} |
| |
| - {IMAGE: "ubuntu-rolling:armv7l", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-arm"} |
| |
| # Disable coverage until coverage.py has a wheel with C ext for ppc64le |
| - {IMAGE: "ubuntu-rolling:ppc64le", NOXSESSION: "tests-nocoverage", RUNNER: "ubuntu-24.04-ppc64le"} |
| timeout-minutes: 15 |
| env: |
| RUSTUP_HOME: /root/.rustup |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| with: |
| key: ${{ matrix.IMAGE.IMAGE }} |
| - name: Clone test vectors |
| timeout-minutes: 2 |
| uses: ./.github/actions/fetch-vectors |
| # When run in a docker container the home directory doesn't have the same owner as the |
| # apparent user so pip refuses to create a cache dir |
| - name: create pip cache dir |
| run: mkdir -p "${HOME}/.cache/pip" |
| - run: | |
| echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV |
| if: matrix.IMAGE.FIPS |
| - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox[uv]' 'tomli; python_version < "3.11"' |
| - run: '/venv/bin/nox -v --install-only' |
| env: |
| # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream |
| OPENSSL_ENABLE_SHA1_SIGNATURES: 1 |
| NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} |
| - run: '/venv/bin/nox --no-install -- --color=yes --wycheproof-root="wycheproof" --x509-limbo-root="x509-limbo"' |
| env: |
| COLUMNS: 80 |
| # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream |
| OPENSSL_ENABLE_SHA1_SIGNATURES: 1 |
| NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} |
| - uses: ./.github/actions/upload-coverage |
| |
| alpine: |
| runs-on: ${{ matrix.IMAGE.RUNNER }} |
| container: |
| image: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} |
| volumes: |
| - /staticnodehost:/staticnodecontainer:rw,rshared |
| - /staticnodehost/20:/__e/node20:ro,rshared |
| - /staticnodehost/24:/__e/node24:ro,rshared |
| strategy: |
| fail-fast: false |
| matrix: |
| IMAGE: |
| - {IMAGE: "alpine", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} |
| - {IMAGE: "alpine:aarch64", NOXSESSION: "tests", RUNNER: "ubuntu-24.04-arm"} |
| timeout-minutes: 15 |
| env: |
| RUSTUP_HOME: /root/.rustup |
| steps: |
| - name: Ridiculous-er workaround for static node20 |
| run: | |
| cp -R /staticnode/* /staticnodecontainer/ |
| - name: Ridiculous alpine workaround for actions support on arm64 |
| run: | |
| # This modifies /etc/os-release so the JS actions |
| # from GH can't detect that it's on alpine:aarch64. It will |
| # then use a glibc nodejs, which works fine when gcompat |
| # is installed in the container (which it is) |
| sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release |
| if: matrix.IMAGE.IMAGE == 'alpine:aarch64' |
| |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| with: |
| key: ${{ matrix.IMAGE.IMAGE }} |
| - name: Clone test vectors |
| timeout-minutes: 2 |
| uses: ./.github/actions/fetch-vectors |
| # When run in a docker container the home directory doesn't have the same owner as the |
| # apparent user so pip refuses to create a cache dir |
| - name: create pip cache dir |
| run: mkdir -p "${HOME}/.cache/pip" |
| - run: | |
| echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV |
| if: matrix.IMAGE.FIPS |
| - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox[uv]' 'tomli; python_version < "3.11"' |
| - run: '/venv/bin/nox -v --install-only' |
| env: |
| # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream |
| OPENSSL_ENABLE_SHA1_SIGNATURES: 1 |
| NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} |
| - run: '/venv/bin/nox --no-install -- --color=yes --wycheproof-root="wycheproof" --x509-limbo-root="x509-limbo"' |
| env: |
| COLUMNS: 80 |
| # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream |
| OPENSSL_ENABLE_SHA1_SIGNATURES: 1 |
| NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} |
| - uses: ./.github/actions/upload-coverage |
| |
| macos: |
| runs-on: ${{ matrix.RUNNER.OS }} |
| strategy: |
| fail-fast: false |
| matrix: |
| RUNNER: |
| - {OS: 'macos-15-intel', ARCH: 'x86_64'} |
| - {OS: 'macos-15', ARCH: 'arm64'} |
| PYTHON: |
| - {VERSION: "3.8", NOXSESSION: "tests"} |
| - {VERSION: "3.14", NOXSESSION: "tests"} |
| - {VERSION: "3.14t", NOXSESSION: "tests"} |
| exclude: |
| # We only test latest Python on arm64. py38 won't work since there's no universal2 binary |
| - PYTHON: {VERSION: "3.8", NOXSESSION: "tests"} |
| RUNNER: {OS: 'macos-15', ARCH: 'arm64'} |
| timeout-minutes: 15 |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| with: |
| key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.PYTHON.VERSION }} |
| |
| - name: Setup python |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 |
| with: |
| python-version: ${{ matrix.PYTHON.VERSION }} |
| cache: pip |
| cache-dependency-path: ci-constraints-requirements.txt |
| timeout-minutes: 3 |
| - run: rustup component add llvm-tools-preview |
| |
| - run: python -m pip install -c ci-constraints-requirements.txt 'nox[uv]' 'tomli; python_version < "3.11"' |
| |
| - name: Clone test vectors |
| timeout-minutes: 2 |
| uses: ./.github/actions/fetch-vectors |
| |
| - uses: dawidd6/action-download-artifact@0bd50d53a6d7fb5cb921e607957e9cc12b4ce392 # v12 |
| with: |
| repo: pyca/infra |
| workflow: build-macos-openssl.yml |
| branch: main |
| workflow_conclusion: success |
| name: openssl-macos-universal2 |
| path: "../openssl-macos-universal2/" |
| github_token: ${{ secrets.GITHUB_TOKEN }} |
| - name: Build nox environment |
| run: | |
| OPENSSL_DIR=$(readlink -f ../openssl-macos-universal2/) \ |
| OPENSSL_STATIC=1 \ |
| CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function" \ |
| nox -v --install-only |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| MACOSX_DEPLOYMENT_TARGET: "10.13" |
| - name: Tests |
| run: nox --no-install -- --color=yes --wycheproof-root=wycheproof --x509-limbo-root=x509-limbo |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| COLUMNS: 80 |
| |
| - uses: ./.github/actions/upload-coverage |
| |
| windows: |
| runs-on: ${{ matrix.WINDOWS.RUNNER }} |
| strategy: |
| fail-fast: false |
| matrix: |
| WINDOWS: |
| - {ARCH: 'x86', WINDOWS: 'win32', RUNNER: 'windows-latest'} |
| - {ARCH: 'x64', WINDOWS: 'win64', RUNNER: 'windows-latest'} |
| PYTHON: |
| - {VERSION: "3.8", NOXSESSION: "tests-nocoverage"} |
| - {VERSION: "3.14", NOXSESSION: "tests"} |
| - {VERSION: "3.14t", NOXSESSION: "tests"} |
| timeout-minutes: 15 |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Setup python |
| id: setup-python |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 |
| with: |
| python-version: ${{ matrix.PYTHON.VERSION }} |
| architecture: ${{ matrix.WINDOWS.ARCH }} |
| cache: pip |
| cache-dependency-path: ci-constraints-requirements.txt |
| timeout-minutes: 3 |
| - run: rustup component add llvm-tools-preview |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| with: |
| key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} |
| - run: python -m pip install -c ci-constraints-requirements.txt "nox[uv]" "tomli; python_version < '3.11'" |
| |
| - uses: dawidd6/action-download-artifact@0bd50d53a6d7fb5cb921e607957e9cc12b4ce392 # v12 |
| with: |
| repo: pyca/infra |
| workflow: build-windows-openssl.yml |
| branch: main |
| workflow_conclusion: success |
| name: "openssl-${{ matrix.WINDOWS.WINDOWS }}" |
| path: "C:/openssl-${{ matrix.WINDOWS.WINDOWS }}/" |
| github_token: ${{ secrets.GITHUB_TOKEN }} |
| - name: Configure |
| run: | |
| echo "OPENSSL_DIR=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}" >> $GITHUB_ENV |
| shell: bash |
| |
| - name: Clone test vectors |
| timeout-minutes: 2 |
| uses: ./.github/actions/fetch-vectors |
| |
| - name: Build nox environment |
| run: nox -v --install-only |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| - name: Tests |
| run: nox --no-install -- --color=yes --wycheproof-root=wycheproof --x509-limbo-root=x509-limbo |
| env: |
| NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} |
| COLUMNS: 80 |
| |
| - uses: ./.github/actions/upload-coverage |
| |
| linux-downstream: |
| runs-on: ubuntu-latest |
| strategy: |
| fail-fast: false |
| matrix: |
| include: |
| - DOWNSTREAM: paramiko |
| REPO: paramiko/paramiko |
| # Latest commit on the paramiko main branch, as of Oct 20, 2025. |
| REF: 8697158113a3eab25ed1d1d541ebe2cad10169a7 |
| PATH: paramiko |
| - DOWNSTREAM: pyopenssl |
| REPO: pyca/pyopenssl |
| # Latest commit on the pyopenssl main branch, as of Jan 23, 2026. |
| REF: bcac7d2545320f4042fc7f8be384fba978381359 |
| PATH: pyopenssl |
| - DOWNSTREAM: pyopenssl-release |
| REPO: pyca/pyopenssl |
| # Latest release tag of pyopenssl-release, as of Sep 18, 2025. |
| REF: 25.3.0 |
| PATH: pyopenssl |
| - DOWNSTREAM: twisted |
| REPO: twisted/twisted |
| # Latest commit on the twisted trunk branch, as of Dec 12, 2025. |
| REF: d1da93654b14ba6870ce77ce77daf584451c2e8f |
| PATH: twisted |
| - DOWNSTREAM: aws-encryption-sdk-python |
| REPO: awslabs/aws-encryption-sdk-python |
| # Latest commit on the aws-encryption-sdk-python master branch, as of Jan 30, 2026. |
| REF: 20ec402e08da8f8277601b57912a6ba9e529263e |
| PATH: aws-encryption-sdk-python |
| - DOWNSTREAM: aws-dynamodb-encryption-python |
| REPO: awslabs/aws-dynamodb-encryption-python |
| # Latest commit on the aws-dynamodb-encryption-python master branch, as of Jan 29, 2026. |
| REF: ff8ceec703f6e85cac3a3d658f3de06226cabdf4 |
| PATH: aws-dynamodb-encryption-python |
| - DOWNSTREAM: certbot |
| REPO: certbot/certbot |
| # Latest commit on the certbot main branch, as of Feb 06, 2026. |
| REF: 420f526062b70b7c8436837cffa9490cd5e42533 |
| PATH: certbot |
| - DOWNSTREAM: certbot-josepy |
| REPO: certbot/josepy |
| # Latest commit on the certbot-josepy main branch, as of Feb 03, 2026. |
| REF: ec72fb737e7883a617eab19ee88f1954c611995f |
| PATH: josepy |
| - DOWNSTREAM: mitmproxy |
| REPO: mitmproxy/mitmproxy |
| # Latest commit on the mitmproxy main branch, as of Feb 02, 2026. |
| REF: c4f81b711898ab25a919c3af0e79f2fe50e492c3 |
| PATH: mitmproxy |
| - DOWNSTREAM: scapy |
| REPO: secdev/scapy |
| # Latest commit on the scapy master branch, as of Jan 12, 2026. |
| REF: f303033267c828a846b5ee645d5fc2a43a927709 |
| PATH: scapy |
| - DOWNSTREAM: sigstore-python |
| REPO: sigstore/sigstore-python |
| # Latest commit on the sigstore-python main branch, as of Feb 06, 2026. |
| REF: 6332a5dd276bf3a8b43f149b51562875746b6f0a |
| PATH: sigstore-python |
| name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" |
| timeout-minutes: 15 |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Checkout downstream repository |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| repository: ${{ matrix.REPO }} |
| ref: ${{ matrix.REF }} |
| path: ${{ matrix.PATH }} |
| persist-credentials: false |
| - name: Cache rust and pip |
| uses: ./.github/actions/cache |
| timeout-minutes: 2 |
| - name: Setup python |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 |
| with: |
| python-version: '3.12' |
| cache: pip |
| cache-dependency-path: ci-constraints-requirements.txt |
| timeout-minutes: 3 |
| |
| - run: python -m pip install -c ci-constraints-requirements.txt 'uv' |
| - run: uv venv |
| - run: source .venv/bin/activate && ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install |
| - run: uv pip install . |
| # cryptography main has a version of "(X+1).0.0.dev1" where X is the |
| # most recently released major version. A package used by a downstream |
| # may depend on cryptography <=X. If you use entrypoints stuff, this can |
| # lead to runtime errors due to version incompatibilities. Rename the |
| # dist-info directory to pretend to be an older version to "solve" this. |
| - run: | |
| .venv/bin/python <<EOF |
| import json |
| import importlib.metadata |
| import shutil |
| import urllib.request |
| |
| d = importlib.metadata.distribution("cryptography") |
| with urllib.request.urlopen("https://pypi.org/pypi/cryptography/json") as r: |
| latest_version = json.load(r)["info"]["version"] |
| new_path = d.locate_file(f"cryptography-{latest_version}.dist-info") |
| shutil.move(d.locate_file(f"cryptography-{d.version}.dist-info"), new_path) |
| |
| EOF |
| - run: source .venv/bin/activate && ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run |
| |
| all-green: |
| # https://github.community/t/is-it-possible-to-require-all-github-actions-tasks-to-pass-without-enumerating-them/117957/4?u=graingert |
| runs-on: ubuntu-latest |
| needs: [linux, alpine, distros, macos, windows, linux-downstream] |
| if: ${{ always() }} |
| timeout-minutes: 3 |
| steps: |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| timeout-minutes: 3 |
| with: |
| persist-credentials: false |
| - name: Decide whether the needed jobs succeeded or failed |
| uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 |
| with: |
| jobs: ${{ toJSON(needs) }} |
| - name: Setup python |
| if: ${{ always() }} |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 |
| with: |
| python-version: '3.14' |
| cache: pip |
| cache-dependency-path: ci-constraints-requirements.txt |
| timeout-minutes: 3 |
| - run: pip install -c ci-constraints-requirements.txt coverage[toml] |
| if: ${{ always() }} |
| - name: Download coverage data |
| if: ${{ always() }} |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 |
| with: |
| pattern: coverage-data-* |
| merge-multiple: true |
| path: coverage-data/ |
| - name: Combine coverage and fail if it's <100%. |
| if: ${{ always() }} |
| id: combinecoverage |
| run: | |
| set +e |
| echo "## Coverage" >> $GITHUB_STEP_SUMMARY |
| python -u .github/bin/merge_rust_coverage.py coverage-data/ | tee COV_REPORT |
| COV_EXIT_CODE=${PIPESTATUS[0]} |
| if [ $COV_EXIT_CODE -ne 0 ]; then |
| echo "🚨 Coverage failed. Under 100" | tee -a $GITHUB_STEP_SUMMARY |
| fi |
| echo '```' >> $GITHUB_STEP_SUMMARY |
| cat COV_REPORT >> $GITHUB_STEP_SUMMARY |
| echo '```' >> $GITHUB_STEP_SUMMARY |
| exit $COV_EXIT_CODE |
| - name: Upload HTML report. |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 |
| with: |
| name: _html-coverage-report |
| path: htmlcov |
| if-no-files-found: ignore |
| if: ${{ failure() && steps.combinecoverage.outcome == 'failure' }} |