name: wai-int-module WAISM module of record # The operator-set module (wai/wai-int-module), the first module of record of WAISM's # integer level (wai/extensions/waism.md, waism/1-int): one WebAssembly module with the ABI # of waism §5 that decodes WAI's integer capabilities through the integer operator set, the # networks and weights arriving as each capability's parameter set. Held on every engine # below, on Linux x86_64 and Linux arm64: # # - engines: the crate built for wasm32-unknown-unknown, scalar and SIMD128, each held at # the integer level by both of the profile's checkers (build.sh); the DRED weights the # module corpus names, fetched and checked against the draft's digest; then the module of # record (record/) and the two builds through wasmtime 50.0.1 with Cranelift and with # Winch, and Wasmi 2.0.0 (host/), and through Node (run-node.mjs): every case of the # module corpus (corpus.json: every committed vector and refusal fixture of the # capabilities the module decodes) to the SHA-256 or the refusal code the corpus states, # and one run digest for every module, engine and host. Then the engines are shown to # refuse what the checkers refuse: the module of record with a float instruction planted # does not compile on Wasmi with its floating point turned off, and with a relaxed vector # instruction planted compiles on no engine here. # - browser: the module of record in Chromium, headless, from Playwright 1.60.0's image # (browser/run-browser.mjs): every case decoded in a page's worker, each output sent back # as bytes and held to the corpus by Node, with the same run digest. # # A module of record is pinned: record/manifest.json names its build. A later change to the # decoders it was built from changes what build.sh builds, not record/, and both are held # here to the same corpus. # # One run per branch at a time. A push supersedes the run before it. concurrency: group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }} cancel-in-progress: true on: pull_request: paths: - 'wai/wai-int-module/**' - 'wai/extensions/waism.md' - '.github/workflows/wai-int-module.yml' push: branches: - main paths: - 'wai/wai-int-module/**' - 'wai/extensions/waism.md' - '.github/workflows/wai-int-module.yml' # The decoders the module is built from (wai-rs, wai-ops) and the corpora its corpus reads # change often; the nightly run holds the module and a fresh build of it to them. schedule: - cron: '35 4 * * *' jobs: # Does this pull request's own diff touch the paths above? A push to main, a schedule, or # anything the script cannot determine answers `true` (scripts/pr-touches-paths.py). relevant: name: does this change touch it runs-on: gate 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-int-module.yml \ "${{ github.event.pull_request.base.sha }}" \ "${{ github.event.pull_request.head.sha }}") echo "this change touches wai-int-module: $r" echo "run=$r" >> "$GITHUB_OUTPUT" engines: needs: relevant if: needs.relevant.outputs.run == 'true' name: ${{ matrix.os }} · both checkers, wasmtime (Cranelift, Winch), Wasmi and Node runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: fail-fast: false matrix: os: [linux, linux-arm64] steps: - uses: actions/checkout@v5 - name: Install Rust 1.99.1 with the wasm32 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 wasm32-unknown-unknown echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - uses: actions/setup-node@v4 with: node-version: '22' # Both builds, each held at the integer level by the Rust checker and check-module.mjs. - name: The module, scalar and SIMD128, held by both checkers shell: bash run: bash wai/wai-int-module/build.sh --out "$RUNNER_TEMP/module" # The corpus names the draft's weights file by digest and holds no copy (opus-dred §4.1). - name: The DRED weights, fetched and checked against the draft's digest shell: bash run: bash wai/live-conformance/dred/fetch.sh "$RUNNER_TEMP/dred" - name: Every case on wasmtime (Cranelift, Winch) and Wasmi, the module of record and this build shell: bash working-directory: wai/wai-int-module/host run: | set -euo pipefail M="$RUNNER_TEMP/module" cargo build --locked --release target/release/wai-int-module-host --count ../record/wai_int.wasm ../record/wai_int.simd128.wasm "$M/wai_int.wasm" "$M/wai_int.simd128.wasm" target/release/wai-int-module-host --external "$RUNNER_TEMP/dred" ../corpus.json \ ../record/wai_int.wasm ../record/wai_int.simd128.wasm "$M/wai_int.wasm" "$M/wai_int.simd128.wasm" - name: Every case under Node, the module of record and this build shell: bash working-directory: wai/wai-int-module run: | set -euo pipefail M="$RUNNER_TEMP/module" node run-node.mjs --external "$RUNNER_TEMP/dred" corpus.json \ record/wai_int.wasm record/wai_int.simd128.wasm "$M/wai_int.wasm" "$M/wai_int.simd128.wasm" # The engines' own guards behind the checkers (waism §7): Wasmi with its floating point # off refuses a module with a float instruction, and no engine here, set with relaxed # vector instructions off, compiles one with a relaxed instruction. - name: The engines refuse a planted float and a planted relaxed instruction shell: bash working-directory: wai/wai-int-module run: | set -euo pipefail H=host/target/release/wai-int-module-host python3 -I plant.py float record/wai_int.wasm "$RUNNER_TEMP/float.wasm" python3 -I plant.py relaxed record/wai_int.wasm "$RUNNER_TEMP/relaxed.wasm" if "$H" --engines wasmi --only int-payload/tiny corpus.json "$RUNNER_TEMP/float.wasm" > "$RUNNER_TEMP/float.log"; then cat "$RUNNER_TEMP/float.log"; echo "::error::Wasmi ran the module with a planted float instruction"; exit 1 fi grep -q "does not compile" "$RUNNER_TEMP/float.log" || { cat "$RUNNER_TEMP/float.log"; echo "::error::the planted float module failed for another reason"; exit 1; } for e in cranelift winch wasmi; do if "$H" --engines "$e" --only int-payload/tiny corpus.json "$RUNNER_TEMP/relaxed.wasm" > "$RUNNER_TEMP/relaxed.log"; then cat "$RUNNER_TEMP/relaxed.log"; echo "::error::$e ran the module with a planted relaxed instruction"; exit 1 fi grep -q "does not compile" "$RUNNER_TEMP/relaxed.log" || { cat "$RUNNER_TEMP/relaxed.log"; echo "::error::the planted relaxed module failed on $e for another reason"; exit 1; } echo "$e: the module with a planted relaxed instruction does not compile" done echo "wasmi: the module with a planted float instruction does not compile" browser: needs: relevant if: needs.relevant.outputs.run == 'true' name: the module of record in Chromium runs-on: linux timeout-minutes: 30 # Playwright 1.60.0's own image, for its Chromium and Node; no package is installed. # Pinned by the digest of its linux/amd64 manifest (the linux runner is x86_64), the image # wai-vector.yml runs. container: image: mcr.microsoft.com/playwright:v1.60.0-noble@sha256:83192064c7510f7ee73dd63dc5f22a5e01a92c81a2e6a9c715d9e3fe55471fd9 env: # The image runs as root, and a browser that finds HOME owned by another user refuses # to start. HOME: /root steps: - uses: actions/checkout@v4 - name: The DRED weights, fetched and checked against the draft's digest shell: bash run: bash wai/live-conformance/dred/fetch.sh "$RUNNER_TEMP/dred" - name: Every case in a page's worker, the module of record shell: bash working-directory: wai/wai-int-module run: | set -euo pipefail B=$(ls -d /ms-playwright/chromium-*/chrome-linux*/chrome | head -1) "$B" --version node browser/run-browser.mjs --browser "$B" --external "$RUNNER_TEMP/dred" corpus.json \ record/wai_int.wasm record/wai_int.simd128.wasm