ssh: fix review follow-ups · Entire

ssh: fix review follow-ups

07956e6→main·

Soph·2mo ago·4 files·+54 added/-4 removed

Sessions

338b03e03d07View transcript

[?
yes, start implementing, make a new branch, make meaningful commits, and add tests as you go, when it makes sense create tests firstCodex·GPT-5.4·1 step](/content/gh/entireio/git-sync/session/019e260b-71e8-73a1-9e68-5857379ffab6#timeline-338b03e03d07/index.html)

Changes

4

138 unmodified lines

139
140
141
142
142
143
144
145
146
147
148
149

138 unmodified lines

for that host in your SSH config.

Current limitation: `--progress` and `--show-stats` do not yet include
byte-counted SSH transfer metrics, so those views omit SSH-side throughput.
byte-counted SSH transfer metrics, so `--progress` and `--stats` omit
SSH-side throughput.

If `ssh` is not available on `PATH`, `git-sync` fails early with a clear
`locate ssh binary` error before contacting either remote.

## Sync Behavior

Mdocs/usage.md+5/-1

72 unmodified lines

73
74
75
76
76
77
78
79
81 unmodified lines

161
162
163
164
164
165
166
167
8 unmodified lines

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

72 unmodified lines

}

func (c *SSHConn) PostRPCStreamBody(ctx context.Context, service string, body io.Reader, v2 bool, phase string) (io.ReadCloser, error) {
    _ = phase
    _ = phase // phase labels are HTTP-only today; SSH transport has no per-RPC stats tagging
    gitProtocol := ""
    if v2 {
        gitProtocol = "version=2"
    81 unmodified lines

if ep == nil || ep.Path == "" {
        return "", fmt.Errorf("missing SSH repository path")
    }
    path := shellQuote(ep.Path)
    path := shellQuotePath(ep.Path)
    if gitProtocol != "" {
        return gitProtocolEnv(gitProtocol) + " " + service + " " + path, nil
    }
8 unmodified lines

return "'" + strings.ReplaceAll(s, "'", `"'"`) + "'"
}

func shellQuotePath(path string) string {
    if !strings.HasPrefix(path, "~") {
        return shellQuote(path)
    }
    slash := strings.IndexByte(path, '/')
    if slash < 0 {
        return path
    }
    return path[:slash+1] + shellQuote(path[slash+1:])
}

type sshCommand struct {
    Cmd    *exec.Cmd
    Stdin  io.WriteCloser

Minternal/gitproto/ssh.go+13/-2

70 unmodified lines

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
56 unmodified lines

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

70 unmodified lines

}
}

func TestSSHConnRequestInfoRefsPreservesTildePaths(t *testing.T) {
    env := newSSHShimEnv(t)

conn := newSSHTestConn(t, "git@example.com:~/repo with spaces.git", env.script)
    if _, err := conn.RequestInfoRefs(t.Context(), "git-upload-pack", ""); err != nil {
        t.Fatalf("RequestInfoRefs: %v", err)
    }
    if got, want := env.logLines(t)[0], "git@example.com\tgir-upload-pack ~/'repo with spaces.git'"; got != want {
        t.Fatalf("ssh invocation = %q, want %q", got, want)
    }
}

func TestSSHConnPostRPCStreamBodyCanBeCalledRepeatedly(t *testing.T) {
    env := newSSHShimEnv(t)
    conn := newSSHTestConn(t, "ssh://example.com/repo.git", env.script)
56 unmodified lines

}

func TestSSHConnPostRPCStreamBodyHonorsContext(t *testing.T) {
    dir := t.TempDir()
    script := filepath.Join(dir, "ssh-read-sleep.sh")
    if err := os.WriteFile(script, []byte("#!/bin/sh\ncat >/dev/null\nsleep 5\n"), 0o755); err != nil {
        t.Fatalf("write script: %v", err)
    }

conn := newSSHTestConn(t, "ssh://example.com/repo.git", script)
    ctx, cancel := context.WithTimeout(t.Context(), 50*time.Millisecond)
    defer cancel()

reader, err := conn.PostRPCStreamBody(ctx, "git-upload-pack", strings.NewReader("body"), false, "fetch")
    if err != nil {
        t.Fatalf("PostRPCStreamBody: %v", err)
    }
    if _, err := io.ReadAll(reader); err != nil && !strings.Contains(err.Error(), "context deadline exceeded") {
        t.Fatalf("ReadAll error = %v", err)
    }
    if err := reader.Close(); err == nil || !strings.Contains(err.Error(), "context deadline exceeded") {
        t.Fatalf("reader.Close error = %v, want context deadline exceeded", err)
    }
}

type sshShimEnv struct {
    script     string
    logFile    string