#!/usr/bin/env bash # Falsify the HTTP corpus tool: each patch here breaks one function of wai-rs. For each, # in a fresh worktree of HEAD: apply it, require the build to succeed, and require # `wai_http_vectors verify` to exit non-zero and to name every case the patch's first # line lists. Then the Python side: each `http_verify.py --mutate` must fail, and the # differential must verify every proof and refuse exactly the flipped ones. # # bash wai/http-conformance/falsify/run.sh [work-dir [patch-name…]] # # With patch names, only those patches run (and nothing else). # Run from the repository root. CARGO_TARGET_DIR, if set, is shared by the builds, which # need the features http and video_manifest (the playlist receipts). set -uo pipefail ROOT="$(git rev-parse --show-toplevel)" WORK="${1:-${RUNNER_TEMP:-/tmp}/wai-http-falsify}" shift || true ONLY="$*" mkdir -p "$WORK" fail=0 for patch in "$ROOT"/wai/http-conformance/falsify/*.patch; do name="$(basename "$patch" .patch)" if [ -n "$ONLY" ] && ! printf ' %s ' $ONLY | grep -q " $name "; then continue; fi wt="$WORK/f-$name" rm -rf "$wt" git -C "$ROOT" worktree add --detach --quiet "$wt" HEAD must="$(head -1 "$patch" | sed 's/^# must fail: //')" if ! git -C "$wt" apply "$patch"; then echo "::error::$name: the patch does not apply"; fail=1 elif ! (cd "$wt/wai/wai-rs" && cargo build --release --no-default-features --features http,video_manifest --bin wai_http_vectors) > "$WORK/$name.build.log" 2>&1; then echo "::error::$name: the patched tree does not build"; tail -20 "$WORK/$name.build.log"; fail=1 else bin="${CARGO_TARGET_DIR:-$wt/wai/wai-rs/target}/release/wai_http_vectors" "$bin" verify "$wt/wai/http-conformance" > "$WORK/$name.verify.log" 2>&1 rc=$? missing="" for c in $must; do grep -q "^FAIL $c:" "$WORK/$name.verify.log" || missing="$missing $c"; done if [ $rc -eq 0 ] || [ -n "$missing" ]; then echo "::error::$name: verify exited $rc; cases not failed:$missing"; fail=1 else echo "ok $name: verify exited $rc and failed$(printf ' %s' $must) ($(grep -c '^FAIL' "$WORK/$name.verify.log") failures)" fi fi git -C "$ROOT" worktree remove --force "$wt" done [ -n "$ONLY" ] && exit $fail cd "$ROOT/wai/http-conformance" for m in left-half no-root counter-zero floor-as-codecs blake3-iv base-at-done tick-noop refinement-unclipped \ pdt-ignored dseq-ignored parts-after-extinf average-floor render-digest-off name-unchecked chain-unchecked \ ilog2-no-interp bola-waits unlabelled-as-zero round-half-down small-order-key small-order-r \ rebind-uri rebind-sequence key-unchecked walk-unbounded reload-walked \ xml-char-unchecked xml-attribute-twice dash-start-ignored dash-timescale-ignored \ unlabelled-escapes abr-unbounded gap-carries receipt-duplicates receipt-surrogates session-data-anywhere \ dash-r-expanded xml-attributes-scanned dash-timelines-unbounded budget-raises \ uri-unresolved gap-withdraws reanchor-backwards walk-exceeded-wedges walk-name-unchecked walk-verify-unchecked bindings-unbounded \ file-numbers-unbounded nonconforming-offered conforming-withheld refines-read-whole; do if python3 http_verify.py . --mutate "$m" > "$WORK/py-$m.log" 2>&1; then echo "::error::http_verify.py --mutate $m passed"; fail=1 else echo "ok http_verify.py --mutate $m: $(grep -c '^FAIL' "$WORK/py-$m.log") failures" fi done # The differential runs the unpatched tool: build it again (the patched builds shared # its output path). (cd "$ROOT/wai/wai-rs" && cargo build --release --no-default-features --features http,video_manifest --bin wai_http_vectors) > "$WORK/unpatched.build.log" 2>&1 || fail=1 bin="${CARGO_TARGET_DIR:-$ROOT/wai/wai-rs/target}/release/wai_http_vectors" if [ -x "$bin" ]; then "$bin" diff . --seed 7 --count 500 --out "$WORK/diff.jsonl" > /dev/null || fail=1 python3 http_verify.py diff "$WORK/diff.jsonl" || fail=1 python3 http_verify.py diff "$WORK/diff.jsonl" --flip 10 --seed 3 || fail=1 else echo "::error::no release wai_http_vectors at $bin for the differential"; fail=1 fi exit $fail