diff --git a/.github/workflows/build-cryptography.yml b/.github/workflows/build-cryptography.yml new file mode 100644 index 00000000..544b0456 --- /dev/null +++ b/.github/workflows/build-cryptography.yml @@ -0,0 +1,206 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +# +# Based on upstream's wheel builder: +# https://github.com/pyca/cryptography/blob/50.0.0/.github/workflows/wheel-builder.yml +# cryptography is a PyO3/Rust extension built with maturin (not setuptools-rust) +# and links OpenSSL. Upstream links a statically-built OpenSSL from their own +# pyca/infra images, which don't exist for riscv64; we link the manylinux +# image's system OpenSSL dynamically instead (gotcha 16) and let auditwheel +# vendor libssl/libcrypto into the wheel. +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 + # abi3 floor: cp312 is RISE's min Python, and it's also the interpreter we + # build with, so a plain `abi3` feature already floors here with no + # explicit pyo3/abi3-pyNN override (unlike upstream, which builds two + # different floors from one cp311 interpreter). + ABI3_FLOOR: cp312 + +jobs: + # Build the sdist ourselves from the tag (never the prebuilt PyPI sdist); it's + # arch-independent, so build it once on x86 (gotcha 4). + build_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: + - name: Checkout cryptography ${{ env.CRYPTOGRAPHY_VERSION }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + repository: pyca/cryptography + ref: ${{ env.CRYPTOGRAPHY_VERSION }} + persist-credentials: false + + - name: Install Python + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + python-version: '3.12' + activate-environment: true + enable-cache: false + + - name: Build sdist + id: sdist + run: | + set -euo pipefail + rm -rf dist + uv pip install build twine + python -m build --sdist --outdir dist + twine check dist/* + + 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" + + - name: Upload sdist artifact + 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 + + # One cp312-abi3 wheel: cibuildwheel builds it once and reuses+tests it on + # cp313/cp314 (find_compatible_wheel), so all three tags share one wheel. + build_abi3: + needs: [build_sdist] + name: Build cryptography ${{ inputs.version || '50.0.0' }} cp312-abi3-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 90 + steps: + - name: Download sdist + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ needs.build_sdist.outputs.sdist_name }} + path: dist/ + + - name: Build and test wheel + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + package-dir: dist/${{ needs.build_sdist.outputs.sdist_name }} + env: + CIBW_ARCHS: riscv64 + CIBW_BUILD: 'cp312-* cp313-* cp314-*' + CIBW_SKIP: '*-musllinux_*' # rustup.rs has no riscv64 musl toolchain + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + # No Rust and no OpenSSL dev headers in the manylinux image; install + # them. openssl-sys finds the (dynamic-only, gotcha 16) system + # OpenSSL via pkg-config, so no OPENSSL_STATIC/OPENSSL_DIR needed. + # The manylinux image's system OpenSSL is RHEL-patched to reject + # SHA1 signing/verification unless `rh-allow-sha1-signatures = yes` + # is set (openssl/openssl#17662); upstream's own unrestricted + # static OpenSSL build never hits this. OPENSSL_CONF=/dev/null + # does NOT fix it - the patch denies SHA1 by default when the + # option is absent from config entirely, so write a minimal config + # that opts back in for the test phase only. It isn't bundled by + # auditwheel (only the .so is), so it never reaches the shipped + # wheel. + CIBW_BEFORE_ALL_LINUX: | + dnf install -y openssl-devel pkgconfig + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + printf 'openssl_conf = openssl_init\n\n[openssl_init]\nalg_section = evp_properties\n\n[evp_properties]\nrh-allow-sha1-signatures = yes\n' > /tmp/rise-allow-sha1.cnf + CIBW_ENVIRONMENT: >- + PATH="$PATH:$HOME/.cargo/bin" + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + # cryptography_vectors is pure-Python and already published on + # public PyPI for this version, so install it directly instead of + # building it from upstream's vectors/ subdir. --wycheproof-root + # and --x509-limbo-root are left unset, which upstream's own + # conftest treats as "skip" (external vector repos, gotcha: + # justified skip - large external downloads). + CIBW_TEST_REQUIRES: >- + cryptography_vectors==${{ needs.build_sdist.outputs.package_version }} + pytest>=7.4.0 pytest-benchmark>=4.0 pytest-xdist>=3.5.0 pretend>=0.7 certifi>=2024 + CIBW_TEST_ENVIRONMENT: OPENSSL_CONF=/tmp/rise-allow-sha1.cnf + CIBW_TEST_COMMAND: cd {package} && python -m pytest -n auto --dist=worksteal tests + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cryptography-${{ env.CRYPTOGRAPHY_VERSION }}-cp312-abi3-manylinux_riscv64 + path: ./wheelhouse/*.whl + if-no-files-found: error + + # Free-threaded wheel: per-interpreter, no abi3 tag (matches upstream's own + # cp314-cp314t wheel). Only cp314t - the riscv64 image has no cp313t. + build_freethreaded: + needs: [build_sdist] + name: Build cryptography ${{ inputs.version || '50.0.0' }} cp314t-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 90 + steps: + - name: Download sdist + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ needs.build_sdist.outputs.sdist_name }} + path: dist/ + + - name: Build and test wheel + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + package-dir: dist/${{ needs.build_sdist.outputs.sdist_name }} + env: + CIBW_ARCHS: riscv64 + CIBW_BUILD: 'cp314t-*' + CIBW_SKIP: '*-musllinux_*' + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + # See the abi3 job above for why this writes an opt-in SHA1 config + # instead of nulling OPENSSL_CONF. + CIBW_BEFORE_ALL_LINUX: | + dnf install -y openssl-devel pkgconfig + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + printf 'openssl_conf = openssl_init\n\n[openssl_init]\nalg_section = evp_properties\n\n[evp_properties]\nrh-allow-sha1-signatures = yes\n' > /tmp/rise-allow-sha1.cnf + CIBW_ENVIRONMENT: >- + PATH="$PATH:$HOME/.cargo/bin" + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + CIBW_TEST_REQUIRES: >- + cryptography_vectors==${{ needs.build_sdist.outputs.package_version }} + pytest>=7.4.0 pytest-benchmark>=4.0 pytest-xdist>=3.5.0 pretend>=0.7 certifi>=2024 + CIBW_TEST_ENVIRONMENT: OPENSSL_CONF=/tmp/rise-allow-sha1.cnf + CIBW_TEST_COMMAND: cd {package} && python -m pytest -n auto --dist=worksteal tests + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cryptography-${{ env.CRYPTOGRAPHY_VERSION }}-cp314t-manylinux_riscv64 + path: ./wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish cryptography ${{ inputs.version || '50.0.0' }} to GitLab + needs: [build_sdist, build_abi3, build_freethreaded] + 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.build_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 }}