From 5e3e5cc5a04f7383f17b9ceab57fc523f206eb57 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 8 May 2026 10:58:52 -0400 Subject: [PATCH] chore(quic-interop): auto-patch upstream certs.sh for macOS BSD tr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `LC_CTYPE=C tr -dc '[:alnum:]' 1 → fakedns SAN inflation), but if it aborts the runner stops the whole matrix BEFORE any later test in TESTCASES_QUIC runs: handshakeloss, transferloss, handshakecorruption, transfercorruption, ipv6, v2, rebind-port, rebind-addr, connectionmigration, and the goodput/crosstraffic measurements all silently never execute. The post-mortem summary shows the 12 testcases that ran before the abort and looks deceptively complete. Add an idempotent `sed` step to run-matrix.sh that rewrites the line to `LC_ALL=C tr` on every invocation, plus a plan-file note so the next person hitting the deceptive summary doesn't repeat the diagnosis. The patch is a working-tree edit to ../quic-interop-runner/, not a fork; re-applied on every clone. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-05-06-interop-runner.md | 21 +++++++++++++++++++ quic/interop/run-matrix.sh | 20 ++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/quic/interop/plans/2026-05-06-interop-runner.md b/quic/interop/plans/2026-05-06-interop-runner.md index 3d07f186e..c042e2ab8 100644 --- a/quic/interop/plans/2026-05-06-interop-runner.md +++ b/quic/interop/plans/2026-05-06-interop-runner.md @@ -60,6 +60,27 @@ python run.py -d -i amethyst -s aioquic -t handshake,chacha20 --log-dir ./logs Inspect `./logs//client_qlog/*.qlog` in qvis when something breaks. +### macOS gotcha — upstream `certs.sh` patch (auto-applied) + +`run-matrix.sh` step 1a rewrites `LC_CTYPE=C tr` → `LC_ALL=C tr` in +the upstream `certs.sh`. macOS BSD `tr` chokes on `/dev/urandom` with +`tr: Illegal byte sequence` when only `LC_CTYPE` is set; `LC_ALL` wins +in the locale-precedence chain and silences it. Without this, the +`amplificationlimit` testcase aborts at cert generation, and every +test sequenced after it in `TESTCASES_QUIC` +(`handshakeloss`, `transferloss`, `handshakecorruption`, +`transfercorruption`, `ipv6`, `v2`, `rebind-port`, `rebind-addr`, +`connectionmigration`, plus the goodput/crosstraffic measurements) +silently never runs. The matrix prints the post-mortem summary +showing only the 12 testcases that ran before the abort, which looks +deceptively complete. + +The patch is idempotent and is re-applied on every clone of the +runner (the fix is a working-tree edit to `../quic-interop-runner/`, +not a fork). If you ever delete `../quic-interop-runner/` and +re-clone manually, run `quic/interop/run-matrix.sh` once first or +apply the same `sed` by hand. Upstream PR not yet filed. + ## Phase ladder (excerpt — full plan in conversation) | Phase | Goal | Tests | Exit criterion | diff --git a/quic/interop/run-matrix.sh b/quic/interop/run-matrix.sh index f6e10f8ab..b6d00367c 100755 --- a/quic/interop/run-matrix.sh +++ b/quic/interop/run-matrix.sh @@ -66,6 +66,26 @@ if [ ! -d "$RUNNER_DIR" ]; then git clone --depth 1 https://github.com/quic-interop/quic-interop-runner.git "$RUNNER_DIR" fi +# 1a. Patch upstream certs.sh for macOS BSD `tr`. The upstream uses +# `LC_CTYPE=C tr -dc '[:alnum:]' 1 → fakedns SAN inflation), but if it aborts, +# the runner aborts the whole matrix BEFORE any test after +# `amplificationlimit` in TESTCASES_QUIC runs (handshakeloss / +# transferloss / rebind-* / etc. all silently skipped). The fix is +# `LC_ALL=C` instead. Idempotent: a second run is a no-op once +# already-patched. macOS `sed -i` requires the empty-extension arg. +if grep -q 'LC_CTYPE=C tr -dc' "$RUNNER_DIR/certs.sh" 2>/dev/null; then + echo "==> patching certs.sh (LC_CTYPE=C → LC_ALL=C for macOS tr compatibility)" + if $is_macos; then + sed -i '' 's/LC_CTYPE=C tr -dc/LC_ALL=C tr -dc/' "$RUNNER_DIR/certs.sh" + else + sed -i 's/LC_CTYPE=C tr -dc/LC_ALL=C tr -dc/' "$RUNNER_DIR/certs.sh" + fi +fi + # 2. venv + Python deps. Prefer 3.13 — pyshark (the runner's pcap parser) # trips on 3.14's asyncio.get_event_loop() removal. Fall back to whatever # `python3` resolves to if 3.13 isn't installed.