Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-07-16 14:49:35 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-07-21 10:25:01 +0300
commitdd7dc4c843c077a101f19e33771bdb62783db38b (patch)
tree63209974d05fa94961906bff9ed86bae9ca88f08
parent499b72a41063d61dbb8a73ed7ffa7aa42f1584fd (diff)
git: Fix ordering of `--end-of-options`
Git commands support two kinds of separators to disambiguate command line options: `--end-of-options` tells it that from here on, option parsing has concluded and that all remaining options are to be considered normal positional command line parameters. And `--` typically separates revisions from paths for positional arguments, like for example in git-log(1). A command using both would thus e.g. like the following: $ git log --follow --end-of-options HEAD -- Makefile As it turns out, our Git DSL puts both types of separators in the same place though, ending up with the following equivalent instead: $ git log --follow HEAD --end-of-options -- Makefile This command does work the same in this case, but it is not how it's intended to work given that we may now potentially interpret "HEAD" as an option. While we do validate that no positional arguments start with leading dashes, this is rather about safety in depth. Fix this bug and move `--end-of-options` immediately after all flags and before the positional arguments. Note that this change requires us to label git-rev-list(1) as a command which doesn't support `--end-of-options`: we use `--all` and `--not`, whose order interacts with other positional arguments. But if the separator is specified, then the command will not even accept pseudo revisions as parameters anymore. We're still safe against injection though given that we have custom logic in place to verify the command's positional arguments.
-rw-r--r--internal/git/command_description.go12
-rw-r--r--internal/git/localrepo/remote_test.go2
2 files changed, 8 insertions, 6 deletions
diff --git a/internal/git/command_description.go b/internal/git/command_description.go
index 79e500aa8..7f9a23b0b 100644
--- a/internal/git/command_description.go
+++ b/internal/git/command_description.go
@@ -187,7 +187,9 @@ var commandDescriptions = map[string]commandDescription{
},
},
"rev-list": {
- flags: scNoRefUpdates,
+ // We cannot use --end-of-options here because pseudo revisions like `--all`
+ // and `--not` count as options.
+ flags: scNoRefUpdates | scNoEndOfOptions,
validatePositionalArgs: func(args []string) error {
for _, arg := range args {
// git-rev-list(1) supports pseudo-revision arguments which can be
@@ -306,6 +308,10 @@ func (c commandDescription) args(flags []Option, args []string, postSepArgs []st
commandArgs = append(commandArgs, args...)
}
+ if c.supportsEndOfOptions() {
+ commandArgs = append(commandArgs, "--end-of-options")
+ }
+
if c.validatePositionalArgs != nil {
if err := c.validatePositionalArgs(args); err != nil {
return nil, err
@@ -319,10 +325,6 @@ func (c commandDescription) args(flags []Option, args []string, postSepArgs []st
}
commandArgs = append(commandArgs, args...)
- if c.supportsEndOfOptions() {
- commandArgs = append(commandArgs, "--end-of-options")
- }
-
if len(postSepArgs) > 0 {
commandArgs = append(commandArgs, "--")
}
diff --git a/internal/git/localrepo/remote_test.go b/internal/git/localrepo/remote_test.go
index 158f3ea49..aa1d30e35 100644
--- a/internal/git/localrepo/remote_test.go
+++ b/internal/git/localrepo/remote_test.go
@@ -367,7 +367,7 @@ func TestRepo_FetchRemote(t *testing.T) {
var stderr bytes.Buffer
require.NoError(t, repo.FetchRemote(ctx, "source", FetchOpts{Stderr: &stderr, Env: []string{"GIT_TRACE=1"}}))
- require.Contains(t, stderr.String(), "trace: built-in: git fetch --quiet source --end-of-options")
+ require.Contains(t, stderr.String(), "trace: built-in: git fetch --quiet --end-of-options source")
})
t.Run("with globals", func(t *testing.T) {