Skip to content

plumbing: transport/ssh, Shell-quote path and args#2067

Merged
pjbgf merged 1 commit into
go-git:mainfrom
hiddeco:ssh-shell-quote-path-args
May 7, 2026
Merged

plumbing: transport/ssh, Shell-quote path and args#2067
pjbgf merged 1 commit into
go-git:mainfrom
hiddeco:ssh-shell-quote-path-args

Conversation

@hiddeco

@hiddeco hiddeco commented May 6, 2026

Copy link
Copy Markdown
Member

The SSH transport interpolates req.URL.Path and each entry of req.Args into the remote-exec command line. The previous formatter wrapped each value in literal single quotes via '%s', which diverges from canonical Git's wire format for any value containing characters that the shell treats specially.

Port sq_quote_buf1 from canonical Git into a shellQuote helper and route both the path and each req.Args entry through it. The helper escapes the same character set that upstream Git escapes (' and !), so the bytes go-git puts on the wire match what git itself would send for the same input. Benign inputs are byte-identical to the previous output; values containing ' or ! now round-trip correctly through any POSIX shell and through git-shell's sq_dequote_to_argv.

Add a table-driven TestBuildCommand covering the plain case, both characters that sq_quote_buf escapes, mixed inputs, and inert metacharacters that pass through unchanged.

@aymanbagabas aymanbagabas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good!

@aymanbagabas

Copy link
Copy Markdown
Member

Why don't we pass a generic io.Writer and reuse our string builder from buildCommand?

func writeShellQuote(w io.Writer, s string) string {

@hiddeco

hiddeco commented May 6, 2026

Copy link
Copy Markdown
Member Author

@aymanbagabas yes, good shout, and this refinement was still on my todo list. Drafting this was primarily to show @pjbgf. I will update once 👧 is 💤.

@hiddeco hiddeco force-pushed the ssh-shell-quote-path-args branch 2 times, most recently from 2351d59 to 6928ea9 Compare May 6, 2026 18:06
The SSH transport interpolates `req.URL.Path` and each entry of
`req.Args` into the remote-exec command line. The previous
formatter wrapped each value in literal single quotes via
`'%s'`, which diverges from canonical Git's wire format for any
value containing characters that the shell treats specially.

Port `sq_quote_buf`[1] from canonical Git into a `writeShellQuote`
helper that mirrors upstream's `struct strbuf *dst` signature, and
route both the path and each `req.Args` entry through it. The
helper escapes the same character set that upstream Git escapes
(`'` and `!`), so the bytes go-git puts on the wire match what
`git` itself would send for the same input. Benign inputs are
byte-identical to the previous output; values containing `'` or
`!` now round-trip correctly through any POSIX shell and through
`git-shell`'s `sq_dequote_to_argv`.

Add a table-driven `TestBuildCommand` covering the plain case,
both characters that `sq_quote_buf` escapes, mixed inputs, and
inert metacharacters that pass through unchanged.

[1]: https://github.com/git/git/blob/v2.54.0/quote.c#L28

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
@hiddeco hiddeco force-pushed the ssh-shell-quote-path-args branch from 6928ea9 to 5aee0b9 Compare May 6, 2026 18:07
hiddeco added a commit to hiddeco/go-git that referenced this pull request May 6, 2026
The SSH transport interpolates `ep.Path` into the remote-exec
command line via `endpointToCommand`. The previous formatter
wrapped the value in literal single quotes via `'%s'`, which
diverges from canonical Git's wire format for any path containing
characters the shell treats specially.

Port `sq_quote_buf`[1] from canonical Git into a `writeShellQuote`
helper and route the path through it. The helper escapes the same
character set that upstream Git escapes (`'` and `!`), so the
bytes go-git puts on the wire match what `git` itself would send
for the same input. Benign paths are byte-identical to the
previous output; paths containing `'` or `!` now round-trip
correctly through any POSIX shell and through `git-shell`'s
`sq_dequote_to_argv`.

Add a table-driven `TestEndpointToCommand` covering the plain
case, both characters that `sq_quote_buf` escapes, mixed inputs,
and inert metacharacters that pass through unchanged.

Back-port from go-git#2067.

[1]: https://github.com/git/git/blob/v2.54.0/quote.c#L28

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
@pjbgf pjbgf merged commit d9a6de1 into go-git:main May 7, 2026
17 checks passed
@hiddeco hiddeco deleted the ssh-shell-quote-path-args branch May 7, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants