fix: simplify RunRemote to not re-prefix source or dest

RunRemote was adding user@host: prefixes on top of the paths already
pre-prefixed by engine.go in the remote-to-remote branch, causing
"both remote" rsync errors. The source path was also incorrectly
prefixed with srcUserHost:, making rsync reject the command entirely.

The fix: buildArgs already orders args correctly for rsync (source
then dest), so just use args[-2] and args[-1] as-is without any
additional prefixing.
This commit is contained in:
2026-07-09 21:58:02 -04:00
parent fce8962f2b
commit 5b28b46e6b
3 changed files with 19 additions and 64 deletions
+3 -26
View File
@@ -96,39 +96,16 @@ func (r *RsyncRunner) RunRemote(ctx context.Context, pair *SyncPairConfig, src *
destKey = filepath.Join(r.sshDir, "id_ed25519")
}
srcUserHost := fmt.Sprintf("%s@%s", src.SSHUser, src.Host)
args := r.buildArgs(pair)
innerSSH := fmt.Sprintf("ssh -i %s -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=%s",
destKey, filepath.Join(r.sshDir, "known_hosts"))
rsyncFlags := strings.Join(args[:len(args)-2], " ")
var sourcePath, destPath string
if pair.Direction == "pull" {
sourcePath = args[len(args)-1]
destPath = args[len(args)-2]
} else {
sourcePath = args[len(args)-2]
destPath = args[len(args)-1]
}
var remoteSrc, remoteDst string
if pair.Direction == "pull" {
remoteSrc = sourcePath
remoteDst = destPath
if !strings.Contains(destPath, "@") {
remoteDst = fmt.Sprintf("%s@%s:%s", dst.SSHUser, dst.Host, destPath)
}
} else {
remoteDst = destPath
if !strings.Contains(destPath, "@") {
remoteDst = fmt.Sprintf("%s@%s:%s", dst.SSHUser, dst.Host, destPath)
}
remoteSrc = fmt.Sprintf("%s:%s", srcUserHost, sourcePath)
}
sourcePath := args[len(args)-2]
destPath := args[len(args)-1]
remoteCmd := fmt.Sprintf("rsync %s -e %q %s %s",
rsyncFlags, innerSSH, remoteSrc, remoteDst)
rsyncFlags, innerSSH, sourcePath, destPath)
sshArgs := []string{
"-i", src.PrivKey,
+15 -37
View File
@@ -16,40 +16,15 @@ type remoteCmdTest struct {
}
func (tc remoteCmdTest) build() (srcArg, dstArg string) {
srcUserHost := tc.srcUser + "@" + tc.srcHost
dstUserHost := tc.dstUser + "@" + tc.dstHost
runner := NewRsyncRunner("/tmp/ssh", "")
args := runner.buildArgs(&SyncPairConfig{
Source: tc.srcPath,
Dest: tc.dstPath,
Direction: tc.direction,
})
var sourcePath, destPath string
if tc.direction == "pull" {
sourcePath = args[len(args)-1]
destPath = args[len(args)-2]
} else {
sourcePath = args[len(args)-2]
destPath = args[len(args)-1]
}
var remoteSrc, remoteDst string
if tc.direction == "pull" {
remoteSrc = sourcePath
remoteDst = destPath
if !strings.Contains(destPath, "@") {
remoteDst = dstUserHost + ":" + destPath
}
} else {
remoteDst = destPath
if !strings.Contains(destPath, "@") {
remoteDst = dstUserHost + ":" + destPath
}
remoteSrc = srcUserHost + ":" + sourcePath
}
return remoteSrc, remoteDst
sourcePath := args[len(args)-2]
destPath := args[len(args)-1]
return sourcePath, destPath
}
func TestBuildArgs_Push(t *testing.T) {
@@ -175,7 +150,7 @@ func TestRunRemote_PushDestNoDoublePrefix(t *testing.T) {
}
}
func TestRunRemote_PushSrcCorrectlyPrefixed(t *testing.T) {
func TestRunRemote_PushSrcAndDestStayAsIs(t *testing.T) {
tc := remoteCmdTest{
srcHost: "10.5.1.10",
srcUser: "root",
@@ -187,15 +162,15 @@ func TestRunRemote_PushSrcCorrectlyPrefixed(t *testing.T) {
}
srcArg, dstArg := tc.build()
if !strings.HasPrefix(srcArg, "root@10.5.1.10:/") {
t.Errorf("push src = %q, want prefix 'root@10.5.1.10:/'", srcArg)
if srcArg != "/share/homes/admin/media" {
t.Errorf("push src = %q, want raw path '/share/homes/admin/media' (no user@host: prefix added)", srcArg)
}
if !strings.HasPrefix(dstArg, "admin@10.5.0.144:/") {
t.Errorf("push dst = %q, want prefix 'admin@10.5.0.144:/'", dstArg)
if dstArg != "/share/media/peliculas" {
t.Errorf("push dst = %q, want raw path '/share/media/peliculas'", dstArg)
}
}
func TestRunRemote_PullSrcNotPrefixed(t *testing.T) {
func TestRunRemote_PullSrcAndDestStayAsIs(t *testing.T) {
tc := remoteCmdTest{
srcHost: "10.5.0.144",
srcUser: "admin",
@@ -205,13 +180,16 @@ func TestRunRemote_PullSrcNotPrefixed(t *testing.T) {
dstPath: "/share/data",
direction: "pull",
}
srcArg, _ := tc.build()
srcArg, dstArg := tc.build()
if countOccurrences(srcArg, "@") > 1 {
t.Errorf("pull src %q has double SSH spec", srcArg)
}
if srcArg != "admin@10.5.0.144:/share/media/peliculas" {
t.Errorf("pull src = %q, want 'admin@10.5.0.144:/share/media/peliculas'", srcArg)
if srcArg != "/share/data" {
t.Errorf("pull src (rsync dest) = %q, want raw '/share/data'", srcArg)
}
if !strings.HasPrefix(dstArg, "admin@10.5.0.144:/") {
t.Errorf("pull dst (rsync src) = %q, want 'admin@10.5.0.144:/...' prefix", dstArg)
}
}