From 587a462e3ce8e9727f44848a94161fc4883edfae Mon Sep 17 00:00:00 2001 From: veg Date: Sat, 4 Jul 2026 10:00:01 +0000 Subject: [PATCH] fix: read-only invitees auto-join passive tmux refuses new-session from read-only clients ('client is read-only'), so an active join for an -r invitee died under set -eu with a raw tmux error. Detect the R flag on the caller's ACL line in the existing preflight and fall back to the mirrored view. --- party | 23 ++++++++++++++++++++--- tests/96-unauthorized.bats | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/party b/party index 062c9f1..6c435a4 100755 --- a/party +++ b/party @@ -949,12 +949,29 @@ EOF # Auth gate. The joiner must already be on the access list (added # by the host via `party invite`). Pre-flight here so the user gets - # a helpful message instead of an opaque tmux refusal. - if ! "$PARTY_TMUX" -S "$RR_SOCKET" server-access -l 2>/dev/null \ - | awk '{print $1}' | grep -qx "$USER"; then + # a helpful message instead of an opaque tmux refusal. For an + # unauthorized caller server-access -l prints its refusal on stderr + # with EMPTY stdout (and exit 0 — see party_conn_state), so the awk + # match comes up empty and we land in the exit-13 branch. + acl_line=$("$PARTY_TMUX" -S "$RR_SOCKET" server-access -l 2>/dev/null \ + | awk -v u="$USER" '$1 == u { print; exit }') + if [ -z "$acl_line" ]; then echo "party: '$RR_PARTY_NAME', ask $RR_HOST_USER to invite you." >&2 exit 13 fi + # Read-only invitees cannot create the guest session: tmux refuses + # with "client is read-only" (verified 3.3a/3.5a), which would kill + # an active join mid-new-session under set -eu. Detect the R flag + # on our own ACL line and take the mirrored view instead. Flag + # format is "user (R)" on 3.3–3.5 and "user (U,R)" on newer tmux; + # both end the flag list in "R)". + case "$acl_line" in + *"R)"*) + if [ "$passive" != 1 ]; then + echo "party: you are read-only on '$RR_PARTY_NAME'; joining passive (mirrored view)." >&2 + passive=1 + fi ;; + esac if [ "$passive" = 1 ]; then # Mirror the host's pane focus, read-only at the tmux client diff --git a/tests/96-unauthorized.bats b/tests/96-unauthorized.bats index 65ba671..69eef9e 100644 --- a/tests/96-unauthorized.bats +++ b/tests/96-unauthorized.bats @@ -85,3 +85,25 @@ STUB [ "$status" -eq 0 ] [[ "$output" == *"no parties found"* ]] } + +@test "read-only invitee joining active falls back to passive with a notice" { + # tmux refuses new-session from a read-only client ("client is + # read-only", exit 1 — verified 3.3a/3.5a), so an active join for an + # -r invitee died mid-command under set -eu. cmd_join must detect the + # R flag on its own ACL line and attach passive instead. The unquoted + # STUB delimiter is deliberate: $USER expands at write time, \$* at + # run time. + cat > "$PARTY_TMP/tmux-ro" <