refactor: fold is_party_alive into party_conn_state

One liveness primitive instead of two. The PID argument was a vestige
(format-checked, never probed, since the kill -0 removal); dropping it
means a roster with a garbage SERVER_PID can no longer mask a live
socket in host/moderation/role resolution.
This commit is contained in:
veg 2026-07-11 12:07:13 +00:00
parent be3fb049d2
commit 6b94255245
5 changed files with 51 additions and 88 deletions

View file

@ -82,32 +82,22 @@ setup() {
# liveness
# ========
#
# is_party_alive must not probe the PID with kill -0. POSIX kill(2) is
# party_conn_state must not probe PIDs with kill -0. POSIX kill(2) is
# allowed to return EPERM when the caller can't signal the target, and
# illumos/BSD/macOS honor that so kill -0 against another user's PID
# illumos/BSD/macOS honor that, so kill -0 against another user's PID
# returns nonzero even when the process exists. Linux and Linux-ABI
# zones (LX-branded) are the outliers that return 0; that's why the
# bug hid in the test matrix until a native illumos run surfaced it.
# Discovery now relies on `tmux -S list-clients` alone, which is
# strictly stronger (filters PID-reuse, dead servers, AF_UNIX impostors).
# Liveness rides on `tmux -S list-clients` alone, which is strictly
# stronger (filters PID-reuse, dead servers, AF_UNIX impostors).
@test "is_party_alive does not reach for kill -0 (cross-user discovery)" {
body=$(declare -f is_party_alive)
@test "party_conn_state does not reach for kill -0 (cross-user discovery)" {
body=$(declare -f party_conn_state)
[[ "$body" != *"kill "* ]] || { echo "$body"; false; }
}
@test "is_party_alive rejects non-numeric PID without invoking tmux" {
! PARTY_TMUX=/nonexistent/should-not-be-called \
is_party_alive "" /tmp/should-not-matter
! PARTY_TMUX=/nonexistent/should-not-be-called \
is_party_alive "abc" /tmp/should-not-matter
}
@test "is_party_alive returns nonzero when tmux server is absent" {
# Numeric PID, but no live tmux server at the socket path: tmux call
# fails the handshake and the function returns nonzero. Uses PID 1
# to also confirm a foreign-uid PID is not preventing the result.
! is_party_alive 1 "$PARTY_TMP/no-such-sock"
@test "party_conn_state answers dead when no tmux server is at the socket" {
[ "$(party_conn_state "$PARTY_TMP/no-such-sock")" = dead ]
}
@test "validate_socket_dir_parent refuses whitespace in PARTY_SOCKET_DIR" {

View file

@ -61,7 +61,7 @@ setup() {
}
# Helper: write a $PARTY_TMUX stub that exits with the given code on
# every invocation. Used to test is_party_alive's tmux probe in isolation.
# every invocation. Used to test party_conn_state's probe in isolation.
_stub_tmux() {
cat > "$PARTY_TMP/tmux-stub" <<EOF
#!/bin/sh
@ -71,42 +71,28 @@ EOF
PARTY_TMUX="$PARTY_TMP/tmux-stub"
}
@test "is_party_alive: tmux probe ok → true (regardless of PID liveness)" {
# Liveness is decided by the tmux probe alone; the PID arg is kept for
# caller-API compatibility and numeric-validation, but is not signal-
# probed (POSIX kill(2) returns EPERM cross-user on illumos/BSD/macOS,
# which broke cross-user discovery in earlier revisions). With a stub
# tmux returning 0, both a live and a never-existed PID must pass.
@test "party_conn_state: silent rc-0 probe answers ok" {
_stub_tmux 0
( sleep 30 ) &
pid=$!
is_party_alive "$pid" /dev/null
kill "$pid" 2>/dev/null
wait "$pid" 2>/dev/null || true
# Same PID, now reaped — tmux stub still says yes, so still alive.
is_party_alive "$pid" /dev/null
# And a PID we never owned (init/launchd, root) — likewise alive.
is_party_alive 1 /dev/null
[ "$(party_conn_state /dev/null)" = ok ]
}
@test "is_party_alive: empty/non-numeric PID → false" {
_stub_tmux 0
! is_party_alive "" /dev/null
! is_party_alive "abc" /dev/null
}
@test "is_party_alive: tmux probe fails → false" {
# PID-reuse / planted nc -lU socket scenario: the socket isn't a real
# tmux server, so the tmux handshake fails. is_party_alive rejects
# regardless of PID state (regression seen cross-user on illumos
# native).
@test "party_conn_state: failing probe answers dead" {
# PID-reuse / planted nc -lU socket scenario: nothing at the socket
# speaks the tmux protocol, so the probe fails and the party is dead,
# regardless of any PID recorded in the roster.
_stub_tmux 1
( sleep 30 ) &
pid=$!
! is_party_alive "$pid" /dev/null
kill "$pid" 2>/dev/null
wait "$pid" 2>/dev/null || true
! is_party_alive 1 /dev/null
[ "$(party_conn_state /dev/null)" = dead ]
}
@test "party_conn_state: rc 0 with stderr output answers unauthorized" {
cat > "$PARTY_TMP/tmux-stub" <<'EOF'
#!/bin/sh
echo "access not allowed" >&2
exit 0
EOF
chmod +x "$PARTY_TMP/tmux-stub"
PARTY_TMUX="$PARTY_TMP/tmux-stub"
[ "$(party_conn_state /dev/null)" = unauthorized ]
}
@test "roster_list returns full record paths under PARTY_SOCKET_DIR" {

View file

@ -45,7 +45,7 @@ EOF
[[ "$output" == *"no parties"* ]]
}
# Cross-user discovery regression. Earlier revisions of is_party_alive
# Cross-user discovery regression. Earlier revisions of party_conn_state
# probed the PID with `kill -0`, which returns EPERM under POSIX semantics
# when the caller can't signal the target — illumos, all BSDs, and macOS
# honor that, so guests couldn't discover parties hosted by other users

View file

@ -15,7 +15,7 @@ setup() {
# default 'party' group existing on the host.
export TMUX_PARTY_GROUP="$(id -gn)"
# Spawn a long-lived sleeper so cmd_list's is_party_alive check sees a
# Spawn a long-lived sleeper so cmd_list's party_conn_state check sees a
# live PID for the "fake server". setup_party_sandbox provides PARTY_TMP.
( exec sleep 60 ) &
export FAKE_SERVER_PID=$!
@ -23,7 +23,7 @@ setup() {
# Recorder: appends every invocation to TMUX_LOG, fakes the few tmux
# subcommands cmd_host depends on (creating a placeholder socket file,
# answering display-message -p '#{pid}' with the sleeper's PID so
# is_party_alive sees it as live), and returns 0 for the rest.
# party_conn_state sees it as live), and returns 0 for the rest.
export TMUX_LOG="$PARTY_TMP/tmux.log"
: > "$TMUX_LOG"
cat > "$PARTY_TMP/tmux-stub" <<'STUB'
@ -711,7 +711,7 @@ STUB
# Parity with test 76 ('cmd_list skips parties...'), but for the join
# resolver. A roster can have a live SERVER_PID (PID reuse, init's pid 1)
# and an [ -S ]-passing socket (planted via `nc -lU`) yet not be a real
# tmux server. is_party_alive must probe list-clients on every resolver,
# tmux server. party_conn_state must probe list-clients on every resolver,
# not just cmd_list — otherwise `party join
# imposter` would resolve to the imposter and try to attach.
legit_dir="$PARTY_SOCKET_DIR/party-$USER:legit2.d"