From 133311f1c4b0f8694cd40b81bea103bbaf40e46e Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 21 May 2026 18:23:11 -0700 Subject: [PATCH] Pty to find its own shell --- browsergateway/ssh_native.go | 2 +- nativessh/pty.go | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/browsergateway/ssh_native.go b/browsergateway/ssh_native.go index 91509b0..a2ac8e9 100644 --- a/browsergateway/ssh_native.go +++ b/browsergateway/ssh_native.go @@ -34,7 +34,7 @@ func serveNativeSSHSession(ctx context.Context, ws *websocket.Conn, cfg NativeSS log.Printf("SSH native: spawning shell") - sess, err := nativessh.NewPTYSession(cfg.Shell) + sess, err := nativessh.NewPTYSession() if err != nil { sendSSHError(ctx, ws, fmt.Sprintf("Failed to spawn shell: %v", err)) return fmt.Errorf("pty session: %w", err) diff --git a/nativessh/pty.go b/nativessh/pty.go index f35531a..ee03295 100644 --- a/nativessh/pty.go +++ b/nativessh/pty.go @@ -15,11 +15,21 @@ type PTYSession struct { cmd *exec.Cmd } -// NewPTYSession spawns shell in a PTY. If shell is empty, /bin/sh is used. -func NewPTYSession(shell string) (*PTYSession, error) { - if shell == "" { - shell = "/bin/sh" +// findShell returns the path to the best available interactive shell by +// checking preferred shells in order, falling back to /bin/sh. +func findShell() string { + preferred := []string{"zsh", "bash", "fish", "ksh", "sh"} + for _, name := range preferred { + if path, err := exec.LookPath(name); err == nil { + return path + } } + return "/bin/sh" +} + +// NewPTYSession spawns the best available shell in a PTY. +func NewPTYSession() (*PTYSession, error) { + shell := findShell() cmd := exec.Command(shell) cmd.Env = append(os.Environ(), "TERM=xterm-256color") ptmx, err := pty.Start(cmd)