Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bin/fm-harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ detect_own() {
local pid=$$ comm args
for _ in 1 2 3 4 5 6 7 8; do
comm=$(ps -o comm= -p "$pid" 2>/dev/null) || break
case "$(basename "$comm")" in
# Strip the directory with parameter expansion, not basename: a login shell
# reports itself as "-zsh", which basename parses as option flags and
# rejects. It also avoids a subprocess on every hop of this walk.
case "${comm##*/}" in
*claude*) echo claude; return ;;
*codex*) echo codex; return ;;
*opencode*) echo opencode; return ;;
Expand Down
7 changes: 5 additions & 2 deletions bin/fm-session-lock-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ fm_harness_ancestry_pid() {
for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
comm=$(ps -o comm= -p "$pid" 2>/dev/null) || break
args=$(ps -o args= -p "$pid" 2>/dev/null)
bc=$(basename "$comm")
# Strip the directory with parameter expansion, not basename: a login shell
# reports itself as "-zsh", which basename parses as option flags and
# rejects. It also avoids a subprocess on every hop of this walk.
bc=${comm##*/}
hit=0; is_claude=0
if printf '%s' "$bc" | grep -qE "$FM_HARNESS_RE"; then
hit=1
Expand Down Expand Up @@ -69,7 +72,7 @@ fm_harness_pid_alive() {
local pid=$1 comm args
kill -0 "$pid" 2>/dev/null || return 1
comm=$(ps -o comm= -p "$pid" 2>/dev/null) || return 1
if printf '%s' "$(basename "$comm")" | grep -qE "$FM_HARNESS_RE"; then
if printf '%s' "${comm##*/}" | grep -qE "$FM_HARNESS_RE"; then
return 0
fi
case "$comm" in
Expand Down
77 changes: 70 additions & 7 deletions tests/fm-secondmate-harness.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,19 @@ esac
SH
chmod +x "$fakebin/ps"

got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE -u FM_PI_HARNESS PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "unmarked shared signed-wrapper ancestry resolved '$got', expected pi"
got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi-signed "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi-signed "$ROOT/bin/fm-harness.sh")
[ "$got" = pi-signed ] || fail "selected signed wrapper resolved '$got', expected pi-signed"
got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "selected plain Pi resolved '$got', expected pi"
got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi-signed-helper "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_PI_HARNESS=pi-signed-helper "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "inexact signed selection marker resolved '$got', expected pi"
got=$(PATH="$fakebin:$BASE_PATH" FM_PI_HARNESS=pi-signed "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE -u PI_CODING_AGENT -u GROK_AGENT PATH="$fakebin:$BASE_PATH" FM_PI_HARNESS=pi-signed "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "signed selection marker without Pi's family marker resolved '$got', expected pi"
got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_TEST_SIGNED_SHAPE=plain "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE -u FM_PI_HARNESS PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_TEST_SIGNED_SHAPE=plain "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "plain Pi marker resolved '$got', expected pi"
got=$(PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_TEST_SIGNED_SHAPE=helper "$ROOT/bin/fm-harness.sh")
got=$(env -u CLAUDECODE -u FM_PI_HARNESS PATH="$fakebin:$BASE_PATH" PI_CODING_AGENT=true FM_TEST_SIGNED_SHAPE=helper "$ROOT/bin/fm-harness.sh")
[ "$got" = pi ] || fail "unrelated pi-signed-helper ancestry resolved '$got', expected pi"

got=$(PATH="$fakebin:$BASE_PATH" bash -c \
Expand All @@ -188,6 +188,68 @@ SH
pass "pi-signed identity: authoritative launch selection distinguishes shared wrapper ancestry"
}

# ===========================================================================
# A) login-shell process names in the ancestry walk
# ===========================================================================
# macOS reports a login shell through `ps -o comm=` with a leading dash ("-zsh").
# Passing that to basename makes it parse "-z -s -h" as option flags and fail
# loudly on stderr at every hop that reaches a login shell, so both ancestry
# walks strip the directory with parameter expansion instead.
test_login_shell_process_name_in_ancestry() {
local dir fakebin got err
dir="$TMP_ROOT/login-shell-ancestry"
fakebin=$(fm_fakebin "$dir")
cat > "$fakebin/ps" <<'SH'
#!/usr/bin/env bash
set -u
field= pid=
while [ "$#" -gt 0 ]; do
case "$1" in
-o) field=$2; shift 2 ;;
-p) pid=$2; shift 2 ;;
*) shift ;;
esac
done
# 300 is the login shell whose name starts with a dash; 400 above it is a real
# harness, so the walk must survive 300 and still resolve the harness.
case "$pid:$field" in
300:comm=) printf '%s\n' '-zsh' ;;
300:args=) printf '%s\n' '-zsh' ;;
300:ppid=) printf '%s\n' 400 ;;
400:comm=) printf '%s\n' '/opt/test/bin/codex' ;;
400:args=) printf '%s\n' 'codex' ;;
400:ppid=) printf '%s\n' 1 ;;
*:comm=) printf '%s\n' /bin/bash ;;
*:args=) printf '%s\n' bash ;;
*:ppid=) printf '%s\n' 300 ;;
esac
SH
chmod +x "$fakebin/ps"

err="$dir/harness.err"
got=$(env -u CLAUDECODE -u PI_CODING_AGENT -u GROK_AGENT \
PATH="$fakebin:$BASE_PATH" FM_CONFIG_OVERRIDE="$dir/config" \
"$ROOT/bin/fm-harness.sh" 2>"$err")
[ "$got" = codex ] || fail "harness detection past a login shell resolved '$got', expected codex"
[ ! -s "$err" ] || fail "harness detection wrote to stderr: $(cat "$err")"

err="$dir/lock.err"
got=$(PATH="$fakebin:$BASE_PATH" bash -c \
'. "$0/bin/fm-session-lock-lib.sh"; fm_harness_ancestry_pid' "$ROOT" 2>"$err")
[ "$got" = 400 ] || fail "session-lock ancestry past a login shell selected '$got', expected 400"
[ ! -s "$err" ] || fail "session-lock ancestry wrote to stderr: $(cat "$err")"

err="$dir/alive.err"
if PATH="$fakebin:$BASE_PATH" bash -c \
'. "$0/bin/fm-session-lock-lib.sh"; kill() { return 0; }; fm_harness_pid_alive 300' \
"$ROOT" 2>"$err"; then
fail "session-lock liveness accepted a login shell as a harness holder"
fi
[ ! -s "$err" ] || fail "session-lock liveness wrote to stderr: $(cat "$err")"

pass "A) a login-shell process name ('-zsh') traverses both ancestry walks without stderr noise"
}

# ===========================================================================
# B) propagate_inheritable_config unit behavior
# ===========================================================================
Expand Down Expand Up @@ -2246,6 +2308,7 @@ SH
test_harness_resolution
test_secondmate_model_effort_tokens
test_pi_signed_detection_and_session_lock_identity
test_login_shell_process_name_in_ancestry
test_propagate_lib
test_spawn_split_and_inherit
test_spawn_backward_compat_crew_fallback
Expand Down