diff options
author | Rubén Dávila <ruben@gitlab.com> | 2018-07-30 04:59:53 +0300 |
---|---|---|
committer | Rubén Dávila <ruben@gitlab.com> | 2018-08-07 20:03:16 +0300 |
commit | 16ba20281169c1460a6ceb207e21b1b0799f50aa (patch) | |
tree | e0134755461499666f2f0b0f9ebbf7fc061ea963 | |
parent | 23df453426141ec5553d662297faff145690a14d (diff) |
Add ability to support custom options for git-receive-pack
In order to reject pushes that are larger then the size configured by
the user on GitLab we need to support custom options for the `git -c` command.
Specifically we're going to receive receive.MaxInputSize= from the
Gitaly client. Pushes over HTTP are also protected by this setting.
-rw-r--r-- | changelogs/unreleased/rd-add-support-for-max-input-size-config.yml | 5 | ||||
-rw-r--r-- | internal/git/helper.go | 13 | ||||
-rw-r--r-- | internal/service/smarthttp/receive_pack.go | 11 | ||||
-rw-r--r-- | internal/service/ssh/receive_pack.go | 11 | ||||
-rw-r--r-- | internal/service/ssh/receive_pack_test.go | 52 | ||||
-rw-r--r-- | vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION | 2 | ||||
-rw-r--r-- | vendor/vendor.json | 10 |
7 files changed, 81 insertions, 23 deletions
diff --git a/changelogs/unreleased/rd-add-support-for-max-input-size-config.yml b/changelogs/unreleased/rd-add-support-for-max-input-size-config.yml new file mode 100644 index 000000000..8695fa7fe --- /dev/null +++ b/changelogs/unreleased/rd-add-support-for-max-input-size-config.yml @@ -0,0 +1,5 @@ +--- +title: Add ability to support custom options for git-receive-pack +merge_request: 834 +author: +type: added diff --git a/internal/git/helper.go b/internal/git/helper.go index ba4e476de..8af8511d9 100644 --- a/internal/git/helper.go +++ b/internal/git/helper.go @@ -59,3 +59,16 @@ func Version() (string, error) { return ver[2], nil } + +// BuildGitOptions helps to generate options to the git command. +// If gitOpts is not empty then its values are passed as part of +// the "-c" option of the git command, the other values are passed along with the subcommand. +func BuildGitOptions(gitOpts []string, otherOpts ...string) []string { + args := []string{} + + if len(gitOpts) > 0 { + args = append([]string{"-c"}, gitOpts...) + } + + return append(args, otherOpts...) +} diff --git a/internal/service/smarthttp/receive_pack.go b/internal/service/smarthttp/receive_pack.go index 441793a8c..e342f051e 100644 --- a/internal/service/smarthttp/receive_pack.go +++ b/internal/service/smarthttp/receive_pack.go @@ -7,6 +7,7 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" log "github.com/sirupsen/logrus" "gitlab.com/gitlab-org/gitaly/internal/command" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/helper" pb "gitlab.com/gitlab-org/gitaly-proto/go" @@ -22,9 +23,10 @@ func (s *server) PostReceivePack(stream pb.SmartHTTPService_PostReceivePackServe } grpc_logrus.Extract(stream.Context()).WithFields(log.Fields{ - "GlID": req.GlId, - "GlRepository": req.GlRepository, - "GlUsername": req.GlUsername, + "GlID": req.GlId, + "GlRepository": req.GlRepository, + "GlUsername": req.GlUsername, + "GitConfigOptions": req.GitConfigOptions, }).Debug("PostReceivePack") if err := validateReceivePackRequest(req); err != nil { @@ -53,7 +55,8 @@ func (s *server) PostReceivePack(stream pb.SmartHTTPService_PostReceivePackServe return err } - osCommand := exec.Command(command.GitPath(), "receive-pack", "--stateless-rpc", repoPath) + gitOptions := git.BuildGitOptions(req.GitConfigOptions, "receive-pack", "--stateless-rpc", repoPath) + osCommand := exec.Command(command.GitPath(), gitOptions...) cmd, err := command.New(stream.Context(), osCommand, stdin, stdout, nil, env...) if err != nil { diff --git a/internal/service/ssh/receive_pack.go b/internal/service/ssh/receive_pack.go index f4986f315..e66ec4e74 100644 --- a/internal/service/ssh/receive_pack.go +++ b/internal/service/ssh/receive_pack.go @@ -7,6 +7,7 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" log "github.com/sirupsen/logrus" "gitlab.com/gitlab-org/gitaly/internal/command" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/helper" pb "gitlab.com/gitlab-org/gitaly-proto/go" @@ -22,9 +23,10 @@ func (s *server) SSHReceivePack(stream pb.SSHService_SSHReceivePackServer) error } grpc_logrus.Extract(stream.Context()).WithFields(log.Fields{ - "GlID": req.GlId, - "GlRepository": req.GlRepository, - "GlUsername": req.GlUsername, + "GlID": req.GlId, + "GlRepository": req.GlRepository, + "GlUsername": req.GlUsername, + "GitConfigOptions": req.GitConfigOptions, }).Debug("SSHReceivePack") if err = validateFirstReceivePackRequest(req); err != nil { @@ -55,7 +57,8 @@ func (s *server) SSHReceivePack(stream pb.SSHService_SSHReceivePackServer) error return err } - osCommand := exec.Command(command.GitPath(), "receive-pack", repoPath) + gitOptions := git.BuildGitOptions(req.GitConfigOptions, "receive-pack", repoPath) + osCommand := exec.Command(command.GitPath(), gitOptions...) cmd, err := command.New(stream.Context(), osCommand, stdin, stdout, stderr, env...) if err != nil { diff --git a/internal/service/ssh/receive_pack_test.go b/internal/service/ssh/receive_pack_test.go index 9aa6754eb..c3e1d24ee 100644 --- a/internal/service/ssh/receive_pack_test.go +++ b/internal/service/ssh/receive_pack_test.go @@ -3,6 +3,7 @@ package ssh import ( "bytes" "fmt" + "io/ioutil" "os" "os/exec" "path" @@ -13,6 +14,7 @@ import ( "github.com/golang/protobuf/jsonpb" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/testhelper" pb "gitlab.com/gitlab-org/gitaly-proto/go" @@ -79,7 +81,15 @@ func TestReceivePackPushSuccess(t *testing.T) { server, serverSocketPath := runSSHServer(t) defer server.Stop() - lHead, rHead, err := testCloneAndPush(t, serverSocketPath, testRepo.GetStorageName(), "1") + lHead, rHead, err := testCloneAndPush(t, serverSocketPath, pushParams{storageName: testRepo.GetStorageName(), glID: "1"}) + if err != nil { + t.Fatal(err) + } + if strings.Compare(lHead, rHead) != 0 { + t.Errorf("local and remote head not equal. push failed: %q != %q", lHead, rHead) + } + + lHead, rHead, err = testCloneAndPush(t, serverSocketPath, pushParams{storageName: testRepo.GetStorageName(), glID: "1", gitConfigOptions: []string{"receive.MaxInputSize=10000"}}) if err != nil { t.Fatal(err) } @@ -92,17 +102,29 @@ func TestReceivePackPushFailure(t *testing.T) { server, serverSocketPath := runSSHServer(t) defer server.Stop() - _, _, err := testCloneAndPush(t, serverSocketPath, "foobar", "1") + _, _, err := testCloneAndPush(t, serverSocketPath, pushParams{storageName: "foobar", glID: "1"}) if err == nil { t.Errorf("local and remote head equal. push did not fail") } - _, _, err = testCloneAndPush(t, serverSocketPath, testRepo.GetStorageName(), "") + + _, _, err = testCloneAndPush(t, serverSocketPath, pushParams{storageName: testRepo.GetStorageName(), glID: ""}) if err == nil { t.Errorf("local and remote head equal. push did not fail") } + + currentGitVersion, _ := git.Version() + + // receive.MaxInputSize is only available since Git 2.11.0 + // Skip this test from the job that uses Git 2.9.0 + if currentGitVersion != "2.9.0" { + _, _, err = testCloneAndPush(t, serverSocketPath, pushParams{storageName: testRepo.GetStorageName(), glID: "1", gitConfigOptions: []string{"receive.MaxInputSize=1"}}) + if err == nil { + t.Errorf("local and remote head equal. push did not fail") + } + } } -func testCloneAndPush(t *testing.T, serverSocketPath string, storageName, glID string) (string, string, error) { +func testCloneAndPush(t *testing.T, serverSocketPath string, params pushParams) (string, string, error) { storagePath := testhelper.GitlabTestStoragePath() tempRepo := "gitlab-test-ssh-receive-pack.git" testRepoPath := path.Join(storagePath, testRepo.GetRelativePath()) @@ -124,12 +146,13 @@ func testCloneAndPush(t *testing.T, serverSocketPath string, storageName, glID s makeCommit(t, localRepoPath) - pbTempRepo := &pb.Repository{StorageName: storageName, RelativePath: tempRepo} + pbTempRepo := &pb.Repository{StorageName: params.storageName, RelativePath: tempRepo} pbMarshaler := &jsonpb.Marshaler{} payload, err := pbMarshaler.MarshalToString(&pb.SSHReceivePackRequest{ - Repository: pbTempRepo, - GlRepository: pbTempRepo.GetRelativePath(), - GlId: glID, + Repository: pbTempRepo, + GlRepository: pbTempRepo.GetRelativePath(), + GlId: params.glID, + GitConfigOptions: params.gitConfigOptions, }) require.NoError(t, err) @@ -159,6 +182,11 @@ func makeCommit(t *testing.T, localRepoPath string) ([]byte, []byte, bool) { commitMsg := fmt.Sprintf("Testing ReceivePack RPC around %d", time.Now().Unix()) committerName := "Scrooge McDuck" committerEmail := "scrooge@mcduck.com" + newFilePath := localRepoPath + "/foo.txt" + + // Create a tiny file and add it to the index + require.NoError(t, ioutil.WriteFile(newFilePath, []byte("foo bar"), 0644)) + testhelper.MustRunCommand(t, nil, "git", "-C", localRepoPath, "add", ".") // The latest commit ID on the remote repo oldHead := bytes.TrimSpace(testhelper.MustRunCommand(t, nil, "git", "-C", localRepoPath, "rev-parse", "master")) @@ -166,7 +194,7 @@ func makeCommit(t *testing.T, localRepoPath string) ([]byte, []byte, bool) { testhelper.MustRunCommand(t, nil, "git", "-C", localRepoPath, "-c", fmt.Sprintf("user.name=%s", committerName), "-c", fmt.Sprintf("user.email=%s", committerEmail), - "commit", "--allow-empty", "-m", commitMsg) + "commit", "-m", commitMsg) if t.Failed() { return nil, nil, false } @@ -184,3 +212,9 @@ func drainPostReceivePackResponse(stream pb.SSH_SSHReceivePackClient) error { } return err } + +type pushParams struct { + storageName string + glID string + gitConfigOptions []string +} diff --git a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION index e23e3fd29..5af665a17 100644 --- a/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION +++ b/vendor/gitlab.com/gitlab-org/gitaly-proto/go/VERSION @@ -1 +1 @@ -0.112.0 +0.111.0 diff --git a/vendor/vendor.json b/vendor/vendor.json index ef4c8deb8..376d4a1b1 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -201,12 +201,12 @@ "revisionTime": "2017-12-31T12:27:32Z" }, { - "checksumSHA1": "oUra5duKbNfxA8e++b+QbLQYYXU=", + "checksumSHA1": "+GRNcdfnAibgtDObICxZIFk7i9Q=", "path": "gitlab.com/gitlab-org/gitaly-proto/go", - "revision": "e3a5c0a6da1c62f406f6b74b281dad43f8b74ea5", - "revisionTime": "2018-08-02T15:59:47Z", - "version": "v0.112.0", - "versionExact": "v0.112.0" + "revision": "b26cda22da41c708d18be78c519a38810acfdc80", + "revisionTime": "2018-07-31T12:04:23Z", + "version": "v0.111.0", + "versionExact": "v0.111.0" }, { "checksumSHA1": "nqWNlnMmVpt628zzvyo6Yv2CX5Q=", |