Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions .github/workflows/build-ciris-verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on the Linux jobs (build-native, build-build-tool,
# publish-pypi) of
# https://github.com/CIRISAI/CIRISVerify/blob/v20.1.0/.github/workflows/release.yml
# and the wheel smoke test of
# https://github.com/CIRISAI/CIRISVerify/blob/v20.1.0/.github/workflows/post-release-verify.yml
name: Build ciris-verify wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/ciris-verify.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-ciris-verify.yml'
- 'docs/packages/ciris-verify.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-ciris-verify.yml'
- 'docs/packages/ciris-verify.yaml'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: ciris-verify
version: ${{ inputs.version }}

build_wheel:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build ciris-verify ${{ matrix.version }} py3-none-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 360
env:
CIRIS_VERIFY_VERSION: ${{ matrix.version }}

steps:
- name: Checkout CIRISVerify v${{ env.CIRIS_VERIFY_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: CIRISAI/CIRISVerify
ref: v${{ env.CIRIS_VERIFY_VERSION }}
persist-credentials: false

- name: Write container script
run: |
cat > riscv64-build.sh <<'EOF'
#!/bin/bash
set -e -x

# rusqlite links the system libsqlite3 dynamically on desktop targets
# (upstream installs libsqlite3-dev for the same reason).
dnf install -y sqlite-devel

# The manylinux image ships no Rust; rust-toolchain.toml pins the exact toolchain.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain none
. "${HOME}/.cargo/env"
rustup toolchain install

# Same feature sets as upstream's aarch64-unknown-linux-gnu legs (no TPM plugin).
cargo build --release -p ciris-verify-ffi
cargo build --release -p ciris-build-tool --features ciris-crypto/pqc-ml-dsa

cd bindings/python
cp ../../target/release/libciris_verify_ffi.so ciris_verify/
mkdir -p ciris_verify/_bin
cp ../../target/release/ciris-build-sign ../../target/release/ciris-build-verify ciris_verify/_bin/
# Upstream's wheels carry no licence: the project's LICENSE sits at the repo root,
# outside the default licence glob of this subdirectory's pyproject.toml.
cp ../../LICENSE .

/opt/python/cp312-cp312/bin/python -m pip install build wheel setuptools
/opt/python/cp312-cp312/bin/python -m build --wheel --outdir /io/dist-any
# Upstream renames the py3-none-any wheel to its platform tag; retag it properly.
/opt/python/cp312-cp312/bin/python -m wheel tags --platform-tag manylinux_2_39_riscv64 --remove /io/dist-any/*.whl
mkdir -p /io/dist
mv /io/dist-any/*.whl /io/dist/
EOF

- name: Build wheel
run: |
docker run --rm \
-v "$(pwd)":/io \
--workdir /io \
"${{ env.MANYLINUX_RISCV64_IMAGE }}" \
bash /io/riscv64-build.sh
ls -la dist/

- name: Check the native payload and licence made it into the wheel
run: |
python3 - dist/*.whl <<'EOF'
import sys, zipfile
whl = sys.argv[1]
names = zipfile.ZipFile(whl).namelist()
for want in ("ciris_verify/libciris_verify_ffi.so", "ciris_verify/_bin/ciris-build-sign", "ciris_verify/_bin/ciris-build-verify"):
assert want in names, (whl, want)
assert any(n.endswith(".dist-info/licenses/LICENSE") for n in names), whl
assert whl.endswith("-py3-none-manylinux_2_39_riscv64.whl"), whl
print(whl, "ok")
EOF

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ciris-verify-${{ env.CIRIS_VERIFY_VERSION }}-py3-none-manylinux_riscv64
path: dist/*.whl
if-no-files-found: error

test_wheel:
name: Test ciris-verify ${{ matrix.version }} ${{ matrix.python }}
needs: [setup, build_wheel]
if: needs.setup.outputs.versions != '[]'
runs-on: ubuntu-24.04-riscv
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python: ["cp312", "cp313", "cp314", "cp314t"]
env:
CIRIS_VERIFY_VERSION: ${{ matrix.version }}

steps:
- name: Checkout CIRISVerify v${{ env.CIRIS_VERIFY_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: CIRISAI/CIRISVerify
ref: v${{ env.CIRIS_VERIFY_VERSION }}
persist-credentials: false

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ciris-verify-${{ env.CIRIS_VERIFY_VERSION }}-py3-none-manylinux_riscv64
path: dist

- name: Write container script
run: |
cat > riscv64-test.sh <<'EOF'
#!/bin/bash
set -e -x

extra_args=()
case "${PYTHON_TAG}" in
*t)
python_dir="/opt/python/${PYTHON_TAG%t}-${PYTHON_TAG}/bin"
# test_init_rss_within_budget checks the whole process's RSS (interpreter, pytest, pydantic
# and all earlier tests) against a fixed 64 MB, which a free-threaded process exceeds on any
# arch (71 MB here, 75 MB with upstream's x86_64 wheel); upstream only tests 3.11/3.12.
extra_args+=(--deselect tests/test_memory_baseline.py::TestLiveFFIMemory::test_init_rss_within_budget)
;;
*) python_dir="/opt/python/${PYTHON_TAG}-${PYTHON_TAG}/bin" ;;
esac
export PATH="${python_dir}:${PATH}"

dnf install -y sqlite-libs
python -m pip install --only-binary=:all: /io/dist/*.whl pytest pytest-asyncio

# The FFI's .init_array constructor otherwise fetches the live registry on dlopen.
export CIRIS_SKIP_EARLY_VERIFY=1

# post-release-verify.yml's wheel version round-trip.
test "$(python -c 'from ciris_verify import get_library_version; print(get_library_version())')" = "${CIRIS_VERIFY_VERSION}"
ciris-build-sign --version
ciris-build-verify --version

# The FFI tests look for the library at tests/../ciris_verify, so run a copy of the
# suite next to a link to the installed package rather than the checkout's sources.
mkdir /tmp/suite
cp -r bindings/python/tests /tmp/suite/
ln -s "$(python -c 'import ciris_verify, os; print(os.path.dirname(ciris_verify.__file__))')" /tmp/suite/ciris_verify
cd /tmp/suite
# Deselected tests fail identically on upstream's x86_64 wheel: a mock wildcard-capability
# assertion, and a 404 message check predating the v2.2.0 "not_yet_registered:" format.
CIRIS_VERIFY_LIVE_TESTS=1 python -m pytest -v -p no:cacheprovider tests \
--deselect tests/test_client.py::TestMockCIRISVerify::test_capability_check_licensed \
--deselect tests/test_client.py::TestVerifyTreeFFI::test_walk_succeeds_registry_returns_404 \
"${extra_args[@]}"
EOF

- name: Install the wheel and run upstream's Python test suite
run: |
docker run --rm \
-v "$(pwd)":/io \
--workdir /io \
-e PYTHON_TAG="${{ matrix.python }}" \
-e CIRIS_VERIFY_VERSION \
"${{ env.MANYLINUX_RISCV64_IMAGE }}" \
bash /io/riscv64-test.sh

publish:
name: Publish ciris-verify ${{ matrix.version }}
needs: [setup, build_wheel, test_wheel]
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: ciris-verify-${{ matrix.version }}-*-manylinux_riscv64
5 changes: 5 additions & 0 deletions docs/packages/ciris-verify.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: ciris-verify
source-code: https://github.com/CIRISAI/CIRISVerify
license: AGPL-3.0-or-later
versions:
- version: 20.1.0
Loading