on: push: branches: - main - dev paths-ignore: - "**.md" - "!.github/workflows/*.yml" pull_request: paths-ignore: - "**.md" - "!.github/workflows/*.yml" permissions: contents: read pull-requests: read packages: read name: General jobs: ci-image: permissions: contents: read packages: write uses: ./.github/workflows/ci-image.yml fmt-rs: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Check Rust files are formatted run: cargo +nightly fmt --check fmt-toml: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} # No path argument: taplo reads a `.` as a literal file, excludes it for # not being a .toml, and checks nothing. - name: Check TOML files are formatted run: taplo fmt --check machete: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Check for unused dependencies run: cargo machete deny: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Check licenses and advisories run: cargo deny check lint: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 60 name: lint steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Lint workspace env: RISC0_SKIP_BUILD: "1" run: cargo clippy --workspace --all-targets --all-features -- -D warnings - name: Lint programs env: RISC0_SKIP_BUILD: "1" run: cargo clippy -p "*program" -- -D warnings unit-tests: needs: ci-image runs-on: ubuntu-latest container: image: ${{ needs.ci-image.outputs.image }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 60 steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Run tests env: RISC0_DEV_MODE: "1" RUST_LOG: "info" run: cargo nextest run --workspace --exclude integration_tests --exclude test_fixtures --all-features # Not a `container:` job: the tests drive the host's Docker daemon through # testcontainers, so they run in the CI image via `run-in-ci-image` instead. test-fixtures-tests: needs: ci-image runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Run test_fixtures tests uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} env: | RISC0_DEV_MODE=1 RUST_LOG=info run: cargo nextest run -p test_fixtures # Not a `container:` job: the test binaries bake CARGO_MANIFEST_DIR in at # compile time, so the archive has to be built on the same path the matrix # jobs later run it from. integration-tests-prebuild: needs: ci-image runs-on: ubuntu-latest outputs: targets: ${{ steps.discover-targets.outputs.targets }} steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Build integration test archive uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} env: RISC0_DEV_MODE=1 run: cargo nextest archive -p integration_tests --archive-file integration-tests.tar.zst --no-pager - name: Upload integration test archive uses: actions/upload-artifact@v4 with: name: integration-tests-archive path: integration-tests.tar.zst - name: List integration test binaries uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} run: | cargo nextest list \ --archive-file integration-tests.tar.zst \ --list-type binaries-only \ --message-format json \ --no-pager > integration-tests-binaries.json # $GITHUB_OUTPUT is outside the mounted workspace, so the container cannot # write to it. jq is on the runner, so do this pass here. - name: Discover integration test targets from archive id: discover-targets run: | targets_json="$(jq -c '[."rust-binaries" | to_entries[] | select(.value.kind == "test" and .value."binary-name" != "tps") | .value."binary-name"] | sort | unique' integration-tests-binaries.json)" if [[ "$targets_json" == "[]" ]]; then echo "No integration test targets were discovered." >&2 exit 1 fi echo "targets=$targets_json" >> "$GITHUB_OUTPUT" echo "Discovered integration targets: $targets_json" integration-tests: needs: [ci-image, test-fixtures-tests, integration-tests-prebuild] runs-on: ubuntu-latest timeout-minutes: 90 strategy: fail-fast: false matrix: target: ${{ fromJson(needs.integration-tests-prebuild.outputs.targets) }} name: integration-tests (${{ matrix.target }}) steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Download integration test archive uses: actions/download-artifact@v4 with: name: integration-tests-archive - name: Run tests uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} env: | RISC0_DEV_MODE=1 RUST_LOG=info run: cargo nextest run --archive-file integration-tests.tar.zst -E "binary(${{ matrix.target }})" valid-proof-test: needs: ci-image runs-on: ubuntu-latest timeout-minutes: 90 steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Test valid proof uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} env: RUST_LOG=info run: cargo test -p integration_tests -- --exact private::private_transfer_to_owned_account # `just build-artifacts` drives the host's Docker daemon via `cargo risczero # build`, so it goes through the image rather than `container:`. artifacts: needs: ci-image runs-on: ubuntu-latest timeout-minutes: 60 name: artifacts steps: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha || github.head_ref }} - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Restore Rust cache uses: Swatinem/rust-cache@v2 with: shared-key: ci-rust-cache save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' }} - name: Build artifacts uses: ./.github/actions/run-in-ci-image with: image: ${{ needs.ci-image.outputs.image }} run: just build-artifacts - name: Check if artifacts match repository run: | if ! git diff --exit-code artifacts/; then echo "❌ Artifacts in the repository are out of date!" echo "Please run 'just build-artifacts' and commit the changes." exit 1 fi echo "✅ Artifacts are up to date"