fix(offbox): use restic -o sftp.command (0.14 has no sftp.args)

Live validation surfaced 'option sftp.args is not known' on restic 0.14.0; switch to the
portable sftp.command SSH invocation (ConnectTimeout/StrictHostKeyChecking preserved).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxLA1mZurFq9kt8hneFeCs
This commit is contained in:
2026-06-30 15:32:43 +02:00
parent 2a7deadc93
commit 02820d6550
+8 -6
View File
@@ -131,13 +131,15 @@ func (m *Manager) offboxBaseArgs(t *settings.OffboxTarget) ([]string, []string)
if port == 0 {
port = 22
}
// One -o sftp.args token; restic splits it on spaces. Our paths have no spaces (data dir). The
// ConnectTimeout makes a dead NAS fail in ~N s; StrictHostKeyChecking + a pinned known_hosts avoid
// blind TOFU; BatchMode prevents any interactive prompt from hanging the runner.
sftpArgs := fmt.Sprintf("-oBatchMode=yes -oConnectTimeout=%d -oStrictHostKeyChecking=yes -oUserKnownHostsFile=%s -oPort=%d -i %s",
offboxConnectTimeoutSec, m.offboxKnownHosts(), port, m.offboxKeyPath())
// restic's sftp backend connects via the `-o sftp.command` SSH invocation (the portable form across
// restic versions — `sftp.args` is not recognized by restic 0.14). The ConnectTimeout makes a dead NAS
// fail in ~N s (the load-bearing spike Q8 knob); StrictHostKeyChecking + a pinned known_hosts avoid
// blind TOFU; BatchMode prevents any interactive prompt from hanging the runner. The value is one -o
// token (restic takes everything after `sftp.command=`); our paths have no spaces (data dir).
sftpCmd := fmt.Sprintf("ssh %s@%s -p %d -oBatchMode=yes -oConnectTimeout=%d -oStrictHostKeyChecking=yes -oUserKnownHostsFile=%s -i %s -s sftp",
t.User, t.Host, port, offboxConnectTimeoutSec, m.offboxKnownHosts(), m.offboxKeyPath())
repo := "sftp:" + t.User + "@" + t.Host + ":" + t.RepoPath
args := []string{"-r", repo, "-o", "sftp.args=" + sftpArgs}
args := []string{"-r", repo, "-o", "sftp.command=" + sftpCmd}
env := []string{"RESTIC_PASSWORD_FILE=" + m.offboxPwPath()}
return args, env
}