Some checks failed
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 10s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m1s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Failing after 4m20s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 4m57s
The WAI site's list of conforming implementations (/conformance/) admits a record only when it verifies, names the pinned commit and toolchain, is admitted against that commit's corpus, is not signed by a published test key and names no local path. CI made no such record: the conformance runner job of wai-breaking.yml wrote its per-suite records to the runner's temporary folder, signed with keys made for their runs and naming the runner's paths, and uploaded none; wai-conformance.yml's independent-verifiers artefact holds whole-corpus records, which §4.1 rule 4 refuses. wai/quickstart/conformance-records.sh runs WAI's own implementations as that job does (the five independent verifiers, the reference packager, the native sink through its module and its C interface, the score renderer, the browser sink, the integer-synthesis decoder, a cache in front of the reference origin, and the reference relay at drafts 22, 18 and 16), each record naming <wai version>+<commit>, signed with the seed in WAI_CONFORMANCE_SEED and admitted by `wai verify --conformant`, and packs the 15 as wai-conformance-<label>.tar.gz (with MANIFEST.json: commit, standard, signer, each record's SHA-256) and its .sha256. The runs are made from a folder holding bin/ and a link to wai/, programs found through PATH's relative `bin`, so a record names bin/<program> and wai/<path>; a record holding a path under /Users/, /Volumes/, /home/, /private/ or /tmp/, or such a python3, stops it. The seed goes to a file only the script reads, removed on exit, and the variable is unset before anything runs. Without the seed: one notice, nothing written, exit 0. A seed that is not one, or a key conform-result-conformance publishes, stops it with nothing written. - wai-breaking.yml, runner job: the three refusals planted on every change; on a push to main the pack at the commit, kept as the artefact wai-conformance-records when the secret is set. - wai-release.yml: job conformance builds the programs at a wai-v* tag, runs and signs them (the seed in that step alone) and attaches wai-conformance-<version>.tar.gz and its .sha256 through publish.sh, to FORGE_API directly. Job setup reports whether WAI_CONFORMANCE_SEED is set, as for WAI_PACKAGES_TOKEN (cc1849097): without it one notice, and the job is skipped. - publish.sh: the release's description names the pack. Checked: PyYAML parses both workflows; check-workflow-concurrency.sh and its selftest, check-tests-in-ci.py and its selftest, check-wai-release-quickstart.py and its selftest, the changelog check, the public-name check with the private list and the other light checks of repo-checks.yml pass under bash. Proved end to end at this change (as f5038ea40, before the rebase onto8da651a54, which touches none of these files), with a throwaway key made on the Framework build host and deleted there: the script, run as the release job runs it, wrote 15 records, every one conformant, admitted against the corpus (areas trust 5, media 2, delivery 2, live 6), path-neutral (bin/<program>, wai/<path>, /usr/bin/python3) and signed by the key, packed with its SHA-256. The WAI site's sync (scripts/sync-conform.mjs, on the M3 Ultra) admitted all 15 as WAI's own by --records with --signer, and the same 15 by --release from a server laid out as the forge's release downloads; the built page held each (check-conform, and the page's e2e: 102 checks). Planted and caught: the script with no seed (one notice, nothing written, exit 0) and with the published test key (exit 1, nothing written); at the sync, a record naming a local path (check f), a record signed by the test key (check e, also with that key named as WAI's) and a pack whose .sha256 does not match (refused by --release). Co-Authored-By: Claude Opus 5.5 <[email protected]>
246 lines
12 KiB
Shell
Executable file
246 lines
12 KiB
Shell
Executable file
#!/usr/bin/env bash
|
|
# WAI's own implementations through the conformance runner, each run's record signed with WAI's
|
|
# key and packed for publication: a push to main keeps the pack as its run's artefact
|
|
# (wai-breaking.yml), and a wai-v* tag attaches it to the release (wai-release.yml), where the
|
|
# WAI site's list of conforming implementations fetches it by tag (its
|
|
# scripts/sync-conform.mjs --release <tag>) and admits each record.
|
|
#
|
|
# WAI_CONFORMANCE_SEED=<64 hexadecimal digits> \
|
|
# bash wai/quickstart/conformance-records.sh --bin <dir> --out <dir> [--commit <sha>] [--label <name>]
|
|
#
|
|
# --bin holds the programs it runs, built from this checkout: wai (with the features the
|
|
# conformance runner job of wai-breaking.yml builds), wai_native_sink_vectors,
|
|
# wai_browser_sink_vectors, wai_int_synth_vectors, wai-pack, wai-relay and joule-moq-interop.
|
|
# --commit is the commit the records name (default HEAD), --label the pack's name (default
|
|
# <wai version>+<the commit's first 12 digits>). It writes two files into --out:
|
|
#
|
|
# wai-conformance-<label>.tar.gz the folder wai-conformance-<label>/: one record a run
|
|
# (<run>.wai-conform.json) and MANIFEST.json, which
|
|
# names the commit, the standard, wai's version, the
|
|
# signer's public key and each record's file, kind,
|
|
# suite and SHA-256
|
|
# wai-conformance-<label>.tar.gz.sha256 its SHA-256, as `shasum -a 256` writes it
|
|
#
|
|
# The runs are the conformance runner job's: the corpora's independent verifiers (claim, jwp,
|
|
# signer, pq and conform-result), the reference packager's policy reader, the native sink
|
|
# through its module and through its C interface, the score renderer, the browser sink, the
|
|
# integer-synthesis decoder, a cache in front of the reference origin, and the reference relay
|
|
# at each draft it speaks. Each names its implementation's version <wai version>+<commit>, is
|
|
# signed with the seed (`"key": "supplied"`), and must be admitted by `wai verify --conformant`
|
|
# against this checkout's corpus.
|
|
#
|
|
# A list publishes what a record says (conformance-results §8), so the runs are made from a
|
|
# folder holding bin/ (a copy of --bin) and wai (a link to this checkout's wai/), each program
|
|
# found through PATH's relative entry `bin`: a record names bin/<program> and wai/<path>, never
|
|
# a path of the machine that ran it. A python3 found under /Users/, /Volumes/, /home/, /private/
|
|
# or /tmp/, or a record holding such a path anywhere, stops it: the list refuses those records
|
|
# (its check f).
|
|
#
|
|
# The seed is read from WAI_CONFORMANCE_SEED, written to a file only this user can read, removed
|
|
# when this exits, and never printed; the variable is unset before anything runs. Without it:
|
|
# one notice line, nothing written, exit 0, since a record signed with a key made for its run
|
|
# says nothing of who ran it. A seed that is not 64 hexadecimal digits, or one whose key is a
|
|
# test key conform-result-conformance publishes (which attests nothing), stops it.
|
|
#
|
|
# Exit 0 when the pack was written, or when no seed was given; 1 when a seed, a run, a check or
|
|
# the pack failed, with nothing written to --out; 2 for a usage error.
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
echo "usage: WAI_CONFORMANCE_SEED=<64 hexadecimal digits> bash wai/quickstart/conformance-records.sh --bin <dir> --out <dir> [--commit <sha>] [--label <name>]" >&2
|
|
exit 2
|
|
}
|
|
fail() {
|
|
echo "conformance-records: $*; nothing was written" >&2
|
|
exit 1
|
|
}
|
|
BIN= OUT= COMMIT= LABEL=
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--bin|--out|--commit|--label)
|
|
[ $# -ge 2 ] || usage
|
|
case "$1" in --bin) BIN=$2 ;; --out) OUT=$2 ;; --commit) COMMIT=$2 ;; --label) LABEL=$2 ;; esac
|
|
shift 2 ;;
|
|
*) usage ;;
|
|
esac
|
|
done
|
|
[ -n "$BIN" ] && [ -n "$OUT" ] || usage
|
|
case "$BIN" in /*) ;; *) BIN="$PWD/$BIN" ;; esac
|
|
case "$OUT" in /*) ;; *) OUT="$PWD/$OUT" ;; esac
|
|
ROOT=$(cd "$(dirname "$0")/../.." && pwd -P)
|
|
|
|
if [ -z "${WAI_CONFORMANCE_SEED:-}" ]; then
|
|
echo "::notice::the repository secret WAI_CONFORMANCE_SEED is not set: WAI's own conformance records are not signed with WAI's key, and none is published (a key made for a run says nothing of who ran it)"
|
|
exit 0
|
|
fi
|
|
|
|
W=$(mktemp -d "${TMPDIR:-/tmp}/wai-conformance.XXXXXX")
|
|
chmod 700 "$W"
|
|
relay=
|
|
cleanup() {
|
|
if [ -n "$relay" ]; then kill "$relay" 2>/dev/null || true; fi
|
|
rm -rf "$W"
|
|
}
|
|
trap cleanup EXIT
|
|
mkdir -m 700 "$W/key"
|
|
KEY="$W/key/seed"
|
|
( umask 077; printf '%s' "$WAI_CONFORMANCE_SEED" | tr -d ' \t\r\n' > "$KEY" )
|
|
unset WAI_CONFORMANCE_SEED
|
|
grep -Eq '^[0-9a-fA-F]{64}$' "$KEY" || fail "WAI_CONFORMANCE_SEED is not an Ed25519 seed (64 hexadecimal digits)"
|
|
|
|
# The seed's public key, which every record must name; and not a test key.
|
|
PUB=$(python3 -I - "$KEY" <<'PY'
|
|
import sys
|
|
try:
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
|
except ImportError:
|
|
sys.exit("conformance-records: python3 has no cryptography package (python3 -m pip install cryptography); nothing was written")
|
|
with open(sys.argv[1]) as f:
|
|
seed = bytearray(bytes.fromhex(f.read().strip()))
|
|
print(Ed25519PrivateKey.from_private_bytes(bytes(seed)).public_key().public_bytes(Encoding.Raw, PublicFormat.Raw).hex())
|
|
seed[:] = bytes(len(seed))
|
|
PY
|
|
)
|
|
[[ "$PUB" =~ ^[0-9a-f]{64}$ ]] || fail "the seed's public key could not be read"
|
|
if python3 -I -c 'import json,sys; sys.exit(0 if sys.argv[2] in json.load(open(sys.argv[1])).get("public_keys", []) else 1)' \
|
|
"$ROOT/wai/conform-result-conformance/vectors.json" "$PUB"; then
|
|
fail "WAI_CONFORMANCE_SEED holds a test key conform-result-conformance publishes ($PUB), which attests nothing"
|
|
fi
|
|
|
|
for p in wai wai_native_sink_vectors wai_browser_sink_vectors wai_int_synth_vectors wai-pack wai-relay joule-moq-interop; do
|
|
[ -x "$BIN/$p" ] || fail "--bin $BIN holds no program $p"
|
|
done
|
|
if [ -e "$OUT" ] && [ -n "$(ls -A "$OUT" 2>/dev/null)" ]; then fail "--out $OUT is not empty"; fi
|
|
COMMIT=${COMMIT:-$(git -C "$ROOT" rev-parse HEAD)}
|
|
[[ "$COMMIT" =~ ^[0-9a-f]{40}$ ]] || fail "--commit $COMMIT: not a commit's 40 hexadecimal digits"
|
|
WV=$(sed -n 's/^version = "\(.*\)"$/\1/p' "$ROOT/wai/wai-rs/Cargo.toml" | head -1)
|
|
[ -n "$WV" ] || fail "wai/wai-rs/Cargo.toml names no version"
|
|
VERSION="$WV+${COMMIT:0:12}"
|
|
LABEL=${LABEL:-$VERSION}
|
|
[[ "$LABEL" =~ ^[A-Za-z0-9][A-Za-z0-9.+_-]*$ ]] || fail "--label $LABEL: letters, digits and . + _ - only"
|
|
|
|
# The path-neutral folder the runs are made from.
|
|
S="$W/run"
|
|
R="$W/records"
|
|
mkdir -p "$S/bin" "$R"
|
|
for p in wai wai_native_sink_vectors wai_browser_sink_vectors wai_int_synth_vectors wai-pack wai-relay joule-moq-interop; do
|
|
cp "$BIN/$p" "$S/bin/"
|
|
done
|
|
ln -s "$ROOT/wai" "$S/wai"
|
|
cd "$S"
|
|
export PATH="bin:$PATH" WAI_MOQ_INTEROP_BIN=bin/joule-moq-interop
|
|
LOCAL='(^|[[:space:]"'"'"'`(=:,;[{<])/(Volumes|Users|private|tmp|home)/'
|
|
py=$(command -v python3) || fail "no python3 on PATH"
|
|
if [[ " $py" =~ $LOCAL ]]; then
|
|
fail "python3 is $py, a local path the records would name; put a python3 outside /Users/, /Volumes/, /home/, /private/ and /tmp/ first on PATH"
|
|
fi
|
|
echo "conformance-records: open-standards ${COMMIT:0:12}, wai $WV, signed by $PUB"
|
|
|
|
# conform <run> <kind> <suite> <name> <impl> [option...]
|
|
conform() {
|
|
local id=$1 kind=$2 suite=$3 name=$4 impl=$5
|
|
shift 5
|
|
if ! bin/wai conform "$kind" --suite "$suite" --text --root wai --impl "$impl" "$@" \
|
|
--name "$name" --version "$VERSION" --key "$KEY" --out "$R/$id.wai-conform.json" --yes > "$W/run.txt" 2>&1; then
|
|
cat "$W/run.txt"
|
|
fail "WAI's own run $id ($kind $suite) did not pass"
|
|
fi
|
|
echo "conformance-records: $id: $(grep -E '^wai conform' "$W/run.txt" | tail -1)"
|
|
}
|
|
for s in claim jwp signer pq conform-result; do
|
|
conform "$s" verifier "$s" "${s//-/_}_verify.py" "python3 -I wai/$s-conformance/${s//-/_}_verify.py verdicts {corpus}"
|
|
done
|
|
conform policy packager policy wai-pack "wai-pack policy-verdict {in}"
|
|
conform native-sink sink native-sink "wai native sink" "wai_native_sink_vectors answers {case}"
|
|
conform native-sink-c-abi sink native-sink "wai native sink, C interface" "wai_native_sink_vectors answers --c-abi {case}"
|
|
conform score decoder score "wai score render" "wai score render {in} --pcm {out}"
|
|
conform browser sink browser "wai browser sink" "wai_browser_sink_vectors answers {case}"
|
|
conform neural decoder neural "wai int_synth decoder" "wai_int_synth_vectors decode {model} {in} {out}"
|
|
conform cache cache cache "mutators.py, relay mode" "python3 -I wai/cache-conformance/mutators.py --mode relay --listen {port} --upstream {origin}"
|
|
# The reference relay on loopback, at each draft it speaks; another program already on its port
|
|
# stops the relay, and with it this, rather than having the client test that program.
|
|
bin/wai-relay --dev > "$W/relay.txt" 2>&1 &
|
|
relay=$!
|
|
for _ in $(seq 1 150); do
|
|
grep -q 'on udp 127.0.0.1:4443' "$W/relay.txt" && break
|
|
kill -0 "$relay" 2>/dev/null || break
|
|
sleep 0.2
|
|
done
|
|
grep -q 'on udp 127.0.0.1:4443' "$W/relay.txt" || { cat "$W/relay.txt"; fail "the reference relay did not start on udp 127.0.0.1:4443"; }
|
|
for d in 22 18 16; do
|
|
conform "moqt-$d" relay moqt wai-relay moqt://127.0.0.1:4443/moq --draft "$d" --tls-disable-verify
|
|
done
|
|
kill "$relay" 2>/dev/null || true
|
|
wait "$relay" 2>/dev/null || true
|
|
relay=
|
|
|
|
# Every record admitted against this checkout's corpus.
|
|
if ! bin/wai verify --conformant --root wai "$R" > "$W/admit.txt" 2>&1; then
|
|
cat "$W/admit.txt"
|
|
fail "wai verify --conformant refused a record"
|
|
fi
|
|
grep '^wai verify' "$W/admit.txt" | sed 's/^/conformance-records: /'
|
|
|
|
# Each record held to what the list admits, then the pack.
|
|
mkdir -p "$W/pack"
|
|
python3 -I - "$R" "$W/pack" "$LABEL" "$COMMIT" "$PUB" "$VERSION" "$WV" "$LOCAL" <<'PY'
|
|
import gzip, hashlib, io, json, os, re, sys, tarfile
|
|
rec_dir, pack, label, commit, pub, version, wv, local = sys.argv[1:9]
|
|
LOCAL = re.compile(local.replace("[:space:]", r"\s"))
|
|
def stop(why):
|
|
sys.exit(f"conformance-records: {why}; nothing was written")
|
|
top = f"wai-conformance-{label}"
|
|
names = sorted(n for n in os.listdir(rec_dir) if n.endswith(".wai-conform.json"))
|
|
if len(names) != 15:
|
|
stop(f"{len(names)} records, not the 15 runs")
|
|
files, entries, standards = [], [], set()
|
|
for n in names:
|
|
b = open(os.path.join(rec_dir, n), "rb").read()
|
|
r = json.loads(b)
|
|
impl = r["implementation"]
|
|
if r.get("key") != "supplied" or r.get("signer_pubkey") != pub:
|
|
stop(f"{n}: signed by {r.get('signer_pubkey')} ({r.get('key')} key), not by the seed")
|
|
if impl.get("version") != version:
|
|
stop(f"{n}: names the version {impl.get('version')}, not {version}")
|
|
if r.get("conformant") is not True:
|
|
stop(f"{n}: not conformant")
|
|
if (r.get("toolchain") or {}).get("version") != wv:
|
|
stop(f"{n}: made by wai {(r.get('toolchain') or {}).get('version')}, not {wv}")
|
|
text = b.decode("utf-8")
|
|
m = LOCAL.search(text)
|
|
if m:
|
|
stop(f"{n}: holds a local path ({text[max(0, m.start() - 40):m.end() + 40]!r}), which a list publishing it would refuse")
|
|
standards.add(r["standard"])
|
|
files.append((n, b))
|
|
entries.append({"file": n, "kind": r["kind"], "suite": r["suite"], "sha256": hashlib.sha256(b).hexdigest()})
|
|
if len(standards) != 1:
|
|
stop(f"the records name the standards {sorted(standards)}")
|
|
manifest = {
|
|
"about": "WAI's own implementations through the conformance runner (wai conform) at one commit of open-standards: one record (conform-result/1) a run, each signed with WAI's key and admitted by wai verify --conformant against that commit's corpus",
|
|
"commit": commit,
|
|
"standard": standards.pop(),
|
|
"wai": wv,
|
|
"signer_pubkey": pub,
|
|
"records": entries,
|
|
}
|
|
files.append(("MANIFEST.json", (json.dumps(manifest, indent=2) + "\n").encode()))
|
|
buf = io.BytesIO()
|
|
with gzip.GzipFile(filename="", mode="wb", fileobj=buf, mtime=0) as gz:
|
|
with tarfile.open(fileobj=gz, mode="w", format=tarfile.PAX_FORMAT) as tar:
|
|
d = tarfile.TarInfo(top)
|
|
d.type, d.mode = tarfile.DIRTYPE, 0o755
|
|
tar.addfile(d)
|
|
for n, b in files:
|
|
t = tarfile.TarInfo(f"{top}/{n}")
|
|
t.size, t.mode = len(b), 0o644
|
|
tar.addfile(t, io.BytesIO(b))
|
|
tgz = f"{top}.tar.gz"
|
|
data = buf.getvalue()
|
|
open(os.path.join(pack, tgz), "wb").write(data)
|
|
open(os.path.join(pack, tgz + ".sha256"), "w").write(f"{hashlib.sha256(data).hexdigest()} {tgz}\n")
|
|
print(f"conformance-records: {tgz}: {len(entries)} records, sha256 {hashlib.sha256(data).hexdigest()}")
|
|
PY
|
|
mkdir -p "$OUT"
|
|
mv "$W/pack/"* "$OUT/"
|
|
echo "conformance-records: written to $OUT"
|