Harden cmux ssh for mixed-version remote sessions
This commit is contained in:
parent
2b7928aa60
commit
daa340fa87
8 changed files with 142 additions and 31 deletions
|
|
@ -8,7 +8,7 @@ Go remote daemon for `cmux ssh` bootstrap, capability negotiation, and CLI relay
|
|||
2. `cmuxd-remote serve --stdio`
|
||||
3. `cmuxd-remote cli <command> [args...]` — relay cmux commands to the local app over the reverse TCP forward
|
||||
|
||||
When invoked as `cmux` (via symlink created during bootstrap), the binary auto-dispatches to the `cli` subcommand. This is busybox-style argv[0] detection.
|
||||
When invoked as `cmux` (via wrapper/symlink installed during bootstrap), the binary auto-dispatches to the `cli` subcommand. This is busybox-style argv[0] detection.
|
||||
|
||||
## RPC methods (newline-delimited JSON over stdio)
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ When invoked as `cmux` (via symlink created during bootstrap), the binary auto-d
|
|||
|
||||
## CLI relay
|
||||
|
||||
The `cli` subcommand (or `cmux` symlink) connects to the local cmux app's socket through an SSH reverse TCP forward and relays commands. It supports both v1 text protocol and v2 JSON-RPC commands.
|
||||
The `cli` subcommand (or `cmux` wrapper/symlink) connects to the local cmux app's socket through an SSH reverse TCP forward and relays commands. It supports both v1 text protocol and v2 JSON-RPC commands.
|
||||
|
||||
Socket discovery order:
|
||||
1. `--socket <path>` flag
|
||||
|
|
@ -31,5 +31,6 @@ For TCP addresses, the CLI retries for up to 15 seconds on connection refused, r
|
|||
1. `workspace.remote.configure` bootstraps this binary over SSH when missing.
|
||||
2. Client sends `hello` before enabling remote port probing/forwarding.
|
||||
3. Daemon status/capabilities are exposed in `workspace.remote.status -> remote.daemon`.
|
||||
4. Bootstrap creates `~/.cmux/bin/cmux` symlink pointing to the daemon binary.
|
||||
4. Bootstrap installs `~/.cmux/bin/cmux` wrapper and keeps a default daemon target (`~/.cmux/bin/cmuxd-remote-current`).
|
||||
5. A background `ssh -N -R` process reverse-forwards a TCP port to the local cmux Unix socket. The relay address is written to `~/.cmux/socket_addr` on the remote.
|
||||
6. Relay startup writes `~/.cmux/relay/<port>.daemon_path` so the wrapper can route each shell to the correct daemon binary when multiple local cmux instances/versions coexist.
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ func runCLI(args []string) int {
|
|||
i++
|
||||
case "--json":
|
||||
jsonOutput = true
|
||||
case "--help", "-h":
|
||||
cliUsage()
|
||||
return 0
|
||||
default:
|
||||
remaining = append(remaining, args[i:]...)
|
||||
goto doneFlags
|
||||
|
|
@ -104,6 +107,12 @@ doneFlags:
|
|||
cliUsage()
|
||||
return 2
|
||||
}
|
||||
cmdName := remaining[0]
|
||||
cmdArgs := remaining[1:]
|
||||
if cmdName == "help" {
|
||||
cliUsage()
|
||||
return 0
|
||||
}
|
||||
|
||||
// refreshAddr is set when the address came from socket_addr file (not env/flag),
|
||||
// allowing retry loops to pick up updated relay ports.
|
||||
|
|
@ -117,9 +126,6 @@ doneFlags:
|
|||
return 1
|
||||
}
|
||||
|
||||
cmdName := remaining[0]
|
||||
cmdArgs := remaining[1:]
|
||||
|
||||
// Special case: "rpc" passthrough
|
||||
if cmdName == "rpc" {
|
||||
return runRPC(socketPath, cmdArgs, jsonOutput, refreshAddr)
|
||||
|
|
|
|||
|
|
@ -381,6 +381,20 @@ func TestCLINoArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCLIHelpFlag(t *testing.T) {
|
||||
code := runCLI([]string{"--help"})
|
||||
if code != 0 {
|
||||
t.Fatalf("--help should return 0, got %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCLIHelpCommand(t *testing.T) {
|
||||
code := runCLI([]string{"help"})
|
||||
if code != 0 {
|
||||
t.Fatalf("help should return 0, got %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlagToParamKey(t *testing.T) {
|
||||
tests := []struct {
|
||||
input, expected string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue