open-standards/scripts/check-wasmtime-pin.py
Transaction Science 2593c1f945
Some checks failed
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 7s
wai-quantum wasmQ / does this change touch it (push) Successful in 10s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 28s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 54s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Successful in 40s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Failing after 1m16s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-app and Create / wai-app · does this change touch it (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
wai-audit collector and player integration / does this change touch it (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
WAI operation catalogue / does this change touch it (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-fleet service / does this change touch it (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-fleet service / service · macos (push) Has been cancelled
wai-ledger service / does this change touch it (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-ledger service / service · macos (push) Has been cancelled
wai-quantum for JavaScript / does this change touch it (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum studio and desktop / does this change touch it (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-sink-android native sink library / does this change touch it (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-sink-swift native sink package / does this change touch it (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
WAI Studio / does this change touch it (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m13s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 2m33s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 2m38s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 4m11s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 4m51s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 6m22s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 7m45s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 9m14s
wai-quantum command line / does this change touch it (push) Has been cancelled
wai-quantum command line / command line · linux (push) Has been cancelled
wai-quantum command line / command line · macos (push) Has been cancelled
wai-quantum contract / does this change touch it (push) Has been cancelled
wai-quantum contract / API compatibility · linux (push) Has been cancelled
wai-quantum contract / schemas and the committed tool lists · linux (push) Has been cancelled
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Has been cancelled
wai-quantum docs, course and locales / does this change touch it (push) Has been cancelled
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Has been cancelled
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Has been cancelled
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Has been cancelled
wai-quantum editors / does this change touch it (push) Has been cancelled
wai-quantum editors / editors · linux (push) Has been cancelled
wai-quantum editors / editors · macos (push) Has been cancelled
wai-quantum resource estimation / does this change touch it (push) Has been cancelled
wai-quantum resource estimation / estimation and calibration · linux, release (push) Has been cancelled
wai-quantum other formats / does this change touch it (push) Has been cancelled
wai-quantum other formats / readers, writers and the set · linux (push) Has been cancelled
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum OpenQASM reader / does this change touch it (push) Has been cancelled
wai-quantum OpenQASM reader / reader and corpus · linux (push) Has been cancelled
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum pulse and dynamics / does this change touch it (push) Has been cancelled
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Has been cancelled
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Has been cancelled
wai-quantum pulse and dynamics / the same bits · macos (push) Has been cancelled
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum for Python / does this change touch it (push) Has been cancelled
wai-quantum for Python / python · linux (push) Has been cancelled
wai-quantum for Python / python · macos (push) Has been cancelled
wai-quantum error correction and mitigation / does this change touch it (push) Has been cancelled
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Has been cancelled
wai-quantum extension points / does this change touch it (push) Has been cancelled
wai-quantum extension points / the registry and the example · linux (push) Has been cancelled
wai-quantum extension points / the registry and the example · linux-arm64 (push) Has been cancelled
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum service / does this change touch it (push) Has been cancelled
wai-quantum service / service · linux (push) Has been cancelled
wai-quantum service / service · macos (push) Has been cancelled
wai-quantum service / service energy · linux packages (push) Has been cancelled
wai-quantum variational and algorithm library / does this change touch it (push) Has been cancelled
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Has been cancelled
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Has been cancelled
wai-quantum verdicts and repairs / does this change touch it (push) Has been cancelled
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Has been cancelled
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum views in agent hosts / does this change touch it (push) Has been cancelled
wai-quantum views in agent hosts / views · the page and its engine (push) Has been cancelled
wai-quantum views in agent hosts / views · a scripted host (push) Has been cancelled
wai-quantum-landscape-fpga reference design / does this change touch it (push) Has been cancelled
wai-quantum-landscape-fpga reference design / the member against the model of the logic, and the logic against the model · linux, release (push) Has been cancelled
wai-quantum-landscape-fpga reference design / the board's code on the board's processor's architecture · linux-arm64, release (push) Has been cancelled
wai: wasmQ, an OpenQASM 3 program and the WebAssembly its externs call, run the same everywhere, metered and receipted
Re-landed from PR #659 (branch wai/quantum-wasmq, head 39fdb517a) as one
commit on main, under the land-it model. Five review rounds; the last had
no high or critical finding, and its mediums were fixed on the branch.

A hybrid quantum program runs classical code between its gates. OpenQASM 3
declares such a function with `extern` and leaves its body and linking
outside the language. wasmQ (wai.quantum.wasmq) packs the program and the
WebAssembly that defines its externs into one content-addressed WAI
envelope; a run gives the same result bytes and fuel on every host and
seals the engine's job receipt.

- extensions/quantum-wasmq.md (normative) and quantum-wasmq.wit.
- wai/wai-wasmq: the profile (Lime1, nothing imported, bounded memory,
  refusal codes W001-W017); what a run asks of its host, bounded from the
  bundle alone before anything runs; fuel defined on the module as written;
  a weighted stack; two engines (the pinned wasmtime 50.0.1 and an
  interpreter of the crate's own that also runs on wasm32); the envelope,
  runner, receipts, transcript replay, reference programs and vectors.
- wai-quantum: engine::wasmq (built with quantum_receipt), the job form
  beside its receipts; the estimate verifier answers a request no host
  re-runs with a verdict carrying rerun_error, combined here with main's
  reaction clock (clock_of).
- wai/quantum-conformance/wasmq: envelopes, refusals and receipts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-09 13:22:09 -05:00

171 lines
7.8 KiB
Python
Executable file

#!/usr/bin/env python3
"""check-wasmtime-pin.py: every workflow that runs wasmtime runs the one pinned release,
with both of its determinism settings.
WAI's WebAssembly legs hold a module's output to pinned bits. A stock wasmtime leaves NaN
canonicalisation off and lets each relaxed SIMD instruction take the host's behaviour, and
two versions of it can lower one instruction two ways, so a leg's bits would be the
engine's choice. The install steps' comment says every workflow pins one version and
passes both settings; this makes that true of every workflow, not only of the ones that
comment sits in.
In every `.github/workflows/*.yml`, with continued lines (`\\` at the end) joined, this
requires that
1. every download of a wasmtime release names version PIN (the `v=` the step sets, or
the version in the URL), and the SHA-256 it checks is the digest of that archive in
DIGESTS;
2. wasmtime is installed no other way (`cargo install wasmtime-cli`, the install
script, or an action);
3. every `wasmtime run`, `wasmtime serve` or `wasmtime compile`, every `wasmtime` given
a module path, and every `CARGO_TARGET_<triple>_RUNNER` that is wasmtime, passes
`-W nan-canonicalization=y` and `-W relaxed-simd-deterministic=y`;
4. at least one download and one run were found, so a check that looked in the wrong
place fails rather than passing on nothing;
5. every crate under wai/ that depends on wasmtime as a library pins it to that release
exactly (`version = "=PIN"`), so the engine a crate embeds is the one the workflows
run (wai-wasmq's native engine, extensions/quantum-wasmq.md §4.6).
check-wasmtime-pin.py [--root DIR]
Exit 0 when all four hold, 1 with one line a finding otherwise. Standard library only.
"""
import os
import re
import sys
PIN = "50.0.1"
# The release archives a workflow may download, by name, with the SHA-256 the release lists.
DIGESTS = {
"wasmtime-v50.0.1-x86_64-linux.tar.xz": "685466455dd42a14774a86c36c8f2e45cbb9bd6d92a850139315df60a75498a5",
}
FLAGS = ("nan-canonicalization=y", "relaxed-simd-deterministic=y")
DOWNLOAD = re.compile(r"bytecodealliance/wasmtime/releases/download/")
URL_VERSION = re.compile(r"releases/download/v(\d[^/\"'\s]*)/")
SET_VERSION = re.compile(r"^\s*v=[\"']?([^\"'\s;]+)")
ARCHIVE = re.compile(r"wasmtime-v(\$v|\$\{v\}|\d[^-\"'\s]*)-([a-z0-9_]+-[a-z]+)\.tar\.xz")
DIGEST = re.compile(r"\b([0-9a-f]{64})\b.*sha256sum -c")
OTHER_INSTALL = re.compile(
r"cargo\s+(?:\S+\s+)*install\s+(?:\S+\s+)*wasmtime-cli|wasmtime\.dev/install|uses:\s*\S*wasmtime"
)
# wasmtime as a command: run, serve or compile, or given a module path (`wasmtime x.wasm`).
INVOKE = re.compile(
r"(?:^|[\s;&|(`/\"'=])wasmtime\s+(?:(?:run|serve|compile)\b|[^\s-]\S*\.(?:c?wasm|wat)\b)"
)
RUNNER = re.compile(r"CARGO_TARGET_\w+_RUNNER\s*[:=]\s*[\"']?wasmtime\b")
# A Cargo dependency on the wasmtime library, and the version it asks for.
CRATE_DEP = re.compile(r"^\s*wasmtime\s*=")
CRATE_VERSION = re.compile(r"version\s*=\s*\"([^\"]+)\"|^\s*wasmtime\s*=\s*\"([^\"]+)\"")
def logical_lines(text):
"""(first line number, text) with backslash-continued lines joined."""
out, buf, start = [], "", 0
for n, line in enumerate(text.splitlines(), 1):
if not buf:
start = n
if line.rstrip().endswith("\\"):
buf += line.rstrip()[:-1] + " "
continue
out.append((start, buf + line))
buf = ""
if buf:
out.append((start, buf))
return out
def check_file(path, rel, findings):
lines = logical_lines(open(path, encoding="utf-8").read())
downloads = runs = 0
for i, (n, line) in enumerate(lines):
code = line.lstrip()
if code.startswith("#"):
continue
if OTHER_INSTALL.search(line):
findings.append(f"{rel}:{n}: installs wasmtime some other way; download the pinned release ({PIN}) by version and SHA-256")
if DOWNLOAD.search(line):
downloads += 1
m = URL_VERSION.search(line)
ver = m.group(1) if m else None
if ver is None: # the URL takes the version from the step's `v=`
for _, prev in reversed(lines[max(0, i - 12) : i]):
s = SET_VERSION.match(prev)
if s:
ver = s.group(1)
break
if ver != PIN:
findings.append(f"{rel}:{n}: downloads wasmtime {ver or '(version not found)'}; every workflow pins {PIN}")
near = lines[max(0, i - 12) : i + 5]
arch = None
for _, other in near:
a = ARCHIVE.search(other)
if a:
arch = a.group(2)
break
name = f"wasmtime-v{ver}-{arch}.tar.xz" if arch else None
digests = [d.group(1) for _, other in lines[i : i + 5] for d in [DIGEST.search(other)] if d]
if name not in DIGESTS:
findings.append(f"{rel}:{n}: downloads {name or 'an archive whose name was not found'}, which has no pinned digest here")
elif not digests:
findings.append(f"{rel}:{n}: downloads {name} and checks no SHA-256 within four lines")
elif digests[0] != DIGESTS[name]:
findings.append(f"{rel}:{n}: checks {name} against {digests[0][:12]}..., not its pinned digest {DIGESTS[name][:12]}...")
for rx in (INVOKE, RUNNER):
m = rx.search(line)
if m:
runs += 1
rest = line[m.start() :]
missing = [f for f in FLAGS if f not in rest]
if missing:
findings.append(f"{rel}:{n}: runs wasmtime without {' and '.join('-W ' + f for f in missing)}")
break
return downloads, runs
def main(argv):
root = "."
if len(argv) == 3 and argv[1] == "--root":
root = argv[2]
elif len(argv) != 1:
sys.exit("usage: check-wasmtime-pin.py [--root DIR]")
wf = os.path.join(root, ".github", "workflows")
findings, downloads, runs = [], 0, 0
for name in sorted(os.listdir(wf)) if os.path.isdir(wf) else []:
if name.endswith((".yml", ".yaml")):
d, r = check_file(os.path.join(wf, name), f".github/workflows/{name}", findings)
downloads += d
runs += r
crates = 0
wai = os.path.join(root, "wai")
for dirpath, dirnames, filenames in os.walk(wai):
dirnames[:] = [d for d in dirnames if d not in ("target", "node_modules", ".git")]
if "Cargo.toml" not in filenames:
continue
path = os.path.join(dirpath, "Cargo.toml")
rel = os.path.relpath(path, root)
section = ""
for n, line in enumerate(open(path, encoding="utf-8").read().splitlines(), 1):
if line.strip().startswith("["):
section = line.strip()
continue
# Only a dependency table names a crate; `wasmtime = [...]` in [features] does not.
if "dependencies" not in section or not CRATE_DEP.match(line):
continue
crates += 1
v = CRATE_VERSION.search(line)
ver = (v.group(1) or v.group(2)) if v else None
if ver != "=" + PIN:
findings.append(f"{rel}:{n}: depends on wasmtime {ver or '(no version)'}; a crate pins the release the workflows run, \"={PIN}\"")
if downloads == 0 or runs == 0:
findings.append(f"found {downloads} wasmtime download(s) and {runs} run(s) under {wf}: this check looked in the wrong place")
for f in findings:
print(f"::error::{f}")
if findings:
return 1
print(f"check-wasmtime-pin: {downloads} downloads of wasmtime {PIN}, each checked against its digest; {runs} runs, each with both settings; {crates} crate dependencies, each on ={PIN}")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))