open-standards/wai/quickstart/publish.sh
Transaction Science 3adb3e92a7
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
wai conformance records: CI signs WAI's own per-suite records with WAI's key and publishes them
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 onto 8da651a54, 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]>
2026-11-10 03:11:58 -05:00

34 lines
2.7 KiB
Shell
Executable file

#!/usr/bin/env bash
# Attach files to the forge release for a tag, creating the release if there is
# none, and replacing an asset of the same name:
#
# FORGE_API=http://host:3400/api/v1 FORGE_REPO=owner/repo FORGE_TOKEN=... \
# bash wai/quickstart/publish.sh <tag> <title> <file>...
#
# Uploads go to FORGE_API directly (over the private network), never through the
# public tunnel, whose request size cap a large asset would hit.
set -euo pipefail
if [ $# -lt 3 ]; then
echo "usage: bash wai/quickstart/publish.sh <tag> <title> <file>..." >&2
exit 2
fi
TAG="$1"; TITLE="$2"; shift 2
: "${FORGE_API:?}" "${FORGE_REPO:?}" "${FORGE_TOKEN:?}"
AUTH="Authorization: token $FORGE_TOKEN"
BASE="$FORGE_API/repos/$FORGE_REPO/releases"
release_id() { curl -fsS -H "$AUTH" "$BASE/tags/$TAG" 2>/dev/null | python3 -c 'import json,sys; print(json.load(sys.stdin).get("id", ""))' 2>/dev/null || true; }
ID="$(release_id)"
if [ -z "$ID" ]; then
BODY="$(python3 -c 'import json,sys; print(json.dumps({"tag_name": sys.argv[1], "name": sys.argv[2], "body": "The WAI command line and what `wai dev` runs, for macOS, Linux and Windows: each wai-<version>-<triple> archive holds bin/ (wai, wai-relay, wai-room, wai-ingest, wai-remote-host, wai-pack, wai-quantum), share/wai/web/ (the room client), share/wai/studio/ (WAI Studio), a README and the licence. For C on Linux, libwai-<version>-<triple>.tar.gz: lib/libwai.a, include/wai.h and lib/pkgconfig/wai.pc. For Swift, wai-sink-swift-<version>.zip, the package whose Package.swift names WaiFFI-<version>.xcframework.zip by URL and checksum. For Android, wai-sink-<version>.aar, also science.transaction.wai:wai-sink in the forge\u2019s Maven registry. WAI\u2019s own conformance results, wai-conformance-<version>.tar.gz: each suite\u2019s record (conform-result/1) of WAI\u2019s implementations run at this tag, signed with WAI\u2019s key. Each .sha256 file checks its file (`shasum -a 256 -c`)."}))' "$TAG" "$TITLE")"
curl -fsS -H "$AUTH" -H 'content-type: application/json' -X POST "$BASE" -d "$BODY" > /dev/null 2>&1 || true
# Builds run side by side; one of them created it if this did not.
for _ in 1 2 3 4 5 6; do ID="$(release_id)"; [ -n "$ID" ] && break; sleep 3; done
fi
[ -n "$ID" ] || { echo "::error::no release for $TAG"; exit 1; }
for f in "$@"; do
name="$(basename "$f")"
for old in $(curl -fsS -H "$AUTH" "$BASE/$ID/assets" | NAME="$name" python3 -c 'import json,os,sys; print(" ".join(str(a["id"]) for a in json.load(sys.stdin) if a["name"] == os.environ["NAME"]))'); do
curl -fsS -H "$AUTH" -X DELETE "$BASE/$ID/assets/$old" > /dev/null
done
curl -fsS -H "$AUTH" -X POST "$BASE/$ID/assets?name=$name" -F "attachment=@$f;type=application/octet-stream" -o /dev/null -w "uploaded $name: http %{http_code}\n"
done