Skip to content

fix: sidebar crash under non-POSIX shells (fish), Alt+digit highlight, and pane-close killing the session#46

Open
panosAthDBX wants to merge 5 commits into
Ataraxy-Labs:mainfrom
panosAthDBX:fix/sidebar-spawn-and-switch-highlight
Open

fix: sidebar crash under non-POSIX shells (fish), Alt+digit highlight, and pane-close killing the session#46
panosAthDBX wants to merge 5 commits into
Ataraxy-Labs:mainfrom
panosAthDBX:fix/sidebar-spawn-and-switch-highlight

Conversation

@panosAthDBX
Copy link
Copy Markdown

@panosAthDBX panosAthDBX commented May 29, 2026

Three self-contained bug fixes, independent of the larger Rust-parity work in #45. (These commits also appear in #45; whichever merges first, the other rebases cleanly.)

1. Sidebar pane crashes immediately under a non-POSIX default shell (e.g. fish)

spawn_sidebar emits a POSIX command (FOO=bar exec …; "${VAR:-default}") that tmux runs via the user's default-command / default-shell. Under fish (or csh) it can't be parsed and the sidebar pane dies with status 127 before start.sh runs — the sidebar never appears. Wrapped in sh -c '…'; env-var values are double-quoted so session names with spaces don't word-split.

2. Alt+digit session switch doesn't move the sidebar highlight

switch_visible_index switched the tmux session but never updated focused_session, which is what the sidebar highlight follows — so after Alt+1/2/… the highlight stayed on the previously focused session (the arrow-key move_focus path already updated it). Now sets focused_session to the switched-to session.

3. Closing the last work pane in a window kills the whole session

kill_orphaned_sidebar_panes killed any sidebar whose window had no other panes. Closing the last work pane left the sidebar alone → it was killed → the window had zero panes → tmux destroyed the window, and the session if it was its last (with detach-on-destroy on, the client then detaches, so it looks like the session "closed"). Now a lone sidebar is only reclaimed when its session has other windows; otherwise it's kept so the session survives and focus lands on the sidebar.

Testing

cargo test --workspace is green. Regression tests added/extended for all three fixes.

This pull request and its description were written by Isaac.

spawn_sidebar emitted a POSIX command (FOO=bar exec ...; ${VAR:-default}) that tmux runs via the user's default-command/default-shell. Under a non-POSIX shell (e.g. fish) it fails to parse and the sidebar pane dies with status 127 before start.sh runs. Wrap the command in sh -c '...' (escaping single quotes) so it is interpreted by a POSIX shell regardless of the user's interactive shell.

Co-authored-by: Isaac
Double-quote OPENSESSIONS_SESSION_NAME / WINDOW_ID / REFOCUS_WINDOW values inside the sh -c command so a session name with spaces (or other word-splitting chars) does not break the launcher. Single quotes are still escaped for the sh -c wrapper. Addresses inspect review findings 2, 5.

Co-authored-by: Isaac
…index

switch_visible_index switched the tmux session but never updated focused_session, so the sidebar highlight (which follows focused_session) stayed on the previously selected session after an Alt+digit switch. Set focused_session to the target, mirroring move_focus.

Co-authored-by: Isaac
Copy link
Copy Markdown

@inspect-review inspect-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inspect review

Triage: 6 entities analyzed | 0 critical, 0 high, 4 medium, 2 low
Verdict: standard_review

Findings (1)

  1. [low] Shell injection vulnerability in tmux_provider.rs spawn_sidebar: Single quotes in session_name are escaped, but double quotes are not. If session_name contains a double quote, it will break out of the inner command's double-quoted string and allow arbitrary command injection.

Reviewed by inspect | Entity-level triage found 0 high-risk changes

kill_orphaned_sidebar_panes killed any sidebar whose window had no other panes. When you closed the last work pane in a window, the sidebar was left alone and got killed, leaving the window with zero panes — which destroys the window, and the session if it was the last one (with detach-on-destroy, the client then detaches and it looks like the session 'closed'). Now only reclaim a lone sidebar when its session has other windows; otherwise keep it so the session survives and focus lands on the sidebar.

Co-authored-by: Isaac
Copy link
Copy Markdown

@inspect-review inspect-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inspect review

Triage: 9 entities analyzed | 0 critical, 0 high, 6 medium, 3 low
Verdict: standard_review

Findings (2)

  1. [low] Shell injection vulnerability in spawn_sidebar: Single quotes in session_name are not properly escaped before being used in the sh -c command. The escape logic inner.replace('\'', r"'\''") is applied to the entire command string, but session_name is already interpolated into inner before this escaping happens. An attacker-controlled session name containing single quotes could break out of the sh -c string and execute arbitrary commands.
  2. [low] Logic error in kill_orphaned_sidebar_panes: The code uses window_session.entry(pane.window_id.clone()).or_insert_with(|| pane.session_name.clone()) which means if a window_id appears in multiple sessions (which shouldn't happen in tmux but the code doesn't validate), only the first session_name will be stored. This could lead to incorrect session_has_other_windows checks when determining whether to kill orphaned sidebars.

Reviewed by inspect | Entity-level triage found 0 high-risk changes

@panosAthDBX panosAthDBX changed the title fix: sidebar crash under non-POSIX shells (fish) + Alt+digit not moving the highlight fix: sidebar crash under non-POSIX shells (fish), Alt+digit highlight, and pane-close killing the session May 29, 2026
@rs545837
Copy link
Copy Markdown
Member

thanks for this PR.

The sidebar spawn command interpolates the tmux session name and window id
into double-quoted `OPENSESSIONS_*` env assignments inside `sh -c '...'`.
The outer single-quote escaping only guards the `sh -c` wrapper; inside the
double quotes `$`, backtick, `"` and `\` stay live, so a session name like
`x"; rm -rf ~ #` could break out of the quotes and inject commands.

Add `sh_double_quote_escape()` and run the session name and window id
through it before interpolation. Backslash is escaped first so the
backslashes added for the other metacharacters are not doubled.

Regression tests cover a name with `"`, `$` and backtick (must be escaped,
breakout sequence must not appear) and a name with a single quote (must
survive the outer `'\''` wrap). The existing benign-name test is unchanged,
confirming normal session names still render identically.

Co-authored-by: Isaac
Copy link
Copy Markdown

@inspect-review inspect-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inspect review

Triage: 12 entities analyzed | 0 critical, 0 high, 6 medium, 6 low
Verdict: standard_review

Findings (1)

  1. [low] In kill_orphaned_sidebar_panes, the logic for checking if a session has other windows is incorrect. It checks is_some_and(|windows| windows.len() > 1) but this will be true even when the session has only one window (the current one), because the HashSet will contain the current window_id. The check should verify that the session has windows OTHER than the current one.

Reviewed by inspect | Entity-level triage found 0 high-risk changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants