diff --git a/bin/fm-primary.sh b/bin/fm-primary.sh index d99e81290b9..c918dae9460 100755 --- a/bin/fm-primary.sh +++ b/bin/fm-primary.sh @@ -24,11 +24,12 @@ # They never change config/crew-harness, config/secondmate-harness, dispatch # profiles, or fm-spawn's independently verified worker-adapter set. # -# Every launch resolves the repository root from this tracked script, changes -# to that root, refuses another live Firstmate lock holder, checks the selected -# CLI and its tracked primary integrations, marks only the current terminal -# surface, then execs the CLI so sessions persist normally and the CLI exit -# status is returned with no launcher process left behind. +# Every launch dereferences up to 40 absolute or relative symlink hops from the +# invoked command, resolves the repository root from the resulting tracked +# script, changes to that root, refuses another live Firstmate lock holder, +# checks the selected CLI and its tracked primary integrations, marks only the +# current terminal surface, then execs the CLI so sessions persist normally and +# the CLI exit status is returned with no launcher process left behind. # # Kimi 0.27.0 is primary-only. # The launcher requires that exact empirically verified version and builds a @@ -51,8 +52,27 @@ # as the captain's FIRSTMATE. set -u -SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P) -FM_ROOT=$(CDPATH='' cd -- "$SCRIPT_DIR/.." && pwd -P) +resolve_script_path() { + local source=$1 dir target hops=0 + while [ -L "$source" ]; do + hops=$((hops + 1)) + if [ "$hops" -gt 40 ]; then + printf 'fm-primary: refusing to resolve more than 40 symlink hops: %s\n' "$1" >&2 + return 1 + fi + dir=$(CDPATH='' cd -P -- "$(dirname -- "$source")" && pwd -P) || return 1 + target=$(readlink "$source") || return 1 + case "$target" in + /*) source=$target ;; + *) source=$dir/$target ;; + esac + done + printf '%s\n' "$source" +} + +SCRIPT_PATH=$(resolve_script_path "${BASH_SOURCE[0]}") || exit 1 +SCRIPT_DIR=$(CDPATH='' cd -P -- "$(dirname -- "$SCRIPT_PATH")" && pwd -P) +FM_ROOT=$(CDPATH='' cd -P -- "$SCRIPT_DIR/.." && pwd -P) FM_HOME=${FM_HOME:-$FM_ROOT} STATE=${FM_STATE_OVERRIDE:-$FM_HOME/state} DATA=${FM_DATA_OVERRIDE:-$FM_HOME/data} diff --git a/tests/fm-primary.test.sh b/tests/fm-primary.test.sh index d90391461f7..4eb5d0fd23d 100755 --- a/tests/fm-primary.test.sh +++ b/tests/fm-primary.test.sh @@ -170,12 +170,22 @@ test_visible_role_marks_only_current_surface() { } test_shim_install_safety() { - local shimdir="$TMP_ROOT/shims" out status=0 + local shimdir="$TMP_ROOT/shims" chain="$TMP_ROOT/relative-chain" out status=0 out=$(FM_PRIMARY_SHIM_DIR="$shimdir" "$ROOT/bin/fm-primary.sh" --install-shim) [ -L "$shimdir/firstmate" ] || fail "opt-in shim was not installed" [ "$(readlink "$shimdir/firstmate")" = "$ROOT/bin/fm-primary.sh" ] || fail "shim target is wrong" - assert_contains "$(FM_PRIMARY_SHIM_DIR="$shimdir" "$ROOT/bin/fm-primary.sh" --install-shim)" 'already installed' \ - "exact shim reinstall was not idempotent" + out=$(PATH="$FAKEBIN:$PATH" FM_HOME="$HOME_FIX" FM_PRIMARY_DRY_RUN=1 \ + FM_PRIMARY_TEST_LOG="$LOG" FM_KIMI_SOURCE_HOME="$KIMI_SOURCE" "$shimdir/firstmate" kimi) + assert_contains "$out" "root=$ROOT" "installed shim did not launch from the tracked root" + assert_contains "$out" 'profile=kimi-k3' "installed shim did not expand the Kimi alias" + assert_contains "$out" "'kimi' '--model' 'kimi-code/k3' '--yolo'" \ + "installed shim did not reach the Kimi primary launch path" + mkdir -p "$chain" + ln -s "../$(basename "$shimdir")/firstmate" "$chain/firstmate" + out=$(PATH="$FAKEBIN:$PATH" FM_HOME="$HOME_FIX" FM_PRIMARY_DRY_RUN=1 "$chain/firstmate" pi) + assert_contains "$out" "root=$ROOT" "relative chained shim did not resolve the tracked root" + assert_contains "$(FM_PRIMARY_SHIM_DIR="$shimdir" "$shimdir/firstmate" --install-shim)" 'already installed' \ + "exact shim reinstall through the installed command was not idempotent" rm "$shimdir/firstmate" printf 'unrelated\n' > "$shimdir/firstmate" out=$(FM_PRIMARY_SHIM_DIR="$shimdir" "$ROOT/bin/fm-primary.sh" --install-shim 2>&1) || status=$?