CI workflow (pyca/pyopenssl)
The CI workflow from pyca/pyopenssl, explained and optimized by Latchkey.
CI health: D - needs work
Point runs-on at Latchkey and get caching, run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the CI workflow from the pyca/pyopenssl repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: CI
on:
pull_request: {}
push: {}
permissions:
contents: read
jobs:
linux:
runs-on: ${{ matrix.PYTHON.OS || 'ubuntu-latest' }}
strategy:
fail-fast: false
matrix:
PYTHON:
# Base builds
- {VERSION: "3.9", NOXSESSION: "tests"}
- {VERSION: "3.10", NOXSESSION: "tests"}
- {VERSION: "3.11", NOXSESSION: "tests"}
- {VERSION: "3.12", NOXSESSION: "tests"}
- {VERSION: "3.13", NOXSESSION: "tests"}
- {VERSION: "3.14", NOXSESSION: "tests"}
- {VERSION: "3.14t", NOXSESSION: "tests"}
- {VERSION: "pypy-3.11", NOXSESSION: "tests"}
- {VERSION: "3.11", NOXSESSION: "tests-wheel", OS: "windows-latest"}
- {VERSION: "3.14t", NOXSESSION: "tests-wheel", OS: "windows-latest"}
# -cryptography-main
- {VERSION: "3.9", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.10", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.11", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.12", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.13", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.14", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "3.14t", NOXSESSION: "tests-cryptography-main"}
- {VERSION: "pypy-3.11", NOXSESSION: "tests-cryptography-main"}
# -cryptography-minimum
- {VERSION: "3.9", NOXSESSION: "tests-cryptography-minimum"}
- {VERSION: "3.10", NOXSESSION: "tests-cryptography-minimum"}
- {VERSION: "3.11", NOXSESSION: "tests-cryptography-minimum"}
- {VERSION: "3.12", NOXSESSION: "tests-cryptography-minimum"}
- {VERSION: "3.13", NOXSESSION: "tests-cryptography-minimum"}
- {VERSION: "pypy-3.11", NOXSESSION: "tests-cryptography-minimum"}
# Cryptography wheels
- {VERSION: "3.9", NOXSESSION: "tests-cryptography-minimum-wheel"}
- {VERSION: "3.9", NOXSESSION: "tests-wheel"}
# Random order
- {VERSION: "3.9", NOXSESSION: "tests-random-order"}
# aws-lc
- {VERSION: "3.14", NOXSESSION: "tests-cryptography-main", OPENSSL: {TYPE: "aws-lc", VERSION: "v1.73.0"}}
# Meta
- {VERSION: "3.9", NOXSESSION: "check-manifest"}
- {VERSION: "3.11", NOXSESSION: "lint"}
- {VERSION: "3.13", NOXSESSION: "mypy"}
- {VERSION: "3.9", NOXSESSION: "docs"}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Setup python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.PYTHON.VERSION }}
- name: Cache custom OpenSSL
if: matrix.PYTHON.OPENSSL
id: ossl-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/ossl
key: ossl-${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}
- name: Build custom OpenSSL
if: matrix.PYTHON.OPENSSL && steps.ossl-cache.outputs.cache-hit != 'true'
run: |
git clone --depth 1 --branch ${{ matrix.PYTHON.OPENSSL.VERSION }} https://github.com/aws/aws-lc.git
cmake -GNinja -B aws-lc/build -S aws-lc -DCMAKE_INSTALL_PREFIX="${HOME}/ossl" -DBUILD_TESTING=OFF
ninja -C aws-lc/build install
rm -rf aws-lc/
- name: Set up custom OpenSSL env
if: matrix.PYTHON.OPENSSL
run: |
cargo install bindgen-cli
echo "OPENSSL_DIR=${HOME}/ossl" >> $GITHUB_ENV
- run: python -m pip install nox
- run: nox
env:
NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }}
- uses: ./.github/actions/upload-coverage
linux-docker:
runs-on: ubuntu-latest
container: ghcr.io/pyca/cryptography-runner-${{ matrix.TEST.CONTAINER }}
strategy:
fail-fast: false
matrix:
TEST:
# cryptography-main used since there's no wheel
- {CONTAINER: "ubuntu-rolling", NOXSESSION: "tests-cryptography-main"}
name: "${{ matrix.TEST.NOXSESSION }} on ${{ matrix.TEST.CONTAINER }}"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- run: /venv/bin/pip install nox
- run: /venv/bin/nox
env:
RUSTUP_HOME: /root/.rustup
NOXSESSION: ${{ matrix.TEST.NOXSESSION }}
- uses: ./.github/actions/upload-coverage
linux-downstream:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
DOWNSTREAM:
- twisted
- certbot
- certbot-josepy
PYTHON:
- 3.12
name: "Downstream tests for ${{ matrix.DOWNSTREAM }}"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Setup python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.PYTHON }}
- run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install
- run: pip install .
- run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run
all-green:
runs-on: ubuntu-latest
needs: [linux, linux-docker, linux-downstream]
if: ${{ always() }}
timeout-minutes: 3
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
timeout-minutes: 3
with:
persist-credentials: false
- name: Setup python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: '3.12'
timeout-minutes: 3
- run: pip install coverage[toml]
- name: Download coverage data
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: coverage-data-*
merge-multiple: true
- name: Combine coverage and fail if it's too low
id: combinecoverage
run: |
set +e
python -m coverage combine
echo "## Python Coverage" >> $GITHUB_STEP_SUMMARY
python -m coverage report -m --fail-under=98 > COV_REPORT
COV_EXIT_CODE=$?
cat COV_REPORT
if [ $COV_EXIT_CODE -ne 0 ]; then
echo "🚨 Python Coverage failed. Coverage too low." | 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: Create coverage HTML
run: python -m coverage html
if: ${{ failure() && steps.combinecoverage.outcome == 'failure' }}
- name: Upload HTML report.
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: _html-report
path: htmlcov
if-no-files-found: ignore
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: CI on: pull_request: {} push: {} permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: linux: timeout-minutes: 30 runs-on: ${{ matrix.PYTHON.OS || 'ubuntu-latest' }} strategy: fail-fast: false matrix: PYTHON: # Base builds - {VERSION: "3.9", NOXSESSION: "tests"} - {VERSION: "3.10", NOXSESSION: "tests"} - {VERSION: "3.11", NOXSESSION: "tests"} - {VERSION: "3.12", NOXSESSION: "tests"} - {VERSION: "3.13", NOXSESSION: "tests"} - {VERSION: "3.14", NOXSESSION: "tests"} - {VERSION: "3.14t", NOXSESSION: "tests"} - {VERSION: "pypy-3.11", NOXSESSION: "tests"} - {VERSION: "3.11", NOXSESSION: "tests-wheel", OS: "windows-latest"} - {VERSION: "3.14t", NOXSESSION: "tests-wheel", OS: "windows-latest"} # -cryptography-main - {VERSION: "3.9", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.10", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.11", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.12", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.13", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.14", NOXSESSION: "tests-cryptography-main"} - {VERSION: "3.14t", NOXSESSION: "tests-cryptography-main"} - {VERSION: "pypy-3.11", NOXSESSION: "tests-cryptography-main"} # -cryptography-minimum - {VERSION: "3.9", NOXSESSION: "tests-cryptography-minimum"} - {VERSION: "3.10", NOXSESSION: "tests-cryptography-minimum"} - {VERSION: "3.11", NOXSESSION: "tests-cryptography-minimum"} - {VERSION: "3.12", NOXSESSION: "tests-cryptography-minimum"} - {VERSION: "3.13", NOXSESSION: "tests-cryptography-minimum"} - {VERSION: "pypy-3.11", NOXSESSION: "tests-cryptography-minimum"} # Cryptography wheels - {VERSION: "3.9", NOXSESSION: "tests-cryptography-minimum-wheel"} - {VERSION: "3.9", NOXSESSION: "tests-wheel"} # Random order - {VERSION: "3.9", NOXSESSION: "tests-random-order"} # aws-lc - {VERSION: "3.14", NOXSESSION: "tests-cryptography-main", OPENSSL: {TYPE: "aws-lc", VERSION: "v1.73.0"}} # Meta - {VERSION: "3.9", NOXSESSION: "check-manifest"} - {VERSION: "3.11", NOXSESSION: "lint"} - {VERSION: "3.13", NOXSESSION: "mypy"} - {VERSION: "3.9", NOXSESSION: "docs"} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Setup python uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: cache: 'pip' python-version: ${{ matrix.PYTHON.VERSION }} - name: Cache custom OpenSSL if: matrix.PYTHON.OPENSSL id: ossl-cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/ossl key: ossl-${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }} - name: Build custom OpenSSL if: matrix.PYTHON.OPENSSL && steps.ossl-cache.outputs.cache-hit != 'true' run: | git clone --depth 1 --branch ${{ matrix.PYTHON.OPENSSL.VERSION }} https://github.com/aws/aws-lc.git cmake -GNinja -B aws-lc/build -S aws-lc -DCMAKE_INSTALL_PREFIX="${HOME}/ossl" -DBUILD_TESTING=OFF ninja -C aws-lc/build install rm -rf aws-lc/ - name: Set up custom OpenSSL env if: matrix.PYTHON.OPENSSL run: | cargo install bindgen-cli echo "OPENSSL_DIR=${HOME}/ossl" >> $GITHUB_ENV - run: python -m pip install nox - run: nox env: NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} - uses: ./.github/actions/upload-coverage linux-docker: timeout-minutes: 30 runs-on: latchkey-small container: ghcr.io/pyca/cryptography-runner-${{ matrix.TEST.CONTAINER }} strategy: fail-fast: false matrix: TEST: # cryptography-main used since there's no wheel - {CONTAINER: "ubuntu-rolling", NOXSESSION: "tests-cryptography-main"} name: "${{ matrix.TEST.NOXSESSION }} on ${{ matrix.TEST.CONTAINER }}" steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - run: /venv/bin/pip install nox - run: /venv/bin/nox env: RUSTUP_HOME: /root/.rustup NOXSESSION: ${{ matrix.TEST.NOXSESSION }} - uses: ./.github/actions/upload-coverage linux-downstream: timeout-minutes: 30 runs-on: latchkey-small strategy: fail-fast: false matrix: DOWNSTREAM: - twisted - certbot - certbot-josepy PYTHON: - 3.12 name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Setup python uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: cache: 'pip' python-version: ${{ matrix.PYTHON }} - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install - run: pip install . - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run all-green: runs-on: latchkey-small needs: [linux, linux-docker, linux-downstream] if: ${{ always() }} timeout-minutes: 3 steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 timeout-minutes: 3 with: persist-credentials: false - name: Setup python uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: cache: 'pip' python-version: '3.12' timeout-minutes: 3 - run: pip install coverage[toml] - name: Download coverage data uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-data-* merge-multiple: true - name: Combine coverage and fail if it's too low id: combinecoverage run: | set +e python -m coverage combine echo "## Python Coverage" >> $GITHUB_STEP_SUMMARY python -m coverage report -m --fail-under=98 > COV_REPORT COV_EXIT_CODE=$? cat COV_REPORT if [ $COV_EXIT_CODE -ne 0 ]; then echo "🚨 Python Coverage failed. Coverage too low." | 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: Create coverage HTML run: python -m coverage html if: ${{ failure() && steps.combinecoverage.outcome == 'failure' }} - name: Upload HTML report. uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: _html-report path: htmlcov if-no-files-found: ignore
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 4 jobs (37 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.