name: smart-byte conformance gate 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: validate-json: 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: 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 smart-byte/conformance/crosscheck/verify_v1.py smart-byte/conformance/v1 spec-vector-coupling: name: Spec changes require vector-pack updates runs-on: linux if: github.event_name == 'pull_request' 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/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: 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