diff --git a/.github/workflows/repo-checks.yml b/.github/workflows/repo-checks.yml index c1a71cd09..81791ead5 100644 --- a/.github/workflows/repo-checks.yml +++ b/.github/workflows/repo-checks.yml @@ -87,6 +87,14 @@ jobs: if: ${{ !cancelled() }} run: ./scripts/pr-touches-paths-selftest.sh + # ── One pinned wasmtime, run with both determinism settings ───────────── + - name: "workflow hygiene: the wasmtime pin check fails closed (self-test)" + if: ${{ !cancelled() }} + run: bash scripts/check-wasmtime-pin-selftest.sh + - name: "workflow hygiene: every wasmtime is the pinned release, run with both determinism settings" + if: ${{ !cancelled() }} + run: python3 -I scripts/check-wasmtime-pin.py + # ── Code cites no section its SPEC lacks; WAI's cited sections exist ──── - name: "spec references: the check can fail (self-test)" if: ${{ !cancelled() }} @@ -108,6 +116,11 @@ jobs: - name: "public text: WAI's public text names no comparison" if: ${{ !cancelled() }} run: bash scripts/check-comparative-prose.sh + # The maintainers' product names are public, held in the script itself: this run + # reads no secret, so it checks every change, a pull request included. + - name: "public text: WAI's public text names no product of its maintainers" + if: ${{ !cancelled() }} + run: bash scripts/check-public-names.sh --maintainer-products-only # The pattern list is a secret, never given to pull-request code: the check runs # on the push to main. - name: "public text: WAI's public text names no company or product (push to main)" diff --git a/.github/workflows/wai-breaking.yml b/.github/workflows/wai-breaking.yml index 8fe49ec75..93d907ce9 100644 --- a/.github/workflows/wai-breaking.yml +++ b/.github/workflows/wai-breaking.yml @@ -11,9 +11,13 @@ name: WAI breaking changes and the conformance runner # the room service's OpenAPI document). # - runner: the tests of `wai breaking` (each kind of break reported and failing until a # changelog entry names it) and of `wai conform` (the reference implementations conform, a -# changed verdict or output byte fails, a changed record is refused by `wai verify`); then -# `wai conform` runs the corpora's independent Python verifiers and the reference packager, -# and `wai verify` checks every record those runs wrote. +# changed verdict or output byte fails, a changed record is refused by `wai verify`, and +# `wai verify --conformant` admits a passing run of the native sink and refuses a planted +# failing one); then `wai conform` runs the corpora's independent Python verifiers and the +# reference packager, and `wai verify` checks every record those runs wrote; and it runs the +# native sink, through its module and its C interface, and the score decoder, each record +# admitted against this checkout's corpus and a planted failing sink refused +# (conformance-results §4.1). # # Push filters match the push's delta, and the `relevant` job gates the work from the pull # request's own diff (scripts/pr-touches-paths.py, reading the list below), as wai-pack.yml @@ -128,15 +132,18 @@ jobs: git config --global --add safe.directory "$GITHUB_WORKSPACE" git config --global user.email ci@example.invalid git config --global user.name ci - cargo test --locked --no-default-features --features quickstart,score,key_discovery \ - --bin wai --test cli_breaking --test cli_conform + cargo test --locked --no-default-features --features quickstart,score,key_discovery,native_sink \ + --bin wai --test cli_breaking --test cli_conform --test cli_conform_sinks - name: Build wai and the reference packager shell: bash run: | set -euo pipefail out() { (cd "$1" && cargo metadata --format-version 1 --no-deps --locked | python3 -c 'import json,sys; print(json.load(sys.stdin)["target_directory"])'); } mkdir -p "$RUNNER_TEMP/bin" - (cd wai/wai-rs && cargo build --locked --no-default-features --features quickstart --bin wai) && cp "$(out wai/wai-rs)/debug/wai" "$RUNNER_TEMP/bin/" + # The test step's features, so cargo reuses what it built. + (cd wai/wai-rs && cargo build --locked --no-default-features --features quickstart,score,key_discovery,native_sink \ + --bin wai --bin wai_native_sink_vectors) + cp "$(out wai/wai-rs)/debug/wai" "$(out wai/wai-rs)/debug/wai_native_sink_vectors" "$RUNNER_TEMP/bin/" (cd wai/wai-pack && cargo build --locked --bin wai-pack) && cp "$(out wai/wai-pack)/debug/wai-pack" "$RUNNER_TEMP/bin/" # The second implementations of the claim, JWP and key-discovery corpora, written from the # extension texts and sharing no code with wai-rs, run through the conformance runner as @@ -156,3 +163,38 @@ jobs: "$w" conform packager --suite policy --text --root wai \ --impl "$RUNNER_TEMP/bin/wai-pack policy-verdict {in}" --out "$d/policy.wai-conform.json" "$w" verify "$d" + # The native sink through the conformance runner, as another implementation would be run: + # through its Rust module and through the C interface its platform integrations link; and + # the score decoder. Each run must be conformant, and `wai verify + # --conformant` must admit each record against this checkout's corpus. A planted sink that + # presents an object whose digest does not match must be refused: its run fails, its record + # still verifies, and admission refuses it (not_conformant). + - name: wai conform with the native sink and the score decoder, each record admitted, a planted failing sink refused + shell: bash + run: | + set -euo pipefail + w="$RUNNER_TEMP/bin/wai"; s="$RUNNER_TEMP/bin/wai_native_sink_vectors"; d="$RUNNER_TEMP/sinks"; mkdir -p "$d" + "$w" conform sink --suite native-sink --text --root wai --impl "$s answers {case}" --out "$d/native-sink.wai-conform.json" + "$w" conform sink --suite native-sink --text --root wai --impl "$s answers --c-abi {case}" --out "$d/native-sink-c-abi.wai-conform.json" + "$w" conform decoder --suite score --text --root wai --impl "$w score render {in} --pcm {out}" --out "$d/score.wai-conform.json" + "$w" verify --conformant --root wai "$d" + # The planted sink's run must fail as a run (exit 1), not as a usage error, a missing + # program or an adapter that does not answer, and on the case it tampers with; its + # record must be refused at rule 2, not at another. + p="$RUNNER_TEMP/planted"; mkdir -p "$p" + planted="$s answers {case} | sed '/object_digest_mismatch/s/\"present\":false/\"present\":true/'" + set +e + "$w" conform sink --suite native-sink --text --root wai --impl "$planted" --out "$p/planted.wai-conform.json" > "$RUNNER_TEMP/planted-run.txt" 2>&1 + c=$? + set -e + cat "$RUNNER_TEMP/planted-run.txt" + [ "$c" = 1 ] || { echo "the planted failing sink: wai conform exited $c, not 1"; exit 1; } + grep -q 'tampered-fragment' "$RUNNER_TEMP/planted-run.txt" || { echo "the planted failing sink: tampered-fragment is not a failed case"; exit 1; } + "$w" verify "$p" + set +e + "$w" verify --conformant --root wai "$p" > "$RUNNER_TEMP/planted-admit.txt" 2>&1 + c=$? + set -e + cat "$RUNNER_TEMP/planted-admit.txt" + [ "$c" = 1 ] || { echo "the planted failing sink: wai verify --conformant exited $c, not 1"; exit 1; } + grep -q 'FAIL admission rule 2 not_conformant' "$RUNNER_TEMP/planted-admit.txt" || { echo "the planted failing sink was not refused at rule 2"; exit 1; } diff --git a/.github/workflows/wai-byte-equality.yml b/.github/workflows/wai-byte-equality.yml index 16f3c1580..5cb0a6ab3 100644 --- a/.github/workflows/wai-byte-equality.yml +++ b/.github/workflows/wai-byte-equality.yml @@ -164,11 +164,74 @@ jobs: # Windows x86_64 leg removed 2026-09-30: runner offline. Restore by # re-adding `- { os: windows, label: windows-x86_64 }` here once the # runner is back online. + # The two disk steps below are bash, and skip on Windows. include: - { os: linux, label: linux-x86_64 } - { os: linux-arm64, label: linux-aarch64 } - { os: macos, label: macos-arm64 (reference) } + env: + # The floor of the disk check below, in GiB. The leg writes under 1 GiB (a + # shallow checkout of about 0.3 GiB plus its pack, and a release target under + # 0.1 GiB, measured 2026-11-03), and a cold toolchain install about 1 GiB more + # under HOME; the rest is room for the jobs that share the disk. Measured with the + # step's own loop on 2026-11-04, every label had 50 GiB or more free under all + # four directories, so the floor fails a leg only on a host within a few GiB of + # full. The macOS runner's HOME and TMPDIR sit on its internal disk, which has + # gone from 7 GiB free to 118 MiB within hours, and at that level its jobs failed + # writing under HOME. + DISK_FLOOR_GIB: '4' steps: + # Infrastructure first, before the checkout writes anything. Main's run 17676 + # failed on both arm64 legs with "No space left on device", linux-aarch64 in + # `git fetch` and macOS in the toolchain's temporary files: the hosts' disks were + # full and no fixture was decoded, yet the matrix read as a byte-equality failure. + # This step measures the free space under every directory the leg writes to (the + # workspace, the runner's temporary directory, TMPDIR, and HOME, where the + # toolchain lives), and writes and syncs 32 MiB once on each filesystem, which a + # disk out of inodes or remounted read-only fails though df shows room. Below the + # floor, or on a write refused for space, an I/O error or a read-only filesystem, + # it fails, and its name and its error say infrastructure. + # + # On linux-aarch64 the four directories are on the runner VM's data disk, so df + # reads the guest's free space, not the host volume's. The disk is an image file + # on that volume, and on 2026-11-04 all but 0.7 of its 200 GiB were already + # allocated there, so a full host volume could take back at most that much; the + # write probe catches the rest. + # + # The forge still reports the leg's own status context as failed (`wai + # cross-architecture byte-equality /