diff options
Diffstat (limited to 'internal')
-rw-r--r-- | internal/command/receivepack/gitalycall.go | 2 | ||||
-rw-r--r-- | internal/command/uploadarchive/gitalycall.go | 2 | ||||
-rw-r--r-- | internal/command/uploadpack/gitalycall.go | 19 | ||||
-rw-r--r-- | internal/command/uploadpack/gitalycall_test.go | 56 | ||||
-rw-r--r-- | internal/handler/exec.go | 24 | ||||
-rw-r--r-- | internal/handler/exec_test.go | 7 | ||||
-rw-r--r-- | internal/testhelper/requesthandlers/requesthandlers.go | 11 |
7 files changed, 106 insertions, 15 deletions
diff --git a/internal/command/receivepack/gitalycall.go b/internal/command/receivepack/gitalycall.go index 072656a..6bd9f49 100644 --- a/internal/command/receivepack/gitalycall.go +++ b/internal/command/receivepack/gitalycall.go @@ -30,7 +30,7 @@ func (c *Command) performGitalyCall(ctx context.Context, response *accessverifie GitConfigOptions: response.GitConfigOptions, } - return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn) (int32, error) { + return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) { ctx, cancel := gc.PrepareContext(ctx, request.Repository, response, c.Args.Env) defer cancel() diff --git a/internal/command/uploadarchive/gitalycall.go b/internal/command/uploadarchive/gitalycall.go index 5a7d2e6..33f0b71 100644 --- a/internal/command/uploadarchive/gitalycall.go +++ b/internal/command/uploadarchive/gitalycall.go @@ -23,7 +23,7 @@ func (c *Command) performGitalyCall(ctx context.Context, response *accessverifie request := &pb.SSHUploadArchiveRequest{Repository: &response.Gitaly.Repo} - return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn) (int32, error) { + return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) { ctx, cancel := gc.PrepareContext(ctx, request.Repository, response, c.Args.Env) defer cancel() diff --git a/internal/command/uploadpack/gitalycall.go b/internal/command/uploadpack/gitalycall.go index 0e6a6d0..43ae4f8 100644 --- a/internal/command/uploadpack/gitalycall.go +++ b/internal/command/uploadpack/gitalycall.go @@ -21,13 +21,30 @@ func (c *Command) performGitalyCall(ctx context.Context, response *accessverifie Features: response.Gitaly.Features, } + if response.Gitaly.UseSidechannel { + gc.DialSidechannel = true + request := &pb.SSHUploadPackWithSidechannelRequest{ + Repository: &response.Gitaly.Repo, + GitProtocol: c.Args.Env.GitProtocolVersion, + GitConfigOptions: response.GitConfigOptions, + } + + return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) { + ctx, cancel := gc.PrepareContext(ctx, request.Repository, response, c.Args.Env) + defer cancel() + + rw := c.ReadWriter + return client.UploadPackWithSidechannel(ctx, conn, registry, rw.In, rw.Out, rw.ErrOut, request) + }) + } + request := &pb.SSHUploadPackRequest{ Repository: &response.Gitaly.Repo, GitProtocol: c.Args.Env.GitProtocolVersion, GitConfigOptions: response.GitConfigOptions, } - return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn) (int32, error) { + return gc.RunGitalyCommand(ctx, func(ctx context.Context, conn *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) { ctx, cancel := gc.PrepareContext(ctx, request.Repository, response, c.Args.Env) defer cancel() diff --git a/internal/command/uploadpack/gitalycall_test.go b/internal/command/uploadpack/gitalycall_test.go index 926d2c9..213b6f9 100644 --- a/internal/command/uploadpack/gitalycall_test.go +++ b/internal/command/uploadpack/gitalycall_test.go @@ -71,3 +71,59 @@ func TestUploadPack(t *testing.T) { require.Empty(t, testServer.ReceivedMD["some-other-ff"]) require.Equal(t, testServer.ReceivedMD["x-gitlab-correlation-id"][0], "a-correlation-id") } + +func TestUploadPack_withSidechannel(t *testing.T) { + gitalyAddress, testServer := testserver.StartGitalyServer(t) + + requests := requesthandlers.BuildAllowedWithGitalyHandlersWithSidechannel(t, gitalyAddress) + url := testserver.StartHttpServer(t, requests) + + output := &bytes.Buffer{} + input := &bytes.Buffer{} + + userId := "1" + repo := "group/repo" + + env := sshenv.Env{ + IsSSHConnection: true, + OriginalCommand: "git-upload-pack " + repo, + RemoteAddr: "127.0.0.1", + } + + args := &commandargs.Shell{ + GitlabKeyId: userId, + CommandType: commandargs.UploadPack, + SshArgs: []string{"git-upload-pack", repo}, + Env: env, + } + + cmd := &Command{ + Config: &config.Config{GitlabUrl: url}, + Args: args, + ReadWriter: &readwriter.ReadWriter{ErrOut: output, Out: output, In: input}, + } + + ctx := correlation.ContextWithCorrelation(context.Background(), "a-correlation-id") + ctx = correlation.ContextWithClientName(ctx, "gitlab-shell-tests") + + err := cmd.Execute(ctx) + require.NoError(t, err) + + require.Equal(t, "SSHUploadPackWithSidechannel: "+repo, output.String()) + + for k, v := range map[string]string{ + "gitaly-feature-cache_invalidator": "true", + "gitaly-feature-inforef_uploadpack_cache": "false", + "x-gitlab-client-name": "gitlab-shell-tests-git-upload-pack", + "key_id": "123", + "user_id": "1", + "remote_ip": "127.0.0.1", + "key_type": "key", + } { + actual := testServer.ReceivedMD[k] + require.Len(t, actual, 1) + require.Equal(t, v, actual[0]) + } + require.Empty(t, testServer.ReceivedMD["some-other-ff"]) + require.Equal(t, testServer.ReceivedMD["x-gitlab-correlation-id"][0], "a-correlation-id") +} diff --git a/internal/handler/exec.go b/internal/handler/exec.go index 8f4a7df..9bd8018 100644 --- a/internal/handler/exec.go +++ b/internal/handler/exec.go @@ -29,21 +29,23 @@ import ( // GitalyHandlerFunc implementations are responsible for making // an appropriate Gitaly call using the provided client and context // and returning an error from the Gitaly call. -type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn) (int32, error) +type GitalyHandlerFunc func(ctx context.Context, client *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) type GitalyCommand struct { - Config *config.Config - ServiceName string - Address string - Token string - Features map[string]string + Config *config.Config + ServiceName string + Address string + Token string + Features map[string]string + DialSidechannel bool } // RunGitalyCommand provides a bootstrap for Gitaly commands executed // through GitLab-Shell. It ensures that logging, tracing and other // common concerns are configured before executing the `handler`. func (gc *GitalyCommand) RunGitalyCommand(ctx context.Context, handler GitalyHandlerFunc) error { - conn, err := getConn(ctx, gc) + registry := client.NewSidechannelRegistry(log.ContextLogger(ctx)) + conn, err := getConn(ctx, gc, registry) if err != nil { log.ContextLogger(ctx).WithError(fmt.Errorf("RunGitalyCommand: %v", err)).Error("Failed to get connection to execute Git command") @@ -53,7 +55,7 @@ func (gc *GitalyCommand) RunGitalyCommand(ctx context.Context, handler GitalyHan childCtx := withOutgoingMetadata(ctx, gc.Features) ctxlog := log.ContextLogger(childCtx) - exitStatus, err := handler(childCtx, conn) + exitStatus, err := handler(childCtx, conn, registry) if err != nil { if grpcstatus.Convert(err).Code() == grpccodes.Unavailable { @@ -116,7 +118,7 @@ func withOutgoingMetadata(ctx context.Context, features map[string]string) conte return metadata.NewOutgoingContext(ctx, md) } -func getConn(ctx context.Context, gc *GitalyCommand) (*grpc.ClientConn, error) { +func getConn(ctx context.Context, gc *GitalyCommand, registry *client.SidechannelRegistry) (*grpc.ClientConn, error) { if gc.Address == "" { return nil, fmt.Errorf("no gitaly_address given") } @@ -160,5 +162,9 @@ func getConn(ctx context.Context, gc *GitalyCommand) (*grpc.ClientConn, error) { ) } + if gc.DialSidechannel { + return client.DialSidechannel(ctx, gc.Address, registry, connOpts) + } + return client.DialContext(ctx, gc.Address, connOpts) } diff --git a/internal/handler/exec_test.go b/internal/handler/exec_test.go index ba6bd6a..784cf19 100644 --- a/internal/handler/exec_test.go +++ b/internal/handler/exec_test.go @@ -11,14 +11,15 @@ import ( "google.golang.org/grpc/metadata" grpcstatus "google.golang.org/grpc/status" + "gitlab.com/gitlab-org/gitaly/v14/client" pb "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" "gitlab.com/gitlab-org/gitlab-shell/internal/config" "gitlab.com/gitlab-org/gitlab-shell/internal/gitlabnet/accessverifier" "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv" ) -func makeHandler(t *testing.T, err error) func(context.Context, *grpc.ClientConn) (int32, error) { - return func(ctx context.Context, client *grpc.ClientConn) (int32, error) { +func makeHandler(t *testing.T, err error) func(context.Context, *grpc.ClientConn, *client.SidechannelRegistry) (int32, error) { + return func(ctx context.Context, client *grpc.ClientConn, registry *client.SidechannelRegistry) (int32, error) { require.NotNil(t, ctx) require.NotNil(t, client) @@ -86,7 +87,7 @@ func TestRunGitalyCommandMetadata(t *testing.T) { t.Run(tt.name, func(t *testing.T) { cmd := tt.gc - err := cmd.RunGitalyCommand(context.Background(), func(ctx context.Context, _ *grpc.ClientConn) (int32, error) { + err := cmd.RunGitalyCommand(context.Background(), func(ctx context.Context, _ *grpc.ClientConn, _ *client.SidechannelRegistry) (int32, error) { md, exists := metadata.FromOutgoingContext(ctx) require.True(t, exists) require.Equal(t, len(tt.want), md.Len()) diff --git a/internal/testhelper/requesthandlers/requesthandlers.go b/internal/testhelper/requesthandlers/requesthandlers.go index 6d501d0..2fdaef6 100644 --- a/internal/testhelper/requesthandlers/requesthandlers.go +++ b/internal/testhelper/requesthandlers/requesthandlers.go @@ -29,6 +29,14 @@ func BuildDisallowedByApiHandlers(t *testing.T) []testserver.TestRequestHandler } func BuildAllowedWithGitalyHandlers(t *testing.T, gitalyAddress string) []testserver.TestRequestHandler { + return buildAllowedWithGitalyHandlers(t, gitalyAddress, false) +} + +func BuildAllowedWithGitalyHandlersWithSidechannel(t *testing.T, gitalyAddress string) []testserver.TestRequestHandler { + return buildAllowedWithGitalyHandlers(t, gitalyAddress, true) +} + +func buildAllowedWithGitalyHandlers(t *testing.T, gitalyAddress string, useSidechannel bool) []testserver.TestRequestHandler { requests := []testserver.TestRequestHandler{ { Path: "/api/v4/internal/allowed", @@ -56,6 +64,9 @@ func BuildAllowedWithGitalyHandlers(t *testing.T, gitalyAddress string) []testse }, }, } + if useSidechannel { + body["gitaly"].(map[string]interface{})["use_sidechannel"] = true + } require.NoError(t, json.NewEncoder(w).Encode(body)) }, }, |