chore(quic-interop): auto-patch upstream certs.sh for macOS BSD tr

`LC_CTYPE=C tr -dc '[:alnum:]' </dev/urandom` in the upstream runner's
certs.sh trips "tr: Illegal byte sequence" on macOS — LC_CTYPE alone
doesn't override the runtime locale chain. Only the amplificationlimit
testcase exercises this loop (chain length > 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) <noreply@anthropic.com>
This commit is contained in:
Vitor Pamplona
2026-05-08 10:58:52 -04:00
parent 5b8bd021b0
commit 5e3e5cc5a0
2 changed files with 41 additions and 0 deletions
@@ -60,6 +60,27 @@ python run.py -d -i amethyst -s aioquic -t handshake,chacha20 --log-dir ./logs
Inspect `./logs/<run>/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 |
+20
View File
@@ -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:]' </dev/urandom` which on macOS still
# trips "tr: Illegal byte sequence" — LC_CTYPE alone doesn't override
# the runtime LC_ALL when LC_ALL is unset/inherited weirdly. The
# `amplificationlimit` testcase is the only one that exercises this
# loop (chain length > 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.