A payload carries its own tables, so a fully valid 3 KB WIV1 decodes a 2^30-byte clip, and a 384-byte WIA1 held gigabytes to present one sample. The stream's length does not bound the work; the header does, within the caps, and a sink applies its own size policy before decoding. - int_payload::declared_cost(cap, payload, params): the output bytes, the symbols, and the most bytes the reference decode holds at once beside the payload and the parsed set, from the header and the set's layer geometry, with the refusals a decode gives before its first symbol. container::declared_size reads the header alone (no feature, no set); the C ABI has wai_int_payload_declared (wai_int_declared_t) and wai-web intPayloadCost. - Each decoder's pre-decode checks are one plan function the decode and the cost share (cond_plan, audio_plan, splat_plan, int_video::check); networks are planned with their live buffer sizes (plan_net). Latents and frames grow to their declared size and no further, and spent buffers are dropped, so the declared figure is what the decode holds. - WIA1: the latent must be the one t_out needs: the synthesis of lat_len gives at least t_out samples and that of lat_len - 1 fewer (geometry_mismatch). Fixture wia1_latent_too_long. - integer-payloads.md §7 states the bound: output, symbols and buffers with their bytes per element, read before decoding; a short stream stops at its first missing symbol; a sink's policy refuses past what it will spend. The claim that work grows with what a stream carries is gone, here and in the CHANGELOG. Tests: tests/int_payload_cost.rs (own binary, live-bytes allocator; CI fast-kernel steps): the declared working bytes bound what each committed decode holds and equal it for keyframe-0 WIV1, including, in release, the 3 KB clip at the cap (declared and held both 1073445624 bytes); tests/int_payload_preflight.rs refuses the reviewer's 384-byte WIA1 (geometry_mismatch, before a symbol, and by declared_cost); ffi_envelope::int_payload_declared_reads_the_header; wai-web the_declared_cost_is_read_before_decoding. Co-Authored-By: Claude Opus 5.5 <[email protected]>
523 lines
30 KiB
YAML
523 lines
30 KiB
YAML
name: WAI conformance
|
|
|
|
# WAI's load-bearing claim is bit-exact reconstruction on every machine,
|
|
# no tolerance parameter. This workflow enforces it mechanically: every
|
|
# cargo-class corpus — and the integer-exact neural decoders, which make the
|
|
# same promise (the registry's NeuralIntegerExact class: i64-only, no float
|
|
# ONNX) — is re-derived on every OS/arch leg of the matrix below (x86-64 and
|
|
# arm64) and must reproduce its frozen BLAKE3 hashes; and the integer
|
|
# byte-equality goldens (rANS / int_synth / JPEG-AI mANS, generated once on
|
|
# a reference machine) must decode identically everywhere. All of it is pure
|
|
# Rust (no C codec chain, no ONNX Runtime), so the matrix needs no system
|
|
# dependencies.
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'wai/wai-rs/**'
|
|
# wai-rs path-depends on wai-quantum, and the quantum corpora below are
|
|
# verified through it: a change there changes what this workflow checks.
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/*-conformance/**'
|
|
- 'wai/byte-exact-conformance/**'
|
|
# The registry export and the two library tests that read files outside
|
|
# wai-rs (the codec glossary, SPEC.md) must fire this workflow too: a
|
|
# hand edit of an exported file, of SPEC §5 or of the glossary is checked
|
|
# here. vocab/v1's and v2's pin terms are checked by a library test.
|
|
- 'wai/registry/**'
|
|
- 'wai/vocab/**'
|
|
- 'wai/glossary/**'
|
|
- 'wai/SPEC.md'
|
|
- 'wai/REGISTRY.md'
|
|
# A library test checks SPEC §5's pinned integer payloads against this
|
|
# extension's sections, so an edit of it is checked here too.
|
|
- 'wai/extensions/integer-payloads.md'
|
|
- 'wai/wai-web/**'
|
|
- '.github/workflows/wai-conformance.yml'
|
|
pull_request:
|
|
paths:
|
|
- 'wai/wai-rs/**'
|
|
# wai-rs path-depends on wai-quantum, and the quantum corpora below are
|
|
# verified through it: a change there changes what this workflow checks.
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/*-conformance/**'
|
|
- 'wai/byte-exact-conformance/**'
|
|
# The registry export and the two library tests that read files outside
|
|
# wai-rs (the codec glossary, SPEC.md) must fire this workflow too: a
|
|
# hand edit of an exported file, of SPEC §5 or of the glossary is checked
|
|
# here. vocab/v1's and v2's pin terms are checked by a library test.
|
|
- 'wai/registry/**'
|
|
- 'wai/vocab/**'
|
|
- 'wai/glossary/**'
|
|
- 'wai/SPEC.md'
|
|
- 'wai/REGISTRY.md'
|
|
# A library test checks SPEC §5's pinned integer payloads against this
|
|
# extension's sections, so an edit of it is checked here too.
|
|
- 'wai/extensions/integer-payloads.md'
|
|
- 'wai/wai-web/**'
|
|
- '.github/workflows/wai-conformance.yml'
|
|
|
|
# No global `shell:` default. The Windows runner is a host executor whose
|
|
# `bash` is the WSL stub (a different OS), so shell-specific steps below pick
|
|
# their shell per-OS: bash on unix, pwsh on Windows. Bare `cargo …` steps take
|
|
# each runner's native default, which runs cargo identically either way. The
|
|
# Windows legs are out of the matrices for now (see the comment on each matrix);
|
|
# their pwsh steps stay, inactive, so restoring a leg is a one-line change.
|
|
|
|
jobs:
|
|
cargo-classes:
|
|
name: cargo-class corpora · ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Self-hosted fleet labels. Both architectures: x86_64 by linux, arm64
|
|
# by linux-arm64 + macos — what matters for the Fx integer floor is the
|
|
# arch, not the OS. No Intel-Mac runner exists in the fleet, and it
|
|
# would add no arch coverage anyway.
|
|
# Windows x86_64 leg removed 2026-09-30: runner offline. Restore by
|
|
# re-adding `windows` here once the runner is back online.
|
|
os: [linux, linux-arm64, macos]
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
# unix: the docker runners (linux / linux-arm64) ship no Rust, so rustup
|
|
# is bootstrapped; the macOS `host` runner has it but launchd's PATH omits
|
|
# ~/.cargo/bin. dtolnay/rust-toolchain is unusable — it calls a `rustup`
|
|
# the docker image lacks.
|
|
- name: Install Rust 1.98.0 (unix)
|
|
if: matrix.os != 'windows'
|
|
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.98.0
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
rustup component add --toolchain 1.98.0 clippy
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
# Windows: a host executor with rustup already installed. Only ensure the
|
|
# pinned toolchain is present + default. pwsh, never bash (that is WSL here).
|
|
- name: Install Rust 1.98.0 (Windows)
|
|
if: matrix.os == 'windows'
|
|
shell: pwsh
|
|
run: |
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
|
|
- name: Build the cargo classes (pure Rust, no C codec chain)
|
|
working-directory: wai/wai-rs
|
|
# neural_int joins the pure-Rust set: the integer-synthesis decoder is
|
|
# i64-only (no ONNX, no float), so it carries the same bit-exact promise
|
|
# and is checkable on this matrix with no ONNX Runtime present. receipt_claims
|
|
# is in the set because the reference meters (wai_meter, wai_world_meter) write a
|
|
# measurement report by default and require it: without it they would drop out
|
|
# of this build on every leg of this matrix, without a word.
|
|
run: cargo build --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,receipt_claims
|
|
- name: Library unit tests (the fixed-point determinism floors)
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --lib --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,oer,receipt_claims,key_discovery
|
|
# The JPEG AI exact decoder reproduces across platforms only if no platform math
|
|
# library is on its path. Two guards, each failing the step: clippy's
|
|
# disallowed-methods (wai-rs/clippy.toml), which each module on the decode path
|
|
# denies, rejects a listed float method however it is spelled; and
|
|
# tests/jpegai_decode_symbols.rs lists the linked decoder's symbols with `nm` and
|
|
# rejects any C math-library function it imports, whatever made the call, and any
|
|
# it defines other than the round-to-integral ones (see its doc). `-A clippy::all`
|
|
# keeps the output to that guard. Unix legs only: `nm` is not on the Windows
|
|
# runner, and for clippy the unix legs already cover both architectures.
|
|
- name: JPEG AI exact decode calls no platform math library (unix)
|
|
if: matrix.os != 'windows'
|
|
shell: bash
|
|
working-directory: wai/wai-rs
|
|
run: |
|
|
set -euo pipefail
|
|
cargo clippy --lib --no-default-features --features neural_int -- -A clippy::all
|
|
cargo test --no-default-features --features world,audio_scene,haptic,splat4d,score,provenance,neural_int,film --test jpegai_decode_symbols
|
|
|
|
# The integer decoders run fast kernels (src/int_kernels.rs) that must give
|
|
# the same integer as the scalar reference kernels for every output element.
|
|
# The feature list above leaves out audio_int, video_int, world_int and
|
|
# splat_int, so without these two steps int_audio's kernel-equivalence tests
|
|
# and tests/int_kernels_vectors.rs (every committed integer-decoder vector
|
|
# decoded under the reference and under each fast policy, against its frozen
|
|
# hash) would run nowhere. `--lib` also carries the other kernels' equivalence
|
|
# modules; tests/int_kernels_geometry.rs runs edge geometry (strides up to
|
|
# usize::MAX, padding far beyond the kernel) through the public decoders
|
|
# under every policy. Both profiles, because the overflow-parity tests assert
|
|
# different things in each: with overflow checks on (dev) that the fast path panics
|
|
# where the reference panics, with them off (release) that it returns the
|
|
# same integers. All pure Rust, so every leg runs them.
|
|
# tests/int_mlicpp.rs decodes the committed wai.neural.int_mlicpp vector against
|
|
# its pinned hashes (image, every scale bucket, every symbol) under every kernel
|
|
# policy and thread count, and checks that damaged payloads are refused rather than
|
|
# overflowing — which is why it runs in both profiles too.
|
|
# tests/int_mlicpp_preflight.rs (its own binary: it installs a counting global
|
|
# allocator) checks that a header the model cannot fit is refused before the
|
|
# decode allocates anything sized from it.
|
|
# tests/int_audio.rs and tests/int_splat.rs decode the committed wai.audio.int_codec and
|
|
# wai.splat.int_codec vectors against the hashes the Python integer reference computed at
|
|
# export, and check each vector's metadata. `--lib` runs int_payload's unit tests: each
|
|
# binary payload (WIV1, WIH1, WIA1, WIS1) against the JSON it is converted from, under
|
|
# every kernel policy, and decode_int for every integer capability in this build, which
|
|
# has no `neural`. tests/int_payload.rs refuses every fixture of int-payload-conformance
|
|
# with its code, every strict prefix of every payload, and runs a byte-change sweep in
|
|
# which nothing may panic; tests/int_payload_preflight.rs (its own binary, a counting
|
|
# allocator) checks that a header past the caps is refused before anything sized from it
|
|
# is allocated; tests/int_payload_cost.rs (its own binary, a live-bytes allocator) checks
|
|
# that int_payload::declared_cost bounds what each decode holds, and, in the release
|
|
# step only, decodes a 2^30-byte clip a 3 KB payload codes. Cargo.toml declares them, and the other
|
|
# feature-gated targets named here, with required-features, so if this step ever loses a
|
|
# feature, cargo stops with an error instead of compiling an empty binary that reports ok.
|
|
# Each committed vector's decoded output is also checked against the SHA-256 in
|
|
# its sha256.json sidecar (SPEC §7 *Digests*), and
|
|
# int_kernels_vectors::every_decoded_output_states_a_sha256 requires a sidecar,
|
|
# or a named exclusion, for every corpus directory. tests/generate.rs checks the
|
|
# wai.generate.spectral vector, which `generate` enables.
|
|
- name: Fast integer kernels ≡ reference kernels (overflow checks on)
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int,generate --lib --test int_kernels_vectors --test int_kernels_geometry --test int_mlicpp --test int_mlicpp_preflight --test int_audio --test int_splat --test generate --test int_payload --test int_payload_preflight --test int_payload_cost
|
|
- name: Fast integer kernels ≡ reference kernels (release, overflow checks off)
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --release --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int,generate --lib --test int_kernels_vectors --test int_kernels_geometry --test int_mlicpp --test int_mlicpp_preflight --test int_audio --test int_splat --test generate --test int_payload --test int_payload_preflight --test int_payload_cost
|
|
# The integer decode path builds under each of its features alone, so a sink can take
|
|
# one medium without the others, and for wasm32 (a browser sink); `int_payload` arms a
|
|
# medium only under its feature, and none needs `neural`.
|
|
- name: Each integer feature alone, and wasm32 (unix)
|
|
if: matrix.os != 'windows'
|
|
shell: bash
|
|
working-directory: wai/wai-rs
|
|
run: |
|
|
set -euo pipefail
|
|
for f in neural_int video_int audio_int splat_int; do
|
|
cargo check --lib --no-default-features --features "$f"
|
|
done
|
|
rustup target add --toolchain 1.98.0 wasm32-unknown-unknown
|
|
cargo check --lib --target wasm32-unknown-unknown --no-default-features --features video_int,audio_int,splat_int
|
|
# carriage: every registered capability round-trips byte-exact. cli_wrap_intent and
|
|
# cli_registry run the `wai` binary, which builds without the codecs feature: the
|
|
# intent rule of `wai wrap`, its refusal of candidate capabilities (SPEC §5), its media
|
|
# class, and `wai registry export --check` on the tree and on a drifted copy.
|
|
# tests/manifest_builders.rs: the manifest types are #[non_exhaustive], and the
|
|
# builders write the JSON a struct literal wrote; members the types keep only
|
|
# as `extra` (and `security`) survive a round trip.
|
|
- name: Carriage conformance and the wai CLI (wrap, registry export)
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --no-default-features --test carriage --test manifest_builders --test cli_wrap_intent --test cli_registry
|
|
# The machine-readable registry (wai/registry/, wai/vocab/v2.*, the table in
|
|
# wai/REGISTRY.md) is generated from wai-rs/src/codecs/registry.rs. Regenerate it in
|
|
# memory and fail on any difference; the message says how to regenerate. One leg: the
|
|
# export is the same text on every platform.
|
|
- name: The registry export is up to date (linux)
|
|
if: matrix.os == 'linux'
|
|
working-directory: wai/wai-rs
|
|
run: cargo run -q --no-default-features --bin wai -- registry export --check
|
|
# The C ABI's envelope surface builds with no codec library (feature `ffi`):
|
|
# unpack returns each manifest as the envelope carries it, the WAI2 table carries
|
|
# every component's identity and selectability, wai_envelope_select follows
|
|
# SPEC §7.1 and never picks a candidate, and the packers refuse a candidate
|
|
# (SPEC §5). Cargo.toml declares the target with required-features.
|
|
- name: C ABI envelope surface (no codec library)
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --no-default-features --features ffi --test ffi_envelope
|
|
# The browser crate wraps the same envelope types (wai::container), so role,
|
|
# companion_of, component identity and the pin reach JS, and its pick is SPEC
|
|
# §7.1's. Its tests target the pure-Rust half (`core`), which runs natively; one
|
|
# leg suffices, the logic is architecture-independent. The JS surface itself runs
|
|
# under wasm32 in wai-web-wasm.yml.
|
|
- name: wai-web envelope surface (native tests)
|
|
if: matrix.os == 'linux'
|
|
working-directory: wai/wai-web
|
|
run: cargo test --locked
|
|
# jwp-receipts §7.1, §7.8: no `did:web`/`did:key` literal in a tracked .rs, .json or
|
|
# .js file under wai/ names a real web origin — every key the tree signs with has a
|
|
# published seed. Ungated: it reads the tree through `git ls-files` and classifies
|
|
# with `signer_id`, which builds with no feature.
|
|
- name: Every signer id in the tree is a label
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --no-default-features --test signer_ids_are_labels
|
|
# jwp-receipts §7: `wai-keys` builds a key log from operator-supplied seeds, appends
|
|
# revocations and rotations, signs statuses and module grants, verifies a log as
|
|
# §7.3 anchors one, and checks a DID document against it. The test drives the binary.
|
|
- name: wai-keys — build, check and publish an origin key log
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --no-default-features --features key_discovery --test wai_keys_cli
|
|
# key_log has no I/O, clock or threads, so a browser sink could run it before it
|
|
# instantiates a module (§7.9); no browser sink does yet. This step checks that it
|
|
# builds for wasm32 on the unix legs (the target is added to the pinned toolchain
|
|
# here; the Windows host runner is not set up for it).
|
|
- name: key_log builds for wasm32 (unix)
|
|
if: matrix.os != 'windows'
|
|
shell: bash
|
|
working-directory: wai/wai-rs
|
|
run: |
|
|
set -euo pipefail
|
|
rustup target add --toolchain 1.98.0 wasm32-unknown-unknown
|
|
cargo check --lib --target wasm32-unknown-unknown --no-default-features --features key_discovery
|
|
|
|
# The corpus-verify loop is genuinely shell-specific (a helper that groups
|
|
# log output and propagates the first non-zero exit), so it ships once per
|
|
# shell family. The command it runs is identical; only the wrapper differs.
|
|
- name: Every cargo-class corpus reproduces its frozen hashes (unix)
|
|
if: matrix.os != 'windows'
|
|
shell: bash
|
|
working-directory: wai/wai-rs
|
|
run: |
|
|
set -euo pipefail
|
|
F=world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,quantum,quantum_ops,oer,receipt_claims,key_discovery,video_int,audio_int,splat_int
|
|
v() { echo "::group::$1"; cargo run -q --no-default-features --features "$F" --bin "$2" -- verify "$3"; echo "::endgroup::"; }
|
|
v worlds wai_world_vectors ../world-conformance
|
|
v spatial-audio wai_audio_vectors ../audio-conformance
|
|
v haptics wai_haptic_vectors ../haptic-conformance
|
|
v state-feeds wai_feed_vectors ../feed-conformance
|
|
v avatars wai_avatar_vectors ../avatar-conformance
|
|
v volumetric wai_splat4d_vectors ../volumetric-conformance
|
|
v score wai_score_vectors ../score-conformance
|
|
v int-synth wai_int_synth_vectors ../neural-conformance
|
|
v film wai_film_vectors ../film-conformance
|
|
v quantum wai_quantum_vectors ../quantum-conformance
|
|
v quantum-ops wai_quantum_ops_vectors ../quantum-ops-conformance
|
|
v oer wai_oer_vectors ../oer-conformance
|
|
v jwp wai_jwp_vectors ../jwp-conformance
|
|
v claims wai_claim_vectors ../claim-conformance
|
|
v pin wai_pin_vectors ../pin-conformance
|
|
v signers wai_signer_vectors ../signer-conformance
|
|
v int-payload wai_int_payload_vectors ../int-payload-conformance
|
|
# The pin corpus's second implementation: Python standard library only, sharing no
|
|
# code with wai-rs. One leg is enough — it checks digests and listing rules, which
|
|
# do not depend on the architecture — and the macOS host has python3.
|
|
- name: The pin corpus checks against an independent verifier (macOS)
|
|
if: matrix.os == 'macos'
|
|
shell: bash
|
|
working-directory: wai
|
|
run: python3 pin-conformance/pin_verify.py pin-conformance
|
|
# OER's second implementation is portable C, not Rust. Rebuild it from source and
|
|
# require its output to match the pinned corpus byte for byte: the kernel is
|
|
# deterministic, and wai_oer_vectors above has already verified the pinned copy,
|
|
# so equality carries that verification to what the source produces today.
|
|
# `cc` with the Makefile's flags, so the step needs no `make` on the runner.
|
|
- name: OER C kernel reproduces its pinned receipts (unix)
|
|
if: matrix.os != 'windows'
|
|
shell: bash
|
|
working-directory: wai/oer-conformance/settle
|
|
run: |
|
|
set -euo pipefail
|
|
cc -O2 -std=c99 -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare \
|
|
-o "$RUNNER_TEMP/settle_host" host_main.c settle.c sha256.c tweetnacl.c -lm
|
|
"$RUNNER_TEMP/settle_host" "$RUNNER_TEMP/firmware_vectors.json" 400
|
|
cmp "$RUNNER_TEMP/firmware_vectors.json" ../firmware_vectors.json
|
|
- name: Every cargo-class corpus reproduces its frozen hashes (Windows)
|
|
if: matrix.os == 'windows'
|
|
shell: pwsh
|
|
working-directory: wai/wai-rs
|
|
run: |
|
|
$F = "world,audio_scene,haptic,splat4d,score,provenance,neural_int,film,quantum,quantum_ops,oer,receipt_claims,key_discovery,video_int,audio_int,splat_int"
|
|
function v($grp, $bin, $path) {
|
|
Write-Output "::group::$grp"
|
|
cargo run -q --no-default-features --features $F --bin $bin -- verify $path
|
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
Write-Output "::endgroup::"
|
|
}
|
|
v worlds wai_world_vectors ../world-conformance
|
|
v spatial-audio wai_audio_vectors ../audio-conformance
|
|
v haptics wai_haptic_vectors ../haptic-conformance
|
|
v state-feeds wai_feed_vectors ../feed-conformance
|
|
v avatars wai_avatar_vectors ../avatar-conformance
|
|
v volumetric wai_splat4d_vectors ../volumetric-conformance
|
|
v score wai_score_vectors ../score-conformance
|
|
v int-synth wai_int_synth_vectors ../neural-conformance
|
|
v film wai_film_vectors ../film-conformance
|
|
v quantum wai_quantum_vectors ../quantum-conformance
|
|
v quantum-ops wai_quantum_ops_vectors ../quantum-ops-conformance
|
|
v oer wai_oer_vectors ../oer-conformance
|
|
v jwp wai_jwp_vectors ../jwp-conformance
|
|
v claims wai_claim_vectors ../claim-conformance
|
|
v pin wai_pin_vectors ../pin-conformance
|
|
v signers wai_signer_vectors ../signer-conformance
|
|
v int-payload wai_int_payload_vectors ../int-payload-conformance
|
|
|
|
# The generated v2 vocabulary (wai/vocab/v2.*) is checked as a consumer uses it:
|
|
# sample manifests, typed and untyped, WAI1 and WAI2, are expanded through the
|
|
# JSON-LD context exactly as written on the wire and validated against the SHACL
|
|
# shapes, each with the result it must give (a candidate in any place is
|
|
# rejected; a media value no revision lists is accepted). One leg: RDF tooling,
|
|
# not arithmetic. The tool versions are pinned.
|
|
vocab-shapes:
|
|
name: v2 vocabulary · manifests validate as stated
|
|
runs-on: linux
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
- name: Install the RDF tools
|
|
shell: bash
|
|
run: python -m pip install rdflib==7.6.0 PyLD==3.3.0 pyshacl==0.40.1
|
|
- name: Sample manifests against vocab/v2.shapes.ttl
|
|
shell: bash
|
|
run: python wai/vocab/check_shapes.py
|
|
|
|
# The corpora above are generated and verified by wai-rs, one implementation. These are
|
|
# the second implementations, written from the extension text in Python and sharing no
|
|
# code with wai-rs: claim_verify.py (every claim vector, the canonical fixture, and the
|
|
# bracket arithmetic of energy-measurement §6.2 recomputed with Python's integers),
|
|
# differential.py (both verifiers' verdicts on generated inputs the corpus does not hold,
|
|
# under a fixed seed, so a run is reproducible), jwp_verify.py (every JWP vector), and
|
|
# signer_verify.py (every key-discovery vector and the canonical fixture, with its
|
|
# verdicts required to equal wai_signer_vectors' line for line), and
|
|
# int_payload_verify.py (the integer payloads and their refusal fixtures).
|
|
# Each exits non-zero on any failure or any difference, and the step fails with it.
|
|
# One platform: what they check is the reading of the text, not the architecture.
|
|
independent-verifiers:
|
|
name: independent verifiers · claims, JWP, key discovery and integer payloads (Python)
|
|
runs-on: linux
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install Rust 1.98.0
|
|
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.98.0
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
# The verifiers check Ed25519's equation with the `cryptography` package and make the
|
|
# rest of jwp-receipts §3.1 step 3 themselves.
|
|
- name: Install the Ed25519 library
|
|
shell: bash
|
|
run: python -m pip install cryptography
|
|
|
|
# differential.py drives wai_claim_vectors' `verdicts` mode; the key-discovery
|
|
# verdicts are compared with wai_signer_vectors'.
|
|
- name: Build the corpus verifiers wai-rs ships
|
|
working-directory: wai/wai-rs
|
|
shell: bash
|
|
run: cargo build --no-default-features --features key_discovery --bin wai_claim_vectors --bin wai_jwp_vectors --bin wai_signer_vectors
|
|
|
|
# The integer payload corpus's second implementation (int-payload-conformance/README):
|
|
# it parses every payload with the extension's rules and check order, converts every
|
|
# JSON source independently and requires the committed bytes, decodes the WIV1
|
|
# keyframe-0 payloads in full to their sidecars' SHA-256, and checks every refusal
|
|
# fixture. Standard library only, so it needs nothing installed.
|
|
- name: int_payload_verify.py
|
|
working-directory: wai
|
|
shell: bash
|
|
run: python3 int-payload-conformance/int_payload_verify.py int-payload-conformance
|
|
- name: claim_verify.py, differential.py, jwp_verify.py, signer_verify.py
|
|
working-directory: wai
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 claim-conformance/claim_verify.py claim-conformance/vectors.json
|
|
python3 claim-conformance/differential.py "$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_claim_vectors" --random 2000 --seed 1
|
|
python3 jwp-conformance/jwp_verify.py jwp-conformance/vectors.json
|
|
python3 signer-conformance/signer_verify.py signer-conformance/vectors.json
|
|
python3 signer-conformance/signer_verify.py verdicts signer-conformance/vectors.json > "$RUNNER_TEMP/signer-py.tsv"
|
|
"$GITHUB_WORKSPACE/wai/wai-rs/target/debug/wai_signer_vectors" verdicts signer-conformance/vectors.json > "$RUNNER_TEMP/signer-rs.tsv"
|
|
diff "$RUNNER_TEMP/signer-py.tsv" "$RUNNER_TEMP/signer-rs.tsv"
|
|
|
|
byte-exact:
|
|
name: cross-arch byte-equality · ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Self-hosted fleet labels. Both architectures: x86_64 by linux, arm64
|
|
# by linux-arm64 + macos — what matters for the Fx integer floor is the
|
|
# arch, not the OS. No Intel-Mac runner exists in the fleet, and it
|
|
# would add no arch coverage anyway.
|
|
# Windows x86_64 leg removed 2026-09-30: runner offline. Restore by
|
|
# re-adding `windows` here once the runner is back online.
|
|
os: [linux, linux-arm64, macos]
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install Rust 1.98.0 (unix)
|
|
if: matrix.os != 'windows'
|
|
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.98.0
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Install Rust 1.98.0 (Windows)
|
|
if: matrix.os == 'windows'
|
|
shell: pwsh
|
|
run: |
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
|
|
- name: Integer rANS + int_synth + JPEG-AI mANS goldens (one machine → every machine)
|
|
working-directory: wai/byte-exact-conformance
|
|
run: cargo test --release
|
|
|
|
# The C2PA emitter is gated behind an off-by-default feature, so the four-platform
|
|
# job above — which builds a fixed feature list — never compiles it. A feature no
|
|
# workflow enables has no CI coverage at all: the suite passes, and the tests in it
|
|
# simply do not run.
|
|
#
|
|
# One platform, deliberately. Everything the matrix above exists to prove is about
|
|
# byte-identical reconstruction across architectures; a signed manifest makes no
|
|
# such claim and would not become more true for being emitted on four machines. What
|
|
# this job proves is that the manifest is still well-formed, still carries the three
|
|
# assertions, and still validates — which is architecture-independent.
|
|
c2pa-emitter:
|
|
name: C2PA manifest emission · signed, read back, validated
|
|
runs-on: linux
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust 1.98.0
|
|
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.98.0
|
|
rustup toolchain install 1.98.0 --profile minimal
|
|
rustup default 1.98.0
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
# `rust_native_crypto` rather than the SDK's default openssl backend, so this
|
|
# job needs no system libraries — the same property the matrix above depends on.
|
|
# Asserted, not assumed: an openssl-linked build would still pass the tests here
|
|
# while quietly making the crate undistributable to a bare runner.
|
|
- name: The emitter pulls in no system crypto
|
|
working-directory: wai/wai-rs
|
|
shell: bash
|
|
run: |
|
|
for dep in openssl openssl-sys; do
|
|
if cargo tree --no-default-features --features c2pa_emit -i "$dep" >/dev/null 2>&1; then
|
|
echo "::error::$dep reached the c2pa_emit dependency graph"
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "no system crypto in the graph"
|
|
|
|
- name: Emit, sign, read back, validate
|
|
working-directory: wai/wai-rs
|
|
run: cargo test --lib --no-default-features --features c2pa_emit c2pa_emit
|
|
|
|
# The feature must stay optional. If `provenance` ever pulls c2pa in, every
|
|
# consumer that wanted only the binding types inherits a large dependency tree
|
|
# they did not ask for, and the "off by default" claim in the extension is false.
|
|
- name: The feature stays optional
|
|
working-directory: wai/wai-rs
|
|
shell: bash
|
|
run: |
|
|
if cargo tree --no-default-features --features provenance -i c2pa >/dev/null 2>&1; then
|
|
echo "::error::c2pa is reachable from the provenance feature; it must stay opt-in"
|
|
exit 1
|
|
fi
|
|
cargo build --no-default-features --features provenance
|
|
echo "provenance builds without c2pa"
|