Skip to content

Commit 2c7fc8b

Browse files
committed
fix(pty-proxy): resolve SHELL path in proxied zsh sessions
1 parent c0834ed commit 2c7fc8b

1 file changed

Lines changed: 33 additions & 10 deletions

File tree

crates/atuin-pty-proxy/src/pty_proxy.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,22 @@ fn render_init(shell: Shell) -> &'static str {
164164
if [[ -n "${BASH_VERSION:-}" ]]; then
165165
exec atuin pty-proxy --shell "$BASH"
166166
elif [[ -n "${ZSH_VERSION:-}" ]]; then
167-
# Prefer ZSH_ARGZERO (zsh 5.3+) — it preserves the path zsh was
168-
# invoked with — and fall back to PATH lookup otherwise. Login shells
169-
# set argv[0] to "-zsh", and ZSH_ARGZERO keeps that leading dash, so
170-
# strip it (${var#-}) before passing the path along.
171-
_atuin_pty_proxy_zsh="${ZSH_ARGZERO:-$(command -v zsh)}"
172-
exec atuin pty-proxy --shell "${_atuin_pty_proxy_zsh#-}"
167+
# Resolve zsh to the same executable that launched this init script.
168+
# ZSH_ARGZERO preserves argv0, including the leading dash used by login
169+
# shells, so normalize it before choosing a shell path.
170+
_atuin_pty_proxy_zsh_argv0="${ZSH_ARGZERO:-zsh}"
171+
_atuin_pty_proxy_zsh_argv0="${_atuin_pty_proxy_zsh_argv0#-}"
172+
if [[ "$_atuin_pty_proxy_zsh_argv0" == */* ]]; then
173+
# argv0 already contains a path, so it identifies the spawned zsh.
174+
_atuin_pty_proxy_shell="$_atuin_pty_proxy_zsh_argv0"
175+
elif [[ -f "${SHELL:-}" ]] && [[ -x "${SHELL:-}" ]] && [[ "${SHELL##*/}" == "$_atuin_pty_proxy_zsh_argv0" ]]; then
176+
# Bare argv0: prefer the matching login shell path over PATH lookup.
177+
_atuin_pty_proxy_shell="$SHELL"
178+
else
179+
# Last resort: resolve the bare shell name from PATH.
180+
_atuin_pty_proxy_shell="$(command -v "$_atuin_pty_proxy_zsh_argv0")"
181+
fi
182+
exec atuin pty-proxy --shell "$_atuin_pty_proxy_shell"
173183
else
174184
exec atuin pty-proxy
175185
fi
@@ -252,10 +262,23 @@ mod tests {
252262
fn init_scripts_forward_shell_path() {
253263
let posix = render_init(Shell::Bash);
254264
assert!(posix.contains(r#"exec atuin pty-proxy --shell "$BASH""#));
255-
// zsh: capture ZSH_ARGZERO (with PATH fallback), then strip the
256-
// leading dash present on login shells before forwarding the path.
257-
assert!(posix.contains(r#"_atuin_pty_proxy_zsh="${ZSH_ARGZERO:-$(command -v zsh)}""#));
258-
assert!(posix.contains(r#"exec atuin pty-proxy --shell "${_atuin_pty_proxy_zsh#-}""#));
265+
// zsh: capture ZSH_ARGZERO, strip the leading dash present on login
266+
// shells, and resolve bare shell names to the spawning shell before
267+
// forwarding the path.
268+
assert!(posix.contains(r#"_atuin_pty_proxy_zsh_argv0="${ZSH_ARGZERO:-zsh}""#));
269+
assert!(posix.contains(r#"_atuin_pty_proxy_zsh_argv0="${_atuin_pty_proxy_zsh_argv0#-}""#));
270+
assert!(posix.contains(r#"if [[ "$_atuin_pty_proxy_zsh_argv0" == */* ]]; then"#));
271+
assert!(posix.contains(r#"_atuin_pty_proxy_shell="$_atuin_pty_proxy_zsh_argv0""#));
272+
assert!(posix.contains(
273+
r#"elif [[ -f "${SHELL:-}" ]] && [[ -x "${SHELL:-}" ]] && [[ "${SHELL##*/}" == "$_atuin_pty_proxy_zsh_argv0" ]]; then"#
274+
));
275+
assert!(posix.contains(r#"_atuin_pty_proxy_shell="$SHELL""#));
276+
assert!(
277+
posix.contains(
278+
r#"_atuin_pty_proxy_shell="$(command -v "$_atuin_pty_proxy_zsh_argv0")""#
279+
)
280+
);
281+
assert!(posix.contains(r#"exec atuin pty-proxy --shell "$_atuin_pty_proxy_shell""#));
259282

260283
let fish = render_init(Shell::Fish);
261284
assert!(fish.contains("exec atuin pty-proxy --shell (status fish-path)"));

0 commit comments

Comments
 (0)