diff --git a/.github/workflows/build-cloudcheck.yml b/.github/workflows/build-cloudcheck.yml new file mode 100644 index 000000000000..6766a274b58b --- /dev/null +++ b/.github/workflows/build-cloudcheck.yml @@ -0,0 +1,144 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `linux` job of +# https://github.com/blacklanternsecurity/cloudcheck/blob/v11.1.0/.github/workflows/python-tests.yml +name: Build cloudcheck wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/cloudcheck.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-cloudcheck.yml' + - 'docs/packages/cloudcheck.yaml' + push: + branches: [main] + paths: + - '.github/workflows/build-cloudcheck.yml' + - 'docs/packages/cloudcheck.yaml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: cloudcheck + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build cloudcheck ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 180 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ['cp312', 'cp313', 'cp314', 'cp314t'] + + env: + CLOUDCHECK_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout cloudcheck v${{ env.CLOUDCHECK_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: blacklanternsecurity/cloudcheck + ref: v${{ env.CLOUDCHECK_VERSION }} + persist-credentials: false + + - name: Determine target interpreter + id: interp + run: | + v="${{ matrix.python }}" + v="${v#cp}" + echo "value=python${v:0:1}.${v:1}" >> "$GITHUB_OUTPUT" + + - name: Build wheel + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 + with: + target: riscv64gc-unknown-linux-gnu + args: --release --out dist -i ${{ steps.interp.outputs.value }} + sccache: false + manylinux: '2_39' + # The tag ships no licence text for its Cargo.toml `GPL-3.0` grant or + # the statically linked vendored OpenSSL. + before-script-linux: | + yum install -y openssl openssl-devel perl perl-core make gcc gcc-c++ binutils + cargo fetch --locked + cp "${CARGO_HOME:-$HOME/.cargo}"/registry/src/*/openssl-src-*/openssl/LICENSE.txt LICENSE.openssl + curl -fsSL https://www.gnu.org/licenses/gpl-3.0.txt -o LICENSE + + - name: Check the wheel ships the extension and its licences + run: | + set -euo pipefail + python3 - dist/*.whl <<'EOF' + import os, sys, zipfile + whl = sys.argv[1] + assert os.path.basename(whl).startswith(f"cloudcheck-{os.environ['CLOUDCHECK_VERSION']}-"), whl + names = zipfile.ZipFile(whl).namelist() + sos = [n for n in names if n.endswith(".so")] + assert any(n.startswith("cloudcheck/cloudcheck.") for n in sos), sos + licences = {n.rsplit("/", 1)[1] + for n in names if ".dist-info/licenses/" in n} - {""} + assert licences == {"LICENSE", "LICENSE.openssl"}, (whl, licences) + print(whl, "->", sos) + EOF + + - name: Install Python + uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 + with: + python-version: ${{ steps.interp.outputs.value }} + activate-environment: true + enable-cache: false + + # Run outside the checkout so the source `cloudcheck/` package, which has + # no compiled module, does not shadow the installed wheel. + # `cloudcheck.providers` imports pydantic, but upstream only lists it in + # its `dev` dependency group (the wheel declares no dependencies), so the + # tests need it installed explicitly. pydantic-core is pinned to a + # binary wheel: PyPI ships manylinux riscv64 wheels for every tag here. + - name: Test wheel + run: | + uv pip install --reinstall dist/*.whl + uv pip install --only-binary pydantic-core 'pytest>=8.4.2' 'pytest-asyncio>=0.24.0' 'pydantic>=2.12.5' + mkdir -p riscv64-tests + cp test_cloudcheck.py riscv64-tests/ + cd riscv64-tests + python -m pytest test_cloudcheck.py -v + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cloudcheck-${{ env.CLOUDCHECK_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: dist/*.whl + if-no-files-found: error + + publish: + name: Publish cloudcheck ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: cloudcheck-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/cloudcheck.yaml b/docs/packages/cloudcheck.yaml new file mode 100644 index 000000000000..f18455e4ae08 --- /dev/null +++ b/docs/packages/cloudcheck.yaml @@ -0,0 +1,5 @@ +package-name: cloudcheck +source-code: https://github.com/blacklanternsecurity/cloudcheck +license: GPL-3.0-only +versions: +- version: 11.1.0