workflows: add build-cryptography.yml for riscv64 wheels #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: 2026 The RISE Project | |
| # SPDX-License-Identifier: MIT | |
| # | |
| # Mirrors upstream's own wheel builder almost verbatim, trimmed to the Linux | |
| # glibc/riscv64 case: | |
| # https://github.com/pyca/cryptography/blob/50.0.0/.github/workflows/wheel-builder.yml | |
| # Dropped: macos, windows, musllinux (no riscv64 musl Rust target, see | |
| # "Skipping musl Builds" in docs/development.md), the pypy311 matrix row, and | |
| # the `vectors` sdist+wheel (cryptography_vectors is pure-Python and already | |
| # published on public PyPI for every cryptography release, so the test job | |
| # installs it directly instead of building it from vectors/). | |
| # | |
| # The `manylinux` job can't reuse upstream's own `container:` job as-is: | |
| # their ghcr.io/pyca/cryptography-manylinux2014:x86_64-style images (with | |
| # Rust, a static OpenSSL build, and an SBOM preinstalled at | |
| # /opt/pyca/cryptography/openssl) don't exist for riscv64, and the closest | |
| # available image (quay.io/pypa/manylinux_2_39_riscv64) ships no Node, so a | |
| # native `container:` job can't run the checkout/artifact actions inside it. | |
| # We drive that image with `podman run` instead (see build-orjson.yml for the | |
| # same pattern), keeping the actions on the host and running upstream's own | |
| # build/repair/smoketest commands inside - only substituting the OpenSSL | |
| # linkage (dynamic system OpenSSL via pkg-config, since there's no prebuilt | |
| # static one for riscv64) and installing Rust ourselves. | |
| name: Build cryptography wheels (riscv64) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'cryptography version to build (git tag, e.g. 50.0.0)' | |
| required: true | |
| default: '50.0.0' | |
| pull_request: | |
| paths: | |
| - '.github/workflows/build-cryptography.yml' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ inputs.version || '50.0.0' }}-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| env: | |
| CRYPTOGRAPHY_VERSION: ${{ inputs.version || '50.0.0' }} | |
| MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 | |
| jobs: | |
| sdist: | |
| name: Build cryptography ${{ inputs.version || '50.0.0' }} sdist | |
| runs-on: ubuntu-latest | |
| outputs: | |
| sdist_name: ${{ steps.sdist.outputs.sdist_name }} | |
| package_version: ${{ steps.sdist.outputs.package_version }} | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| repository: pyca/cryptography | |
| ref: ${{ env.CRYPTOGRAPHY_VERSION }} | |
| persist-credentials: false | |
| - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 | |
| with: | |
| python-version: '3.12' | |
| activate-environment: true | |
| enable-cache: false | |
| # Same as upstream's "Make sdist (cryptography)" step, minus | |
| # --build-constraint/--require-hashes: those hash-pin against upstream's | |
| # own PyPI-hosted build deps, which don't match the riscv64 wheels our | |
| # own registry serves for the same versions (e.g. cffi) - see gotcha 30. | |
| - name: Make sdist (cryptography) | |
| id: sdist | |
| run: | | |
| set -euo pipefail | |
| uv build --sdist | |
| sdist_name="$(ls dist)" | |
| { | |
| echo "sdist_name=${sdist_name}" | |
| echo "package_version=$(echo "${sdist_name}" | sed -En 's/cryptography-(.+)\.tar\.gz/\1/p')" | |
| } >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: ${{ steps.sdist.outputs.sdist_name }} | |
| path: dist/${{ steps.sdist.outputs.sdist_name }} | |
| if-no-files-found: error | |
| # Same PYTHON matrix shape as upstream's `manylinux` job (one abi3 build | |
| # plus one free-threaded build), with a single MANYLINUX row added for | |
| # riscv64 in place of upstream's x86_64/aarch64/ppc64le/armv7l rows. | |
| # Upstream builds two abi3 floors (py39, py311) from one cp311 interpreter | |
| # to serve their whole public; RISE's own floor is cp312 (docs/development.md), | |
| # so we drop the py39 row and build the single abi3 floor we need directly | |
| # with a cp312 interpreter instead of overriding it down from cp311 - no | |
| # ABI_VERSION/PY_LIMITED_API needed, since pyo3's plain `abi3` feature | |
| # already floors at whichever interpreter did the build. | |
| manylinux: | |
| needs: [sdist] | |
| name: "${{ matrix.PYTHON.TAG }} for manylinux_riscv64" | |
| runs-on: ubuntu-24.04-riscv | |
| timeout-minutes: 90 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| PYTHON: | |
| - { VERSION: "cp312-cp312", TAG: 'cp312-cp312' } | |
| - { VERSION: "cp314-cp314t", TAG: 'cp314-cp314t' } | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: ${{ needs.sdist.outputs.sdist_name }} | |
| path: dist/ | |
| - run: mkdir tmpwheelhouse wheelhouse | |
| # Corresponds to upstream's "Build the wheel" + "auditwheel repair" | |
| # steps. The image has no Rust and no OpenSSL dev headers/pkg-config, | |
| # so install them first (upstream's own container bakes these in); | |
| # openssl-sys then finds the image's dynamic system OpenSSL via | |
| # pkg-config (there's no static build to point OPENSSL_DIR/ | |
| # OPENSSL_STATIC at, so both are dropped, along with --sbom-include, | |
| # which points at a static build's generated sbom.json that has no | |
| # riscv64 equivalent). | |
| - name: Build the wheel | |
| run: | | |
| podman run -t \ | |
| --network=host \ | |
| -v "$(pwd)":/workspace \ | |
| --workdir /workspace \ | |
| -e PYTHON_VERSION="${{ matrix.PYTHON.VERSION }}" \ | |
| -e PIP_EXTRA_INDEX_URL="https://pypi.riseproject.dev/simple/" \ | |
| "${{ env.MANYLINUX_RISCV64_IMAGE }}" \ | |
| bash -c ' | |
| set -euo pipefail | |
| dnf install -y openssl-devel pkgconfig | |
| curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | |
| export PATH="$PATH:$HOME/.cargo/bin" | |
| manylinux-entrypoint uv build --python="/opt/python/$PYTHON_VERSION/bin/python" \ | |
| --wheel dist/cryptography*.tar.gz -o tmpwheelhouse/ | |
| auditwheel repair --plat manylinux_2_39_riscv64 tmpwheelhouse/cryptography*.whl -w wheelhouse/ | |
| unzip -q wheelhouse/*.whl -d execstack.check | |
| results=$(readelf -lW execstack.check/cryptography/hazmat/bindings/*.so) | |
| count=$(echo "$results" | grep -c "GNU_STACK.*[R ][W ]E" || true) | |
| test "$count" -eq 0 | |
| ' | |
| # Corresponds to upstream's "Smoketest" step (their | |
| # .github/actions/wheel-smoketest composite action). It can't be | |
| # `uses:`'d directly - it needs to run against the manylinux image's | |
| # own /opt/python interpreter, and this job never becomes a native | |
| # `container:` job (see the workflow-level comment) - so its two checks | |
| # (install with no index, then confirm the OpenSSL backend loads) are | |
| # reproduced inline here instead. The manylinux_riscv64 image has no | |
| # SHA1-restricting crypto-policy the way a distro-derived host might, | |
| # so no config override is needed for this smoke check. | |
| - name: Smoketest | |
| run: | | |
| podman run -t \ | |
| --network=host \ | |
| -v "$(pwd)":/workspace \ | |
| --workdir /workspace \ | |
| -e PYTHON_VERSION="${{ matrix.PYTHON.VERSION }}" \ | |
| -e PIP_EXTRA_INDEX_URL="https://pypi.riseproject.dev/simple/" \ | |
| "${{ env.MANYLINUX_RISCV64_IMAGE }}" \ | |
| bash -c ' | |
| set -euo pipefail | |
| "/opt/python/$PYTHON_VERSION/bin/python" -m venv /tmp/smoketest-venv | |
| . /tmp/smoketest-venv/bin/activate | |
| pip install "cffi>=2.0.0" | |
| pip install cryptography --no-index -f wheelhouse/ | |
| python -c "from cryptography.hazmat.backends.openssl.backend import backend; print(\"Loaded:\", backend.openssl_version_text()); print(\"Linked Against:\", backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode(\"ascii\"))" | |
| ' | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: "cryptography-${{ needs.sdist.outputs.package_version }}-${{ matrix.PYTHON.TAG }}-manylinux_riscv64" | |
| path: wheelhouse/*.whl | |
| if-no-files-found: error | |
| # Runs the real upstream test suite against the built wheel - upstream's | |
| # own wheel-builder.yml only smoketests (the full suite runs separately in | |
| # ci.yml, from a source checkout across many OpenSSL variants, which is out | |
| # of scope here). cryptography_vectors comes straight from public PyPI | |
| # (see the workflow-level comment); --wycheproof-root/--x509-limbo-root are | |
| # left unset, which upstream's own conftest treats as skip (external vector | |
| # repos - large downloads, a justified skip). | |
| test: | |
| needs: [sdist, manylinux] | |
| name: "${{ matrix.PYTHON.TAG }} tests" | |
| runs-on: ubuntu-24.04-riscv | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| PYTHON: | |
| - { VERSION: "cp312-cp312", TAG: 'cp312-cp312' } | |
| - { VERSION: "cp314-cp314t", TAG: 'cp314-cp314t' } | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| repository: pyca/cryptography | |
| ref: ${{ env.CRYPTOGRAPHY_VERSION }} | |
| persist-credentials: false | |
| sparse-checkout: | | |
| tests | |
| pyproject.toml | |
| sparse-checkout-cone-mode: false | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: "cryptography-${{ needs.sdist.outputs.package_version }}-${{ matrix.PYTHON.TAG }}-manylinux_riscv64" | |
| path: wheelhouse/ | |
| - name: Run test suite | |
| run: | | |
| podman run -t \ | |
| --network=host \ | |
| -v "$(pwd)":/workspace \ | |
| --workdir /workspace \ | |
| -e PYTHON_VERSION="${{ matrix.PYTHON.VERSION }}" \ | |
| -e PIP_EXTRA_INDEX_URL="https://pypi.riseproject.dev/simple/" \ | |
| "${{ env.MANYLINUX_RISCV64_IMAGE }}" \ | |
| bash -c ' | |
| set -euo pipefail | |
| "/opt/python/$PYTHON_VERSION/bin/python" -m venv /tmp/test-venv | |
| . /tmp/test-venv/bin/activate | |
| pip install "cffi>=2.0.0" | |
| pip install cryptography --no-index -f wheelhouse/ | |
| pip install cryptography_vectors=="${{ needs.sdist.outputs.package_version }}" \ | |
| "pytest>=7.4.0" "pytest-benchmark>=4.0" "pytest-xdist>=3.5.0" "pretend>=0.7" "certifi>=2024" | |
| python -m pytest -n auto --dist=worksteal tests | |
| ' | |
| publish: | |
| name: Publish cryptography ${{ inputs.version || '50.0.0' }} to GitLab | |
| needs: [sdist, manylinux, test] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Publish wheels and open docs PR | |
| uses: riseproject-dev/python-wheels/actions/publish-wheels@main | |
| with: | |
| artifact-pattern: cryptography-${{ needs.sdist.outputs.package_version }}-*-manylinux_riscv64 | |
| gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }} | |
| gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }} | |
| gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }} | |
| gh-token: ${{ secrets.GITHUB_TOKEN }} |