feat(ssh): persistent SSH workspaces — one connection, many clean commands (PRD 0013) - #485
Merged
Conversation
…mands (PRD 0013) `moshcode ssh` / `/ssh`: named targets, one OpenSSH ControlMaster per target behind a hashed 0700 socket, open/check/close via `ssh -O`, and `exec` as a no-PTY command channel with real argv quoting, raw stdin, per-call cwd/env, timeout, and a --json object that separates the command's verdict (`ok`, `code`) from the transport's (`transportOk`). Interactive attach, scp put/get on the same socket, a remote tmux `shell` with send/read/kill, and `bench`. moshscript gets sshOpen/sshExec/sshClose and friends returning the same shape. Two OpenSSH facts found by running it: `-M` with `-o ControlMaster=yes` is read as ask mode (every mux request "Permission denied"), so the master is `-o ControlMaster=yes -N -f`; and `ControlMaster=auto` on a client is the native stale-socket recovery, so exec runs with it. Tests: 35 unit tests with a fake runner, 13 against an ephemeral non-root sshd on loopback (skipped where sshd is absent). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RcmWsBrbzQpfTTz71wfbkw
ThreatCrush Security Scan3 finding(s) in the 10 file(s) this pull request changes. MEDIUM: 3
88 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 8 | **MEDIUM**: 70 | **LOW**: 10Not introduced by this pull request. The full set is in the Security tab.
…and 68 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
ralyodio
marked this pull request as ready for review
September 3, 2026 16:37
Merged
ralyodio
added a commit
that referenced
this pull request
Sep 3, 2026
`moshcode ssh` — persistent SSH workspaces (#485, PRD 0013): named targets, one OpenSSH ControlMaster per target, `exec` as a no-PTY command channel with a --json verdict that separates the command's exit from the transport's, interactive attach, scp put/get, a remote tmux shell, and moshscript helpers. Claude-Session: https://claude.ai/code/session_01RcmWsBrbzQpfTTz71wfbkw Co-authored-by: Claude Fable 5.1 <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.
Implements PRD 0013 — persistent SSH workspaces (
moshcode ssh//ssh): one authenticated OpenSSH connection per named target, and a clean command channel for every call.What
src/ssh.mjs— the whole feature, zero dependencies, OpenSSH on PATH is the implementation:~/.moshcode/ssh/targets.json(host or~/.ssh/configalias, port, cwd, persist) — written atomically at 0600, secret-shaped fields dropped on read~/.moshcode/ssh/control, or$TMPDIR/moshcode-ssh-<uid>when the home path would overflowsun_path)open/check/closeviassh -O check/-O exit— no PID tracking; stale sockets are detected, unlinked, reopened, and a mid-command transport failure is retried onceexec: argv →cd -- '<cwd>' && K='v' exec 'cmd' 'args'with POSIX quoting,-T(no PTY) by default,--tty, raw--stdin,--cwd,--env,--timeout,--shfor a deliberate pipeline;--jsonreturns{ ok, transportOk, code, signal, stdout, stderr, durationMs }whereokis the command's verdict andtransportOkis ssh's (exit 255)moshcode ssh <name>hands the terminal to ssh over the same master, landing in the target's cwdput/getover scp on the same socket;putlands as a temp file and is renamedshell— a namespaced remote tmux session withsend/read/kill/list; says so when tmux is missing andexeckeeps workingbench <name>measures fresh vs multiplexed on the user's own host (loopback here: ~96ms → ~12ms median)SSH_VERBS,PIT_COMMANDS); README command table regenerated; new## SSH workspacesREADME sectionsshOpen,sshCheck,sshExec(returns the same object as--json),sshClose,sshPut,sshGet,sshShellSend/Read/Kill, plusssh(...)as a cliVerbprd/0013-persistent-ssh-workspaces.md(0012 was already billing)Two OpenSSH facts that shaped it (both found by running it)
-Mtogether with-o ControlMaster=yesis read as a second request for master mode, i.e. ask mode — every mux client then gets "Master refused session request: Permission denied". The PRD's conceptual-MNfinvocation has this flaw; the implementation uses-o ControlMaster=yes -N -fand no-M.ControlMaster=autoon the client is the native stale-socket recovery: a dead socket is unlinked and the client becomes the new master.execruns withauto.Tests
test/ssh.test.mjs(35 tests, no network): names, registry + permissions, socket hashing + long-home fallback, durations, quoting, argv for master/exec/attach/scp, keepalive probing, transport-vs-command classification, debug redaction, check/open/close lifecycle, exec cwd/env/stdin/timeout/retry/auth-failure/no-ssh, CLI JSON shapes and exit codes, shell verbstest/ssh-sshd.test.mjs(13 tests): an ephemeral non-rootsshdon loopback with generated keys and a privatessh_config(skips cleanly where sshd is absent) — open/check/close, printf/failing command/stdin bytes/cwd/env/--sh, timeout, 6 parallel CLI execs on one master, killed-master recovery, auth failure, nothing-listening, changed host key refused, put/get, CLI end to end, bench, remote tmux state persistence, tmux-missingSecurity posture
Never passes
StrictHostKeyChecking=no, never stores a password or key, never auto-accepts a host key,BatchMode=yesonly when stdin is not a terminal (or--batch), debug output summarises the remote command by byte count so--envvalues are never logged, stdin is never logged.🤖 Generated with Claude Code
https://claude.ai/code/session_01RcmWsBrbzQpfTTz71wfbkw