open-standards/.github/workflows/conformance.yml
Transaction Science 48eaa9a587 ci: every Python install pinned by SHA-256; verifiers run with -I
Six workflow steps installed whatever PyPI served that day: cryptography
(wai-conformance, wai-http twice, wai-web-wasm), the RDF tools' dependencies
(wai-conformance), PyYAML (standards-build, aac-rs), the ML stack of
wai-neural-e2e, and pip itself (wai-neural-e2e, wai-sota-vectors). A
compromised release would have run on the runners. Each now installs a
hashed requirements file with --require-hashes, the way wai-pack.yml
already does:

- cryptography: wai/pack-conformance/requirements-verify.txt (the same file);
- RDF tools: wai/vocab/requirements-shapes.txt, from requirements-shapes.in;
- PyYAML: aac/aac-rs/tools/pagesets/requirements-ci.txt, from requirements-ci.in;
- wai-neural-e2e: wai/tools/requirements-neural-e2e.txt, from
  requirements-neural-e2e.in;
- wai-sota-vectors: wai/tools/requirements-sota-int-hashes.txt, from
  requirements-sota-int.txt.

Each generated file's header holds the uv command that regenerates it. The
two ML locks take torch and torchvision from the CPU wheel index through
wai/tools/torch-cpu-overrides.txt (2.14.0+cpu on Linux, 2.14.0 on macOS),
with no CUDA packages. The new lock files are added to the path filters of
the workflows that install them.

pillow goes from 12.3.0 to 13.0.0 in requirements-sota-int.txt: 12.x has
heap overflows in the TIFF writer and the JPEG decoder and an argument
injection into Ghostscript (GHSA-332p-7hrc-92wf, GHSA-8g5g-8vmr-9782,
GHSA-w889-685w-c8fh); 13.0.0 is the first fixed release.

The 26 verifier and differential calls that ran without -I now run with it,
so neither the working directory nor PYTHON* variables can put a module in
front of the standard library: pin, int_payload, staged, http (4), measure,
sim, sim_diff, claim, differential, jwp, chain and chain-gap differentials,
signer (2), check_shapes, smart-byte verify_v1, pack_verify and the five pack
differentials (7). Each script already puts its own directory on sys.path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 13:56:02 -04:00

232 lines
8.6 KiB
YAML

name: smart-byte conformance gate
# One run per branch at a time. A push supersedes the run before it.
#
# There is one `macos` runner and it is the dev Mac, so every macOS job in this
# repo queues on it. With no concurrency group, a session pushing four versions
# of a branch queued four complete sets of runs and every one of them had to
# drain: on 2026-10-05 a PR's 21 contexts settled none in 70 minutes behind a
# backlog of 25 runs, and the queue grew faster than it cleared. Only the newest
# commit's verdict is wanted, so the older runs are cancelled.
#
# Verified on this forge (Forgejo 16.0.5) in `ci-test` before being added here:
# the key parses, and a newer push moves an older run to `cancelled` even while
# it is still queued, which is the case that matters.
#
# `cancel-in-progress: true` also applies to `main`. That is deliberate and
# safe here: main advances by merge commits whose tree contains the commits
# before them, so the newer run covers the older one's changes.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
paths:
- 'smart-byte/spec/**'
- 'smart-byte/conformance/**'
- '.github/workflows/conformance.yml'
push:
branches:
- main
paths:
- 'smart-byte/spec/**'
- 'smart-byte/conformance/**'
- '.github/workflows/conformance.yml'
jobs:
# Does this pull request's own diff touch the paths below? This forge matches a
# workflow's `paths:` against the push, so a merge of main into a branch fires the
# workflow whatever the pull request changes; every job here waits on this answer.
# 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: linux-arm64
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/conformance.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches conformance: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
validate-json:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: Validate conformance JSON files
runs-on: linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Ensure jq is available
run: jq --version
- name: Validate every JSON file under smart-byte/conformance/v*
run: |
set -euo pipefail
found=0
fail=0
while IFS= read -r -d '' f; do
found=$((found+1))
if ! jq empty "$f" >/dev/null 2>&1; then
echo "::error file=$f::invalid JSON"
fail=$((fail+1))
else
echo "ok: $f"
fi
done < <(find smart-byte/conformance -type f -name '*.json' -print0)
if [ "$found" -eq 0 ]; then
echo "::error::no JSON files found under smart-byte/conformance/v*"
exit 1
fi
if [ "$fail" -ne 0 ]; then
echo "::error::$fail JSON file(s) failed validation"
exit 1
fi
echo "validated $found JSON file(s)"
- name: Validate vector schema (top-level array, name field present)
run: |
set -euo pipefail
fail=0
while IFS= read -r -d '' f; do
if ! jq -e 'type == "array"' "$f" >/dev/null; then
echo "::error file=$f::top-level value must be a JSON array"
fail=$((fail+1))
continue
fi
if ! jq -e 'all(.[]; has("name") and has("description"))' "$f" >/dev/null; then
echo "::error file=$f::every vector must have name and description fields"
fail=$((fail+1))
fi
done < <(find smart-byte/conformance -type f -name '*_vectors.json' -print0)
if [ "$fail" -ne 0 ]; then
echo "::error::$fail vector file(s) failed schema validation"
exit 1
fi
- name: Validate vector names are unique within each file
run: |
set -euo pipefail
fail=0
while IFS= read -r -d '' f; do
dupes=$(jq -r '[.[].name] | group_by(.) | map(select(length>1)) | .[][0] // empty' "$f")
if [ -n "$dupes" ]; then
echo "::error file=$f::duplicate vector name(s): $dupes"
fail=$((fail+1))
fi
done < <(find smart-byte/conformance -type f -name '*_vectors.json' -print0)
if [ "$fail" -ne 0 ]; then
exit 1
fi
# The pack's values come from the Rust reference implementation, and
# standards-build checks them against it under `cargo test`. This job checks
# them against a second implementation, written separately in another
# language, so a mistake shared by the generator and its own verifier still
# fails here. Standard library only: nothing to install beyond python3.
crosscheck:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: Second implementation reproduces every vector
runs-on: linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Ensure python3 is available
shell: bash
run: |
if ! command -v python3 >/dev/null 2>&1; then
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq python3
fi
python3 --version
- name: Cross-check v1
run: python3 -I smart-byte/conformance/crosscheck/verify_v1.py smart-byte/conformance/v1
spec-vector-coupling:
needs: relevant
if: needs.relevant.outputs.run == 'true' && (github.event_name == 'pull_request')
name: Spec changes require vector-pack updates
runs-on: linux
steps:
- name: Checkout (with full history for diff)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine the PR base
id: base
run: |
base="${{ github.event.pull_request.base.sha }}"
if [ -z "$base" ]; then
base="origin/main"
fi
echo "base=$base" >> "$GITHUB_OUTPUT"
- name: Enforce coupling between spec and conformance changes
run: |
set -euo pipefail
base="${{ steps.base.outputs.base }}"
head="${{ github.event.pull_request.head.sha }}"
if [ -z "$head" ]; then
head="HEAD"
fi
changed=$(git diff --name-only "$base" "$head")
echo "Files changed in this PR:"
echo "$changed"
spec_touched=0
conformance_touched=0
if echo "$changed" | grep -qE '^smart-byte/spec/'; then
spec_touched=1
fi
if echo "$changed" | grep -qE '^smart-byte/conformance/'; then
conformance_touched=1
fi
if [ "$spec_touched" -eq 1 ] && [ "$conformance_touched" -eq 0 ]; then
echo "::error::This PR modifies smart-byte/spec/ without modifying smart-byte/conformance/."
echo "::error::Per the conformance social contract, every spec change must be accompanied by a vector-pack update."
echo "::error::If the spec change is editorial and the wire format is unchanged, record the editorial reason in smart-byte/conformance/v<N>/regeneration.md and include that file in the PR."
exit 1
fi
echo "coupling check passed (spec_touched=$spec_touched, conformance_touched=$conformance_touched)"
versions-present:
needs: relevant
if: needs.relevant.outputs.run == 'true'
name: VERSIONS.md and README.md must exist
runs-on: linux
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Required pack metadata files
run: |
set -euo pipefail
missing=0
for f in smart-byte/conformance/README.md smart-byte/conformance/VERSIONS.md; do
if [ ! -f "$f" ]; then
echo "::error file=$f::missing required pack metadata file"
missing=$((missing+1))
fi
done
for d in smart-byte/conformance/v*/ ; do
if [ ! -f "$d/regeneration.md" ]; then
echo "::error file=$d/regeneration.md::missing regeneration.md for $d"
missing=$((missing+1))
fi
done
if [ "$missing" -ne 0 ]; then
exit 1
fi