summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor <idrozdov@gitlab.com>2019-06-03 15:21:25 +0000
committerNick Thomas <nick@gitlab.com>2019-06-03 15:21:25 +0000
commitcde5b73cb8776c70c6d00ff34c568ea4438bcba9 (patch)
treeddc0d81da81ebfdb2c05819c88cde2c56dbaf4d5
parentbeb5855542645cdc9bf7f954b9c5a9333dfb3975 (diff)
downloadgitlab-shell-cde5b73cb8776c70c6d00ff34c568ea4438bcba9.tar.gz
Go implementation for git-upload-pack
-rw-r--r--go/internal/command/command.go3
-rw-r--r--go/internal/command/command_test.go13
-rw-r--r--go/internal/command/commandargs/command_args.go1
-rw-r--r--go/internal/command/commandargs/command_args_test.go7
-rw-r--r--go/internal/command/receivepack/gitalycall.go10
-rw-r--r--go/internal/command/receivepack/receivepack.go9
-rw-r--r--go/internal/command/receivepack/receivepack_test.go18
-rw-r--r--go/internal/command/shared/disallowedcommand/disallowedcommand.go7
-rw-r--r--go/internal/command/uploadpack/gitalycall.go36
-rw-r--r--go/internal/command/uploadpack/gitalycall_test.go40
-rw-r--r--go/internal/command/uploadpack/uploadpack.go36
-rw-r--r--go/internal/command/uploadpack/uploadpack_test.go31
-rw-r--r--go/internal/gitlabnet/accessverifier/client.go16
-rw-r--r--go/internal/gitlabnet/accessverifier/client_test.go7
-rw-r--r--go/internal/gitlabnet/testserver/gitalyserver.go9
-rw-r--r--go/internal/testhelper/requesthandlers/requesthandlers.go18
16 files changed, 213 insertions, 48 deletions
diff --git a/go/internal/command/command.go b/go/internal/command/command.go
index f55207a..8b02f16 100644
--- a/go/internal/command/command.go
+++ b/go/internal/command/command.go
@@ -7,6 +7,7 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/receivepack"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/twofactorrecover"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/uploadpack"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
)
@@ -38,6 +39,8 @@ func buildCommand(args *commandargs.CommandArgs, config *config.Config, readWrit
return &twofactorrecover.Command{Config: config, Args: args, ReadWriter: readWriter}
case commandargs.ReceivePack:
return &receivepack.Command{Config: config, Args: args, ReadWriter: readWriter}
+ case commandargs.UploadPack:
+ return &uploadpack.Command{Config: config, Args: args, ReadWriter: readWriter}
}
return nil
diff --git a/go/internal/command/command_test.go b/go/internal/command/command_test.go
index cdcda8a..37db89f 100644
--- a/go/internal/command/command_test.go
+++ b/go/internal/command/command_test.go
@@ -9,6 +9,7 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/fallback"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/receivepack"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/twofactorrecover"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/uploadpack"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/testhelper"
)
@@ -69,6 +70,18 @@ func TestNew(t *testing.T) {
expectedType: &receivepack.Command{},
},
{
+ desc: "it returns a UploadPack command if the feature is enabled",
+ config: &config.Config{
+ GitlabUrl: "http+unix://gitlab.socket",
+ Migration: config.MigrationConfig{Enabled: true, Features: []string{"git-upload-pack"}},
+ },
+ environment: map[string]string{
+ "SSH_CONNECTION": "1",
+ "SSH_ORIGINAL_COMMAND": "git-upload-pack",
+ },
+ expectedType: &uploadpack.Command{},
+ },
+ {
desc: "it returns a Fallback command if the feature is unimplemented",
config: &config.Config{
GitlabUrl: "http+unix://gitlab.socket",
diff --git a/go/internal/command/commandargs/command_args.go b/go/internal/command/commandargs/command_args.go
index 7e241ea..6789c5b 100644
--- a/go/internal/command/commandargs/command_args.go
+++ b/go/internal/command/commandargs/command_args.go
@@ -14,6 +14,7 @@ const (
Discover CommandType = "discover"
TwoFactorRecover CommandType = "2fa_recovery_codes"
ReceivePack CommandType = "git-receive-pack"
+ UploadPack CommandType = "git-upload-pack"
)
var (
diff --git a/go/internal/command/commandargs/command_args_test.go b/go/internal/command/commandargs/command_args_test.go
index 01202c0..c3c6ff2 100644
--- a/go/internal/command/commandargs/command_args_test.go
+++ b/go/internal/command/commandargs/command_args_test.go
@@ -76,6 +76,13 @@ func TestParseSuccess(t *testing.T) {
"SSH_ORIGINAL_COMMAND": `git-receive-pack group/repo; any command`,
},
expectedArgs: &CommandArgs{SshArgs: []string{"git-receive-pack", "group/repo"}, CommandType: ReceivePack},
+ }, {
+ desc: "It parses git-upload-pack command",
+ environment: map[string]string{
+ "SSH_CONNECTION": "1",
+ "SSH_ORIGINAL_COMMAND": `git upload-pack "group/repo"`,
+ },
+ expectedArgs: &CommandArgs{SshArgs: []string{"git-upload-pack", "group/repo"}, CommandType: UploadPack},
},
}
diff --git a/go/internal/command/receivepack/gitalycall.go b/go/internal/command/receivepack/gitalycall.go
index 22652d7..87ef9c5 100644
--- a/go/internal/command/receivepack/gitalycall.go
+++ b/go/internal/command/receivepack/gitalycall.go
@@ -20,16 +20,8 @@ func (c *Command) performGitalyCall(response *accessverifier.Response) error {
Token: response.Gitaly.Token,
}
- repo := response.Gitaly.Repo
request := &pb.SSHReceivePackRequest{
- Repository: &pb.Repository{
- StorageName: repo.StorageName,
- RelativePath: repo.RelativePath,
- GitObjectDirectory: repo.GitObjectDirectory,
- GitAlternateObjectDirectories: repo.GitAlternateObjectDirectories,
- GlRepository: repo.RepoName,
- GlProjectPath: repo.ProjectPath,
- },
+ Repository: &response.Gitaly.Repo,
GlId: response.UserId,
GlRepository: response.Repo,
GlUsername: response.Username,
diff --git a/go/internal/command/receivepack/receivepack.go b/go/internal/command/receivepack/receivepack.go
index d1ff3f8..d6b788c 100644
--- a/go/internal/command/receivepack/receivepack.go
+++ b/go/internal/command/receivepack/receivepack.go
@@ -1,18 +1,13 @@
package receivepack
import (
- "errors"
-
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/shared/accessverifier"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/shared/disallowedcommand"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
)
-var (
- disallowedCommandError = errors.New("> GitLab: Disallowed command")
-)
-
type Command struct {
Config *config.Config
Args *commandargs.CommandArgs
@@ -22,7 +17,7 @@ type Command struct {
func (c *Command) Execute() error {
args := c.Args.SshArgs
if len(args) != 2 {
- return disallowedCommandError
+ return disallowedcommand.Error
}
repo := args[1]
diff --git a/go/internal/command/receivepack/receivepack_test.go b/go/internal/command/receivepack/receivepack_test.go
index 874bac3..e5263f5 100644
--- a/go/internal/command/receivepack/receivepack_test.go
+++ b/go/internal/command/receivepack/receivepack_test.go
@@ -2,8 +2,6 @@ package receivepack
import (
"bytes"
- "encoding/json"
- "net/http"
"testing"
"github.com/stretchr/testify/require"
@@ -12,23 +10,11 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet/testserver"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/testhelper/requesthandlers"
)
func TestForbiddenAccess(t *testing.T) {
- requests := []testserver.TestRequestHandler{
- {
- Path: "/api/v4/internal/allowed",
- Handler: func(w http.ResponseWriter, r *http.Request) {
- body := map[string]interface{}{
- "status": false,
- "message": "Disallowed by API call",
- }
- w.WriteHeader(http.StatusForbidden)
- require.NoError(t, json.NewEncoder(w).Encode(body))
- },
- },
- }
-
+ requests := requesthandlers.BuildDisallowedByApiHandlers(t)
url, cleanup := testserver.StartHttpServer(t, requests)
defer cleanup()
diff --git a/go/internal/command/shared/disallowedcommand/disallowedcommand.go b/go/internal/command/shared/disallowedcommand/disallowedcommand.go
new file mode 100644
index 0000000..3c98bcc
--- /dev/null
+++ b/go/internal/command/shared/disallowedcommand/disallowedcommand.go
@@ -0,0 +1,7 @@
+package disallowedcommand
+
+import "errors"
+
+var (
+ Error = errors.New("> GitLab: Disallowed command")
+)
diff --git a/go/internal/command/uploadpack/gitalycall.go b/go/internal/command/uploadpack/gitalycall.go
new file mode 100644
index 0000000..28d555c
--- /dev/null
+++ b/go/internal/command/uploadpack/gitalycall.go
@@ -0,0 +1,36 @@
+package uploadpack
+
+import (
+ "context"
+
+ "google.golang.org/grpc"
+
+ pb "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"
+ "gitlab.com/gitlab-org/gitaly/client"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet/accessverifier"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/handler"
+)
+
+func (c *Command) performGitalyCall(response *accessverifier.Response) error {
+ gc := &handler.GitalyCommand{
+ Config: c.Config,
+ ServiceName: string(commandargs.UploadPack),
+ Address: response.Gitaly.Address,
+ Token: response.Gitaly.Token,
+ }
+
+ request := &pb.SSHUploadPackRequest{
+ Repository: &response.Gitaly.Repo,
+ GitProtocol: response.GitProtocol,
+ GitConfigOptions: response.GitConfigOptions,
+ }
+
+ return gc.RunGitalyCommand(func(ctx context.Context, conn *grpc.ClientConn) (int32, error) {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+
+ rw := c.ReadWriter
+ return client.UploadPack(ctx, conn, rw.In, rw.Out, rw.ErrOut, request)
+ })
+}
diff --git a/go/internal/command/uploadpack/gitalycall_test.go b/go/internal/command/uploadpack/gitalycall_test.go
new file mode 100644
index 0000000..2097964
--- /dev/null
+++ b/go/internal/command/uploadpack/gitalycall_test.go
@@ -0,0 +1,40 @@
+package uploadpack
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet/testserver"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/testhelper/requesthandlers"
+)
+
+func TestUploadPack(t *testing.T) {
+ gitalyAddress, cleanup := testserver.StartGitalyServer(t)
+ defer cleanup()
+
+ requests := requesthandlers.BuildAllowedWithGitalyHandlers(t, gitalyAddress)
+ url, cleanup := testserver.StartHttpServer(t, requests)
+ defer cleanup()
+
+ output := &bytes.Buffer{}
+ input := &bytes.Buffer{}
+
+ userId := "1"
+ repo := "group/repo"
+
+ cmd := &Command{
+ Config: &config.Config{GitlabUrl: url},
+ Args: &commandargs.CommandArgs{GitlabKeyId: userId, CommandType: commandargs.UploadPack, SshArgs: []string{"git-upload-pack", repo}},
+ ReadWriter: &readwriter.ReadWriter{ErrOut: output, Out: output, In: input},
+ }
+
+ err := cmd.Execute()
+ require.NoError(t, err)
+
+ require.Equal(t, "UploadPack: "+repo, output.String())
+}
diff --git a/go/internal/command/uploadpack/uploadpack.go b/go/internal/command/uploadpack/uploadpack.go
new file mode 100644
index 0000000..cff198d
--- /dev/null
+++ b/go/internal/command/uploadpack/uploadpack.go
@@ -0,0 +1,36 @@
+package uploadpack
+
+import (
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/shared/accessverifier"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
+)
+
+type Command struct {
+ Config *config.Config
+ Args *commandargs.CommandArgs
+ ReadWriter *readwriter.ReadWriter
+}
+
+func (c *Command) Execute() error {
+ args := c.Args.SshArgs
+ if len(args) != 2 {
+ return disallowedcommand.Error
+ }
+
+ repo := args[1]
+ response, err := c.verifyAccess(repo)
+ if err != nil {
+ return err
+ }
+
+ return c.performGitalyCall(response)
+}
+
+func (c *Command) verifyAccess(repo string) (*accessverifier.Response, error) {
+ cmd := accessverifier.Command{c.Config, c.Args, c.ReadWriter}
+
+ return cmd.Verify(c.Args.CommandType, repo)
+}
diff --git a/go/internal/command/uploadpack/uploadpack_test.go b/go/internal/command/uploadpack/uploadpack_test.go
new file mode 100644
index 0000000..a06ba24
--- /dev/null
+++ b/go/internal/command/uploadpack/uploadpack_test.go
@@ -0,0 +1,31 @@
+package uploadpack
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet/testserver"
+ "gitlab.com/gitlab-org/gitlab-shell/go/internal/testhelper/requesthandlers"
+)
+
+func TestForbiddenAccess(t *testing.T) {
+ requests := requesthandlers.BuildDisallowedByApiHandlers(t)
+ url, cleanup := testserver.StartHttpServer(t, requests)
+ defer cleanup()
+
+ output := &bytes.Buffer{}
+
+ cmd := &Command{
+ Config: &config.Config{GitlabUrl: url},
+ Args: &commandargs.CommandArgs{GitlabKeyId: "disallowed", SshArgs: []string{"git-upload-pack", "group/repo"}},
+ ReadWriter: &readwriter.ReadWriter{ErrOut: output, Out: output},
+ }
+
+ err := cmd.Execute()
+ require.Equal(t, "Disallowed by API call", err.Error())
+}
diff --git a/go/internal/gitlabnet/accessverifier/client.go b/go/internal/gitlabnet/accessverifier/client.go
index ebe8545..d87c4ad 100644
--- a/go/internal/gitlabnet/accessverifier/client.go
+++ b/go/internal/gitlabnet/accessverifier/client.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
+ pb "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet"
@@ -27,19 +28,10 @@ type Request struct {
Username string `json:"username,omitempty"`
}
-type GitalyRepo struct {
- StorageName string `json:"storage_name"`
- RelativePath string `json:"relative_path"`
- GitObjectDirectory string `json:"git_object_directory"`
- GitAlternateObjectDirectories []string `json:"git_alternate_object_directories"`
- RepoName string `json:"gl_repository"`
- ProjectPath string `json:"gl_project_path"`
-}
-
type Gitaly struct {
- Repo GitalyRepo `json:"repository"`
- Address string `json:"address"`
- Token string `json:"token"`
+ Repo pb.Repository `json:"repository"`
+ Address string `json:"address"`
+ Token string `json:"token"`
}
type CustomPayloadData struct {
diff --git a/go/internal/gitlabnet/accessverifier/client_test.go b/go/internal/gitlabnet/accessverifier/client_test.go
index a759919..31175ae 100644
--- a/go/internal/gitlabnet/accessverifier/client_test.go
+++ b/go/internal/gitlabnet/accessverifier/client_test.go
@@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"
+ pb "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/command/commandargs"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet"
@@ -29,13 +30,13 @@ func buildExpectedResponse(who string) *Response {
Username: "root",
GitConfigOptions: []string{"option"},
Gitaly: Gitaly{
- Repo: GitalyRepo{
+ Repo: pb.Repository{
StorageName: "default",
RelativePath: "@hashed/5f/9c/5f9c4ab08cac7457e9111a30e4664920607ea2c115a1433d7be98e97e64244ca.git",
GitObjectDirectory: "path/to/git_object_directory",
GitAlternateObjectDirectories: []string{"path/to/git_alternate_object_directory"},
- RepoName: "project-26",
- ProjectPath: repo,
+ GlRepository: "project-26",
+ GlProjectPath: repo,
},
Address: "unix:gitaly.socket",
Token: "token",
diff --git a/go/internal/gitlabnet/testserver/gitalyserver.go b/go/internal/gitlabnet/testserver/gitalyserver.go
index 141a518..a31dfe2 100644
--- a/go/internal/gitlabnet/testserver/gitalyserver.go
+++ b/go/internal/gitlabnet/testserver/gitalyserver.go
@@ -18,7 +18,6 @@ type testGitalyServer struct{}
func (s *testGitalyServer) SSHReceivePack(stream pb.SSHService_SSHReceivePackServer) error {
req, err := stream.Recv()
-
if err != nil {
return err
}
@@ -30,6 +29,14 @@ func (s *testGitalyServer) SSHReceivePack(stream pb.SSHService_SSHReceivePackSer
}
func (s *testGitalyServer) SSHUploadPack(stream pb.SSHService_SSHUploadPackServer) error {
+ req, err := stream.Recv()
+ if err != nil {
+ return err
+ }
+
+ response := []byte("UploadPack: " + req.Repository.GlRepository)
+ stream.Send(&pb.SSHUploadPackResponse{Stdout: response})
+
return nil
}
diff --git a/go/internal/testhelper/requesthandlers/requesthandlers.go b/go/internal/testhelper/requesthandlers/requesthandlers.go
index d7e077b..a7bc427 100644
--- a/go/internal/testhelper/requesthandlers/requesthandlers.go
+++ b/go/internal/testhelper/requesthandlers/requesthandlers.go
@@ -10,6 +10,24 @@ import (
"gitlab.com/gitlab-org/gitlab-shell/go/internal/gitlabnet/testserver"
)
+func BuildDisallowedByApiHandlers(t *testing.T) []testserver.TestRequestHandler {
+ requests := []testserver.TestRequestHandler{
+ {
+ Path: "/api/v4/internal/allowed",
+ Handler: func(w http.ResponseWriter, r *http.Request) {
+ body := map[string]interface{}{
+ "status": false,
+ "message": "Disallowed by API call",
+ }
+ w.WriteHeader(http.StatusForbidden)
+ require.NoError(t, json.NewEncoder(w).Encode(body))
+ },
+ },
+ }
+
+ return requests
+}
+
func BuildAllowedWithGitalyHandlers(t *testing.T, gitalyAddress string) []testserver.TestRequestHandler {
requests := []testserver.TestRequestHandler{
{