Relationships
#845 copy/rsync ignores transport extraOptions (and proxyCommand), unlike exec/script
Opened by atalanta · 6/26/2026· Shipped 6/28/2026
Problem
When a host's ssh transport sets extraOptions (or proxyCommand), those options are applied to exec and script but silently dropped for copy when useRsync: true. This makes it impossible to express, for a copy/rsync, anything that isn't identityFile/proxyJump/port — most importantly a custom ProxyCommand.
Why this bites
OpenSSH's -J <user@host> does not propagate the command-line -i to the jump hop — each hop resolves its own identity from ssh_config. With no ssh_config entry for the jump host, the jump leg offers the user's default keys and is denied. The documented-in-the-wild workaround is to supply an explicit ProxyCommand that carries -i on the jump leg, via the transport's extraOptions. This works for exec/script but not for rsync copies, so a fleet that can run commands through a jump host cannot deploy files through the same jump host.
Evidence (models/_lib/runner.ts @ 2026.06.04.2)
sshCommonOpts() (used by exec/script) appends both proxyCommand and extraOptions:
if (t.proxyCommand !== undefined) o.push('-o', `ProxyCommand=${t.proxyCommand}`);
for (const extra of t.extraOptions) o.push('-o', extra);
...
if (t.proxyJump !== undefined) o.push('-J', t.proxyJump);
if (t.identityFile !== undefined) o.push('-i', t.identityFile);But buildRsyncArgv() hand-rolls its own -e ssh ... string and includes only ControlPath, identityFile, proxyJump, and port — no proxyCommand, no extraOptions:
if (ctx.controlPath && t.controlMaster.enabled) sshParts.push('-o', `ControlPath=${ctx.controlPath}`);
if (t.identityFile) sshParts.push('-i', t.identityFile);
if (t.proxyJump) sshParts.push('-J', t.proxyJump);
sshParts.push('-p', String(t.port));(buildScpArgv likely has the same gap — worth checking.)
Repro
- Fleet with a host that reaches its target via a jump host, configured with
extraOptions: ['ProxyCommand=ssh -i <key> -W %h:%p user@jump']. execon that host succeeds.copy --useRsync trueto the same host fails — the emitted-e ssh ...omits the ProxyCommand, so rsync connects directly (here: times out).
Proposed fix
Have buildRsyncArgv (and buildScpArgv) reuse the same option assembly as sshCommonOpts — or at minimum also append -o ProxyCommand=... and the extraOptions entries — so copy/rsync/scp honor the full transport like exec/script do. The -e string just needs the same -o flags.
Environment
- @swamp/ssh 2026.06.04.2
- macOS, OpenSSH client; OpenBSD 7.6 target reached via a Fedora jump host (key auth both legs).
Upstream repository: https://github.com/swamp-club/swamp-extensions
Environment
- Extension:
@swamp/ssh@2026.06.04.2 - swamp:
20260626.005336.0-sha.f302d18e - OS:
darwin(aarch64) - Deno:
2.8.3 - Shell:
/bin/zsh
Shipped
Click a lifecycle step above to view its details.