From f05a7823ccff0377b4b57f3cfca25d9b67dd50cf Mon Sep 17 00:00:00 2001 From: Daniel Rapp Date: Tue, 11 Aug 2026 21:15:54 +0000 Subject: [PATCH] test: fix two macOS bash-3.2 failures + silence a spurious ERR trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three fixes from one investigation into the maintainer's macOS run, which aborted at 913 checks with 2 failures. All three are invisible to CI (Ubuntu, bash 5, no `sandy` on PATH). 1. §68 — the test suite was EXECUTING sandy. The assert script lives in a double-quoted `python3 -c "..."` string, and a Python comment inside it read: # Regression: the proxy of a `sandy`-named workspace ... Bash expands backticks in a double-quoted string regardless of Python comment syntax, so the suite ran the real `sandy` command and spliced its multi-line output into the script: # Regression: the proxy of a [sandy] Building... [sandy] Sandbox image up to date.-named workspace must join to ... The second line is not a comment -> SyntaxError: invalid decimal literal -> both §68 checks fail. On CI there is no `sandy` on PATH, so the expansion is empty, the line stays a comment, and it passes. Beyond the false failure, a test suite silently invoking the tool under test is its own bug (that 'Sandbox image up to date' is a real image check). Fixed by switching the block to a QUOTED heredoc (`python3 - "$_json" <<'DFPY'`), which kills the whole expansion class rather than just this backtick; `python3 - ARG` keeps sys.argv[1] == the JSON, so the assertions are byte-identical. Verified both directions on Linux with a fake `sandy` on PATH: old block FAILS (reproducing macOS), new block PASSES. Same bug class as the Dockerfile.proxy backtick regression already guarded by §49. Scanned all 35 `python3 -c "..."` blocks — this was the only one. 2. §83 — nested `source <(sed ...)` inside `$(...)`, which bash 3.2 does not reliably support: the source yields nothing, both calls exit 127, and the ERR trap aborts the entire run, so every section after §83 never executed. run-tests.sh already documents this trap twice in its own comments and avoids it elsewhere. Switched to the suite's extract-then-eval idiom. 3. sandy:1043 — `_ac="$(docker exec ... )" || _ac=""` handles the status, but with `set -E` the introspection ERR trap is inherited by the substitution subshell and bash 3.2 fires it anyway, so every macOS --print-state with an unreachable tmux probe printed 'introspection handler failed ... Report this at ' for entirely normal behavior. Moved the guard INSIDE the substitution (`|| true`), silencing it on both bash versions. Emitted values are unchanged (verified: 2 and null). Co-Authored-By: Claude Opus 5 --- sandy | 9 ++++++++- test/run-tests.sh | 23 +++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/sandy b/sandy index ad1961c..7a83db7 100755 --- a/sandy +++ b/sandy @@ -1040,7 +1040,14 @@ _sandy_emit_container_daemon_fields() { # non-zero status hits the introspection ERR trap under set -eE and # kills the whole emission (host regression: one broken daemon # container failed every --print-state consumer). - _ac="$(docker exec -u "$(id -u)" "$_cid" tmux display -p -t sandy '#{session_attached}' 2>/dev/null)" || _ac="" + # `|| true` INSIDE the substitution, not `|| _ac=""` outside it: with + # `set -E` the introspection ERR trap is inherited by the subshell, and + # bash 3.2 (macOS /bin/bash) fires it for the failing `docker exec` even + # though the outer `||` handles the status — printing a spurious + # "introspection handler failed / Report this at ..." on every + # --print-state with an unreachable probe. bash 4+ exempts it; macOS does + # not. Absorbing the failure inside the subshell silences it on both. + _ac="$(docker exec -u "$(id -u)" "$_cid" tmux display -p -t sandy '#{session_attached}' 2>/dev/null || true)" if ! [[ "$_ac" =~ ^[0-9]+$ ]]; then _ac="null" fi diff --git a/test/run-tests.sh b/test/run-tests.sh index 1450cbe..523beac 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -5124,7 +5124,15 @@ _df_assert() { # $1=mode ("" or "light") local _json _rc=0 _json="$(PATH="$_DF_BIN:$PATH" bash "$_SBX_SCRIPT" --print-state ${1:+$1} 2>/dev/null)" || _rc=$? [ "$_rc" -eq 0 ] || return 1 - python3 -c " + # QUOTED heredoc, NOT `python3 -c "..."`: in a double-quoted string bash + # expands backticks/$( ) inside what looks like a Python comment. The word + # `sandy` in the regression note below was command substitution — on a host + # with sandy on PATH the suite RAN it and spliced its multi-line output into + # this script, corrupting it into a SyntaxError and failing both checks. + # Invisible on CI (no sandy on PATH -> empty expansion). Same class as the + # Dockerfile.proxy backtick bug guarded above. `python3 - ARG` keeps + # sys.argv[1] == the JSON, so the assertions are unchanged. + python3 - "$_json" <<'DFPY' import json, sys d = json.loads(sys.argv[1]) rc = d['running_containers'] @@ -5143,7 +5151,7 @@ assert isinstance(daemon['attached_clients'], int), daemon assert broken['daemon'] is True, broken assert broken['attached_clients'] is None, broken assert bare['attached_clients'] is None, bare -# Regression: the proxy of a `sandy`-named workspace must join to sandy-92aa9f98, +# Regression: the proxy of a "sandy"-named workspace must join to sandy-92aa9f98, # NOT the double-stripped bare hash '92aa9f98'. A proxy is not a daemon session. assert proxy['sandbox'] == 'sandy-92aa9f98', proxy assert proxy['daemon'] is False, proxy @@ -5154,7 +5162,7 @@ assert proxy['attached_clients'] is None, proxy assert daemon['updated_at'] == '2026-07-14T12:00:00Z', daemon assert broken['updated_at'] is None, broken assert bare['updated_at'] is None, bare -" "$_json" +DFPY } check "full mode: daemon fields correct; a failing attach-probe yields null, not a dead emission" \ _df_assert @@ -6678,7 +6686,14 @@ check "session-end notice compares HEAD (symbolic-ref) + surfaces the change" \ check ".head-at-launch is cleaned up unconditionally at session end" \ bash -c 'grep -q "rm -f .*\.head-at-launch" "$1"' -- "$_S83" # _sandy_head_display behavioral unit test (pure fn, no docker) -_hd_out="$(bash -c 'source <(sed -n "/^_sandy_head_display()/,/^}/p" "$1"); _sandy_head_display refs/heads/feature/x; printf "|"; _sandy_head_display detached:abc1234' -- "$_S83")" +# Extract-then-eval, NOT `source <(sed ...)` inside `$(...)`: bash 3.2 (macOS) +# does not reliably handle nested process substitution there — it yields an +# empty source and `command not found` (exit 127), which under `set -euo +# pipefail` aborts the whole suite. Same trap already called out at the top of +# this file; CI (Ubuntu/bash 5) cannot catch it. +_hd_fn="$(sed -n '/^_sandy_head_display()/,/^}/p' "$_S83")" +_hd_out="$(bash -c "$_hd_fn +_sandy_head_display refs/heads/feature/x; printf '|'; _sandy_head_display detached:abc1234")" check "_sandy_head_display: refs/heads/; detached:→detached HEAD ()" \ test "$_hd_out" = "feature/x|detached HEAD (abc1234)"