name: wai-quantum wasmQ # wasmQ (wai/extensions/quantum-wasmq.md): an OpenQASM 3 program and the WebAssembly its # `extern`s call, run with the same result bytes and fuel on every host and sealed in a # receipt (wai/wai-wasmq). Each leg runs the crate's tests on its host and checks the # conformance vectors, which pin each run's whole job digest, so every leg passing is the # claim that the bytes are the same on linux x86_64, macOS arm64 and wasm32. The linux leg # also rebuilds the reference modules and requires the modules of record byte for byte. concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }} cancel-in-progress: true on: push: branches: [main] paths: - 'wai/wai-wasmq/**' - 'wai/quantum-conformance/wasmq/**' - 'wai/extensions/quantum-wasmq.*' - 'wai/wai-quantum/**' - 'rust-toolchain.toml' - '.github/workflows/wai-quantum-wasmq.yml' pull_request: paths: - 'wai/wai-wasmq/**' - 'wai/quantum-conformance/wasmq/**' - 'wai/extensions/quantum-wasmq.*' - 'wai/wai-quantum/**' - 'rust-toolchain.toml' - '.github/workflows/wai-quantum-wasmq.yml' jobs: relevant: name: does this change touch it runs-on: linux outputs: run: ${{ steps.gate.outputs.run }} steps: - uses: actions/checkout@v5 with: fetch-depth: 0 - id: gate run: | set -euo pipefail r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-quantum-wasmq.yml \ "${{ github.event.pull_request.base.sha }}" \ "${{ github.event.pull_request.head.sha }}") echo "this change touches wasmQ: $r" echo "run=$r" >> "$GITHUB_OUTPUT" native: name: profile, engines, reference modules, adversarial, vectors · ${{ matrix.os }} needs: relevant if: needs.relevant.outputs.run == 'true' strategy: fail-fast: false matrix: os: [linux, macos] runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 shell: bash run: | export PATH="$HOME/.cargo/bin:$PATH" command -v rustup >/dev/null 2>&1 || \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 rustup toolchain install 1.99.1 --profile minimal --component clippy rustup default 1.99.1 echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: The crate's tests, every engine of this host shell: bash working-directory: wai/wai-wasmq run: | set -euo pipefail cargo test --locked --release --no-fail-fast 2>&1 | tee "$RUNNER_TEMP/wasmq.log" if grep -q 'FAILED' "$RUNNER_TEMP/wasmq.log"; then echo "::error::a test failed"; exit 1; fi # Every test file of the crate ran, and none ran empty: a file nobody runs, or # one whose tests are all compiled out, would otherwise pass unseen. for f in tests/*.rs; do t=$(basename "$f" .rs) awk -v t="tests/$t.rs" '$1 == "Running" && $2 == t { seen = 1; next } seen && /^test result: ok\. [1-9][0-9]* passed; 0 failed/ { ok = 1; exit } seen && /^test result:/ { exit } END { exit ok ? 0 : 1 }' "$RUNNER_TEMP/wasmq.log" \ || { echo "::error::tests/$t.rs did not run and pass with at least one test"; exit 1; } done grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/wasmq.log" || { echo "::error::no test ran"; exit 1; } - name: The vectors, each engine, and their digest shell: bash working-directory: wai/wai-wasmq run: | set -euo pipefail for e in native interpreter interpreter-prepared; do cargo run --locked --release -q --bin wasmq_vectors -- verify ../quantum-conformance/wasmq "$e" | tail -1 done - name: Clippy, warnings denied shell: bash working-directory: wai/wai-wasmq run: cargo clippy --locked --release --all-targets -- -D warnings # wai-quantum holds a wasmQ job's form beside its receipts (engine::wasmq), and its # engine builds without them; each feature set builds, without warnings. - name: wai-quantum's engine with the receipts and without them if: matrix.os == 'linux' shell: bash working-directory: wai/wai-quantum env: RUSTFLAGS: -D warnings run: | set -euo pipefail cargo check --locked --no-default-features --features quantum_engine --lib cargo check --locked --no-default-features --features quantum_engine,quantum_receipt --lib modules: name: the reference modules rebuild to their modules of record · linux needs: relevant if: needs.relevant.outputs.run == 'true' runs-on: linux timeout-minutes: 30 steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 with the wasm32-unknown-unknown target shell: bash run: | export PATH="$HOME/.cargo/bin:$PATH" command -v rustup >/dev/null 2>&1 || \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 rustup toolchain install 1.99.1 --profile minimal rustup default 1.99.1 rustup target add --toolchain 1.99.1 wasm32-unknown-unknown echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Build and compare shell: bash run: bash wai/wai-wasmq/modules/build.sh --check - name: The sources the modules of record were built from shell: bash run: bash wai/wai-wasmq/modules/build.sh --sources wasip2: name: interpreter and vectors under wasm32-wasip2 (wasmtime) needs: relevant if: needs.relevant.outputs.run == 'true' runs-on: linux timeout-minutes: 60 steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 with the wasm32-wasip2 target shell: bash run: | export PATH="$HOME/.cargo/bin:$PATH" command -v rustup >/dev/null 2>&1 || \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 rustup toolchain install 1.99.1 --profile minimal rustup default 1.99.1 rustup target add --toolchain 1.99.1 wasm32-wasip2 echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" # The release binary, pinned by version and SHA-256, with both determinism settings on # every run (scripts/check-wasmtime-pin.py). Here wasmtime is the host the interpreter # runs in; the modules the interpreter runs are interpreted, not compiled by it. - name: Install wasmtime 50.0.1 shell: bash run: | set -euo pipefail [ "$(uname -m)" = x86_64 ] || { echo "::error::the pinned wasmtime archive is x86_64; this host is $(uname -m)"; exit 1; } if ! command -v xz >/dev/null 2>&1; then SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo" $SUDO apt-get update -qq $SUDO apt-get install -y -qq xz-utils fi v=50.0.1 f="wasmtime-v$v-x86_64-linux.tar.xz" curl --proto '=https' --tlsv1.2 -sSfL -o "$RUNNER_TEMP/$f" \ "https://github.com/bytecodealliance/wasmtime/releases/download/v$v/$f" echo "685466455dd42a14774a86c36c8f2e45cbb9bd6d92a850139315df60a75498a5 $RUNNER_TEMP/$f" | sha256sum -c - tar -xJf "$RUNNER_TEMP/$f" -C "$RUNNER_TEMP" echo "$RUNNER_TEMP/wasmtime-v$v-x86_64-linux" >> "$GITHUB_PATH" - name: The tests under wasm32, the interpreter the only engine shell: bash working-directory: wai/wai-wasmq run: | set -euo pipefail W=$(cd .. && pwd) CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y --dir $W::$W" \ cargo test --locked --release --target wasm32-wasip2 --no-default-features --no-fail-fast \ --lib --tests 2>&1 | tee "$RUNNER_TEMP/wasip2.log" if grep -q 'FAILED' "$RUNNER_TEMP/wasip2.log"; then echo "::error::a test failed under wasip2"; exit 1; fi for f in tests/*.rs; do t=$(basename "$f" .rs) awk -v t="tests/$t.rs" '$1 == "Running" && $2 == t { seen = 1; next } seen && /^test result: ok\. [1-9][0-9]* passed; 0 failed/ { ok = 1; exit } seen && /^test result:/ { exit } END { exit ok ? 0 : 1 }' "$RUNNER_TEMP/wasip2.log" \ || { echo "::error::tests/$t.rs did not run and pass under wasip2 with at least one test"; exit 1; } done - name: The vectors under wasm32 shell: bash run: | set -euo pipefail cargo build --locked --release --target wasm32-wasip2 --manifest-path wai/wai-wasmq/Cargo.toml --no-default-features --bin wasmq_vectors wasmtime run -W nan-canonicalization=y -W relaxed-simd-deterministic=y --dir wai/quantum-conformance/wasmq::/v \ wai/wai-wasmq/target/wasm32-wasip2/release/wasmq_vectors.wasm verify /v interpreter,interpreter-prepared | tail -1