fix(remote): per-user SSH socket isolation + tunnel/iTerm2 jump hardening (#193, #190, #198)#201
Merged
Merged
Conversation
…jump - #193: the remote SSH socket was hardcoded to /tmp/codeisland.sock, so multiple OS users on a shared host collided. With StreamLocalBindUnlink a later user's reverse forward would unlink/rebind another user's socket, silently stealing their events. Probe the remote uid at connect time and route a per-user /tmp/codeisland-<uid>.sock through the SSH -R forward, the remote hook command (CODEISLAND_SOCKET_PATH), and the OpenCode plugin. Remote hook script also defaults to a uid-scoped path. Falls back to the legacy shared path if the probe fails. - #190: force ControlMaster=no / ControlPath=none on the tunnel so `ssh -N` doesn't hand the forward to a pre-existing multiplexing master and exit 0 immediately, which the forwarder misreads as a failed connection ("ssh exited (0)"). - #198: the iTerm2 jump now selects the matched *window* (not just tab+session) so a fullscreen / cross-Space session is raised and its Space switched to. Tests: per-user socket injection into the remote hook script and OpenCode plugin, plus the legacy fallback path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
Closed
wxtsky
added a commit
that referenced
this pull request
May 30, 2026
Follow-up hardening on #201: - Guard each iTerm2 `select <window>` with its own `try` so an unexpected failure (e.g. a window mid fullscreen-transition) can't abort the surrounding script and skip the tab/session select — that would have made the jump worse than before. - Probe the remote uid with a bare `id -u` instead of a `$(...)` pipeline so it runs identically under non-POSIX login shells (fish/csh) instead of silently falling back to the shared socket path. Also drops the redundant cleanup round-trip (StreamLocalBindUnlink already clears stale sockets on bind), so a failing host no longer waits on a second SSH. - Remove the now-unused shellSingleQuoted helper. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GeorgeDong32
pushed a commit
to GeorgeDong32/CodeIsland
that referenced
this pull request
May 31, 2026
…jump (wxtsky#201) - wxtsky#193: the remote SSH socket was hardcoded to /tmp/codeisland.sock, so multiple OS users on a shared host collided. With StreamLocalBindUnlink a later user's reverse forward would unlink/rebind another user's socket, silently stealing their events. Probe the remote uid at connect time and route a per-user /tmp/codeisland-<uid>.sock through the SSH -R forward, the remote hook command (CODEISLAND_SOCKET_PATH), and the OpenCode plugin. Remote hook script also defaults to a uid-scoped path. Falls back to the legacy shared path if the probe fails. - wxtsky#190: force ControlMaster=no / ControlPath=none on the tunnel so `ssh -N` doesn't hand the forward to a pre-existing multiplexing master and exit 0 immediately, which the forwarder misreads as a failed connection ("ssh exited (0)"). - wxtsky#198: the iTerm2 jump now selects the matched *window* (not just tab+session) so a fullscreen / cross-Space session is raised and its Space switched to. Tests: per-user socket injection into the remote hook script and OpenCode plugin, plus the legacy fallback path. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GeorgeDong32
pushed a commit
to GeorgeDong32/CodeIsland
that referenced
this pull request
May 31, 2026
…#202) Follow-up hardening on wxtsky#201: - Guard each iTerm2 `select <window>` with its own `try` so an unexpected failure (e.g. a window mid fullscreen-transition) can't abort the surrounding script and skip the tab/session select — that would have made the jump worse than before. - Probe the remote uid with a bare `id -u` instead of a `$(...)` pipeline so it runs identically under non-POSIX login shells (fish/csh) instead of silently falling back to the shared socket path. Also drops the redundant cleanup round-trip (StreamLocalBindUnlink already clears stale sockets on bind), so a failing host no longer waits on a second SSH. - Remove the now-unused shellSingleQuoted helper. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes three remote/jump robustness issues reported on the tracker.
#193 — Remote SSH socket shared across users on multi-user hosts
RemoteHost.remoteSocketPathwas hardcoded to/tmp/codeisland.sock, while the local app already uses/tmp/codeisland-<uid>.sock. On a shared remote host, withStreamLocalBindUnlink=yes, a second user's reverse forward would unlink/rebind the first user's socket, so their Claude/Codex/OpenCode hooks silently sent events to the wrong tunnel (or failed).Fix: probe the remote uid once at connect time and route a per-user
/tmp/codeisland-<uid>.sockconsistently through:-Rreverse forward (SSHForwarder)CODEISLAND_SOCKET_PATH(command_forinconfigureRemoteHooksScript)remoteOpencodePluginForInstall)codeisland-remote-hook.pynow defaults to a uid-scoped path)If the uid probe fails (older/restricted host), we fall back to the legacy shared path, so nothing regresses.
RemoteManagerresolves the path before opening the tunnel and reuses it for hook installation.#190 —
ssh exited (0), connection reported as failedThe forwarder uses
ssh -N. If the user's SSH config enables connection multiplexing (ControlMaster auto+ControlPath),ssh -Ncan hand the forward to a pre-existing master and exit 0 immediately — which the forwarder misread as a dead tunnel (matches the reporter: manualsshworks, CodeIsland shows "ssh exited (0)"). ForceControlMaster=no/ControlPath=noneso the tunnel always holds its own dedicated connection.#198 — iTerm2 fullscreen / cross-Space jump lands on the wrong window
The session-id jump path selected the matched tab + session but never selected the window, so a fullscreen window (its own Space) wasn't raised. Add
select <window>on all three iTerm2 match paths (session-id, tty, cwd) so the owning window is brought to the front and macOS switches to its Space.Tests
swift test— 333 passing.🤖 Generated with Claude Code