summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorfeistel <6742251-feistel@users.noreply.gitlab.com>2021-09-08 14:40:35 +0000
committerfeistel <6742251-feistel@users.noreply.gitlab.com>2021-09-08 14:41:57 +0000
commit67415dc4f6f293460517d4281b5e4e80e66ffb91 (patch)
treef3c3e9162a39ddc8fcfcf6f659ab5cdf362871d6 /cmd
parent7884a4420ac8ffd3ee34589c0f8e0d25ca0fd076 (diff)
downloadgitlab-shell-67415dc4f6f293460517d4281b5e4e80e66ffb91.tar.gz
refactor: rearchitect command and executable Go modules
Diffstat (limited to 'cmd')
-rw-r--r--cmd/check/command/command.go22
-rw-r--r--cmd/check/command/command_test.go42
-rw-r--r--cmd/check/main.go6
-rw-r--r--cmd/gitlab-shell-authorized-keys-check/command/command.go39
-rw-r--r--cmd/gitlab-shell-authorized-keys-check/command/command_test.go120
-rw-r--r--cmd/gitlab-shell-authorized-keys-check/main.go5
-rw-r--r--cmd/gitlab-shell-authorized-principals-check/command/command.go39
-rw-r--r--cmd/gitlab-shell-authorized-principals-check/command/command_test.go114
-rw-r--r--cmd/gitlab-shell-authorized-principals-check/main.go5
-rw-r--r--cmd/gitlab-shell/command/command.go65
-rw-r--r--cmd/gitlab-shell/command/command_test.go281
-rw-r--r--cmd/gitlab-shell/main.go5
12 files changed, 734 insertions, 9 deletions
diff --git a/cmd/check/command/command.go b/cmd/check/command/command.go
new file mode 100644
index 0000000..e72f792
--- /dev/null
+++ b/cmd/check/command/command.go
@@ -0,0 +1,22 @@
+package command
+
+import (
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/healthcheck"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+)
+
+
+func New(config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
+ if cmd := build(config, readWriter); cmd != nil {
+ return cmd, nil
+ }
+
+ return nil, disallowedcommand.Error
+}
+
+func build(config *config.Config, readWriter *readwriter.ReadWriter) command.Command {
+ return &healthcheck.Command{Config: config, ReadWriter: readWriter}
+}
diff --git a/cmd/check/command/command_test.go b/cmd/check/command/command_test.go
new file mode 100644
index 0000000..cd06456
--- /dev/null
+++ b/cmd/check/command/command_test.go
@@ -0,0 +1,42 @@
+package command_test
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitlab-shell/cmd/check/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/healthcheck"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+var (
+ basicConfig = &config.Config{GitlabUrl: "http+unix://gitlab.socket"}
+)
+
+func TestNew(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ config *config.Config
+ expectedType interface{}
+ }{
+ {
+ desc: "it returns a Healthcheck command",
+ config: basicConfig,
+ expectedType: &healthcheck.Command{},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ command, err := command.New(tc.config, nil)
+
+ require.NoError(t, err)
+ require.IsType(t, tc.expectedType, command)
+ })
+ }
+}
diff --git a/cmd/check/main.go b/cmd/check/main.go
index 44d8175..e4bcdf2 100644
--- a/cmd/check/main.go
+++ b/cmd/check/main.go
@@ -4,12 +4,12 @@ import (
"fmt"
"os"
+ checkCmd "gitlab.com/gitlab-org/gitlab-shell/cmd/check/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/internal/config"
"gitlab.com/gitlab-org/gitlab-shell/internal/executable"
"gitlab.com/gitlab-org/gitlab-shell/internal/logger"
- "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
)
func main() {
@@ -19,7 +19,7 @@ func main() {
ErrOut: os.Stderr,
}
- executable, err := executable.New(executable.Healthcheck, false)
+ executable, err := executable.New(executable.Healthcheck)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
@@ -34,7 +34,7 @@ func main() {
logCloser := logger.Configure(config)
defer logCloser.Close()
- cmd, err := command.New(executable, os.Args[1:], sshenv.Env{}, config, readWriter)
+ cmd, err := checkCmd.New(config, readWriter)
if err != nil {
fmt.Fprintf(readWriter.ErrOut, "%v\n", err)
os.Exit(1)
diff --git a/cmd/gitlab-shell-authorized-keys-check/command/command.go b/cmd/gitlab-shell-authorized-keys-check/command/command.go
new file mode 100644
index 0000000..3db8605
--- /dev/null
+++ b/cmd/gitlab-shell-authorized-keys-check/command/command.go
@@ -0,0 +1,39 @@
+package command
+
+import (
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/authorizedkeys"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+func New(e *executable.Executable, arguments []string, env sshenv.Env, config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
+ args, err := Parse(e, arguments, env)
+ if err != nil {
+ return nil, err
+ }
+
+ if cmd := build(args, config, readWriter); cmd != nil {
+ return cmd, nil
+ }
+
+ return nil, disallowedcommand.Error
+}
+
+func Parse(e *executable.Executable, arguments []string, env sshenv.Env) (*commandargs.AuthorizedKeys, error) {
+ args := &commandargs.AuthorizedKeys{Arguments: arguments}
+
+ if err := args.Parse(); err != nil {
+ return nil, err
+ }
+
+ return args, nil
+}
+
+func build(args *commandargs.AuthorizedKeys, config *config.Config, readWriter *readwriter.ReadWriter) command.Command {
+ return &authorizedkeys.Command{Config: config, Args: args, ReadWriter: readWriter}
+}
diff --git a/cmd/gitlab-shell-authorized-keys-check/command/command_test.go b/cmd/gitlab-shell-authorized-keys-check/command/command_test.go
new file mode 100644
index 0000000..5c5419e
--- /dev/null
+++ b/cmd/gitlab-shell-authorized-keys-check/command/command_test.go
@@ -0,0 +1,120 @@
+package command_test
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell-authorized-keys-check/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/authorizedkeys"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+var (
+ authorizedKeysExec = &executable.Executable{Name: executable.AuthorizedKeysCheck}
+ basicConfig = &config.Config{GitlabUrl: "http+unix://gitlab.socket"}
+)
+
+func TestNew(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ config *config.Config
+ expectedType interface{}
+ }{
+ {
+ desc: "it returns a AuthorizedKeys command",
+ executable: authorizedKeysExec,
+ arguments: []string{"git", "git", "key"},
+ config: basicConfig,
+ expectedType: &authorizedkeys.Command{},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ command, err := command.New(tc.executable, tc.arguments, tc.env, tc.config, nil)
+
+ require.NoError(t, err)
+ require.IsType(t, tc.expectedType, command)
+ })
+ }
+}
+
+func TestParseSuccess(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedArgs commandargs.CommandArgs
+ expectError bool
+ }{
+ {
+ desc: "It parses authorized-keys command",
+ executable: &executable.Executable{Name: executable.AuthorizedKeysCheck},
+ arguments: []string{"git", "git", "key"},
+ expectedArgs: &commandargs.AuthorizedKeys{Arguments: []string{"git", "git", "key"}, ExpectedUser: "git", ActualUser: "git", Key: "key"},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ result, err := command.Parse(tc.executable, tc.arguments, tc.env)
+
+ if !tc.expectError {
+ require.NoError(t, err)
+ require.Equal(t, tc.expectedArgs, result)
+ } else {
+ require.Error(t, err)
+ }
+ })
+ }
+}
+
+func TestParseFailure(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedError string
+ }{
+ {
+ desc: "With not enough arguments for the AuthorizedKeysCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedKeysCheck},
+ arguments: []string{"user"},
+ expectedError: "# Insufficient arguments. 1. Usage\n#\tgitlab-shell-authorized-keys-check <expected-username> <actual-username> <key>",
+ },
+ {
+ desc: "With too many arguments for the AuthorizedKeysCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedKeysCheck},
+ arguments: []string{"user", "user", "key", "something-else"},
+ expectedError: "# Insufficient arguments. 4. Usage\n#\tgitlab-shell-authorized-keys-check <expected-username> <actual-username> <key>",
+ },
+ {
+ desc: "With missing username for the AuthorizedKeysCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedKeysCheck},
+ arguments: []string{"user", "", "key"},
+ expectedError: "# No username provided",
+ },
+ {
+ desc: "With missing key for the AuthorizedKeysCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedKeysCheck},
+ arguments: []string{"user", "user", ""},
+ expectedError: "# No key provided",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ _, err := command.Parse(tc.executable, tc.arguments, tc.env)
+
+ require.EqualError(t, err, tc.expectedError)
+ })
+ }
+}
diff --git a/cmd/gitlab-shell-authorized-keys-check/main.go b/cmd/gitlab-shell-authorized-keys-check/main.go
index cda3e0b..bfaeca7 100644
--- a/cmd/gitlab-shell-authorized-keys-check/main.go
+++ b/cmd/gitlab-shell-authorized-keys-check/main.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
+ cmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell-authorized-keys-check/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/internal/config"
@@ -20,7 +21,7 @@ func main() {
ErrOut: os.Stderr,
}
- executable, err := executable.New(executable.AuthorizedKeysCheck, true)
+ executable, err := executable.New(executable.AuthorizedKeysCheck)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
@@ -35,7 +36,7 @@ func main() {
logCloser := logger.Configure(config)
defer logCloser.Close()
- cmd, err := command.New(executable, os.Args[1:], sshenv.Env{}, config, readWriter)
+ cmd, err := cmd.New(executable, os.Args[1:], sshenv.Env{}, config, readWriter)
if err != nil {
// For now this could happen if `SSH_CONNECTION` is not set on
// the environment
diff --git a/cmd/gitlab-shell-authorized-principals-check/command/command.go b/cmd/gitlab-shell-authorized-principals-check/command/command.go
new file mode 100644
index 0000000..b5ded54
--- /dev/null
+++ b/cmd/gitlab-shell-authorized-principals-check/command/command.go
@@ -0,0 +1,39 @@
+package command
+
+import (
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/authorizedprincipals"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+func New(e *executable.Executable, arguments []string, env sshenv.Env, config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
+ args, err := Parse(e, arguments, env)
+ if err != nil {
+ return nil, err
+ }
+
+ if cmd := build(args, config, readWriter); cmd != nil {
+ return cmd, nil
+ }
+
+ return nil, disallowedcommand.Error
+}
+
+func Parse(e *executable.Executable, arguments []string, env sshenv.Env) (*commandargs.AuthorizedPrincipals, error) {
+ args := &commandargs.AuthorizedPrincipals{Arguments: arguments}
+
+ if err := args.Parse(); err != nil {
+ return nil, err
+ }
+
+ return args, nil
+}
+
+func build(args *commandargs.AuthorizedPrincipals, config *config.Config, readWriter *readwriter.ReadWriter) command.Command {
+ return &authorizedprincipals.Command{Config: config, Args: args, ReadWriter: readWriter}
+}
diff --git a/cmd/gitlab-shell-authorized-principals-check/command/command_test.go b/cmd/gitlab-shell-authorized-principals-check/command/command_test.go
new file mode 100644
index 0000000..b6a89f5
--- /dev/null
+++ b/cmd/gitlab-shell-authorized-principals-check/command/command_test.go
@@ -0,0 +1,114 @@
+package command_test
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ cmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell-authorized-principals-check/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/authorizedprincipals"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+var (
+ authorizedPrincipalsExec = &executable.Executable{Name: executable.AuthorizedPrincipalsCheck}
+ basicConfig = &config.Config{GitlabUrl: "http+unix://gitlab.socket"}
+)
+
+func TestNew(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ config *config.Config
+ expectedType interface{}
+ }{
+ {
+ desc: "it returns a AuthorizedPrincipals command",
+ executable: authorizedPrincipalsExec,
+ arguments: []string{"key", "principal"},
+ config: basicConfig,
+ expectedType: &authorizedprincipals.Command{},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ command, err := cmd.New(tc.executable, tc.arguments, tc.env, tc.config, nil)
+
+ require.NoError(t, err)
+ require.IsType(t, tc.expectedType, command)
+ })
+ }
+}
+
+func TestParseSuccess(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedArgs commandargs.CommandArgs
+ expectError bool
+ }{
+ {
+ desc: "It parses authorized-principals command",
+ executable: &executable.Executable{Name: executable.AuthorizedPrincipalsCheck},
+ arguments: []string{"key", "principal-1", "principal-2"},
+ expectedArgs: &commandargs.AuthorizedPrincipals{Arguments: []string{"key", "principal-1", "principal-2"}, KeyId: "key", Principals: []string{"principal-1", "principal-2"}},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ result, err := cmd.Parse(tc.executable, tc.arguments, tc.env)
+
+ if !tc.expectError {
+ require.NoError(t, err)
+ require.Equal(t, tc.expectedArgs, result)
+ } else {
+ require.Error(t, err)
+ }
+ })
+ }
+}
+
+func TestParseFailure(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedError string
+ }{
+ {
+ desc: "With not enough arguments for the AuthorizedPrincipalsCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedPrincipalsCheck},
+ arguments: []string{"key"},
+ expectedError: "# Insufficient arguments. 1. Usage\n#\tgitlab-shell-authorized-principals-check <key-id> <principal1> [<principal2>...]",
+ },
+ {
+ desc: "With missing key_id for the AuthorizedPrincipalsCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedPrincipalsCheck},
+ arguments: []string{"", "principal"},
+ expectedError: "# No key_id provided",
+ },
+ {
+ desc: "With blank principal for the AuthorizedPrincipalsCheck",
+ executable: &executable.Executable{Name: executable.AuthorizedPrincipalsCheck},
+ arguments: []string{"key", "principal", ""},
+ expectedError: "# An invalid principal was provided",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ _, err := cmd.Parse(tc.executable, tc.arguments, tc.env)
+
+ require.EqualError(t, err, tc.expectedError)
+ })
+ }
+}
diff --git a/cmd/gitlab-shell-authorized-principals-check/main.go b/cmd/gitlab-shell-authorized-principals-check/main.go
index 87f7fa3..d0e709c 100644
--- a/cmd/gitlab-shell-authorized-principals-check/main.go
+++ b/cmd/gitlab-shell-authorized-principals-check/main.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
+ cmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell-authorized-principals-check/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/internal/config"
@@ -20,7 +21,7 @@ func main() {
ErrOut: os.Stderr,
}
- executable, err := executable.New(executable.AuthorizedPrincipalsCheck, true)
+ executable, err := executable.New(executable.AuthorizedPrincipalsCheck)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
@@ -35,7 +36,7 @@ func main() {
logCloser := logger.Configure(config)
defer logCloser.Close()
- cmd, err := command.New(executable, os.Args[1:], sshenv.Env{}, config, readWriter)
+ cmd, err := cmd.New(executable, os.Args[1:], sshenv.Env{}, config, readWriter)
if err != nil {
// For now this could happen if `SSH_CONNECTION` is not set on
// the environment
diff --git a/cmd/gitlab-shell/command/command.go b/cmd/gitlab-shell/command/command.go
new file mode 100644
index 0000000..98bfdff
--- /dev/null
+++ b/cmd/gitlab-shell/command/command.go
@@ -0,0 +1,65 @@
+package command
+
+import (
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/discover"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/lfsauthenticate"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/personalaccesstoken"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/receivepack"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorrecover"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorverify"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadarchive"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadpack"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+func New(e *executable.Executable, arguments []string, env sshenv.Env, config *config.Config, readWriter *readwriter.ReadWriter) (command.Command, error) {
+ args, err := Parse(e, arguments, env)
+ if err != nil {
+ return nil, err
+ }
+
+ if cmd := Build(args, config, readWriter); cmd != nil {
+ return cmd, nil
+ }
+
+ return nil, disallowedcommand.Error
+}
+
+func Parse(e *executable.Executable, arguments []string, env sshenv.Env) (*commandargs.Shell, error) {
+ args := &commandargs.Shell{Arguments: arguments, Env: env}
+
+ if err := args.Parse(); err != nil {
+ return nil, err
+ }
+
+ return args, nil
+}
+
+func Build(args *commandargs.Shell, config *config.Config, readWriter *readwriter.ReadWriter) command.Command {
+ switch args.CommandType {
+ case commandargs.Discover:
+ return &discover.Command{Config: config, Args: args, ReadWriter: readWriter}
+ case commandargs.TwoFactorRecover:
+ return &twofactorrecover.Command{Config: config, Args: args, ReadWriter: readWriter}
+ case commandargs.TwoFactorVerify:
+ return &twofactorverify.Command{Config: config, Args: args, ReadWriter: readWriter}
+ case commandargs.LfsAuthenticate:
+ return &lfsauthenticate.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}
+ case commandargs.UploadArchive:
+ return &uploadarchive.Command{Config: config, Args: args, ReadWriter: readWriter}
+ case commandargs.PersonalAccessToken:
+ return &personalaccesstoken.Command{Config: config, Args: args, ReadWriter: readWriter}
+ }
+
+ return nil
+}
diff --git a/cmd/gitlab-shell/command/command_test.go b/cmd/gitlab-shell/command/command_test.go
new file mode 100644
index 0000000..5dacb67
--- /dev/null
+++ b/cmd/gitlab-shell/command/command_test.go
@@ -0,0 +1,281 @@
+package command_test
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ cmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell/command"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/discover"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/lfsauthenticate"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/personalaccesstoken"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/receivepack"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorrecover"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorverify"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadarchive"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadpack"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/config"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
+ "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
+)
+
+var (
+ gitlabShellExec = &executable.Executable{Name: executable.GitlabShell}
+ basicConfig = &config.Config{GitlabUrl: "http+unix://gitlab.socket"}
+)
+
+func TestNew(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ config *config.Config
+ expectedType interface{}
+ }{
+ {
+ desc: "it returns a Discover command",
+ executable: gitlabShellExec,
+ env: buildEnv(""),
+ config: basicConfig,
+ expectedType: &discover.Command{},
+ },
+ {
+ desc: "it returns a TwoFactorRecover command",
+ executable: gitlabShellExec,
+ env: buildEnv("2fa_recovery_codes"),
+ config: basicConfig,
+ expectedType: &twofactorrecover.Command{},
+ },
+ {
+ desc: "it returns a TwoFactorVerify command",
+ executable: gitlabShellExec,
+ env: buildEnv("2fa_verify"),
+ config: basicConfig,
+ expectedType: &twofactorverify.Command{},
+ },
+ {
+ desc: "it returns an LfsAuthenticate command",
+ executable: gitlabShellExec,
+ env: buildEnv("git-lfs-authenticate"),
+ config: basicConfig,
+ expectedType: &lfsauthenticate.Command{},
+ },
+ {
+ desc: "it returns a ReceivePack command",
+ executable: gitlabShellExec,
+ env: buildEnv("git-receive-pack"),
+ config: basicConfig,
+ expectedType: &receivepack.Command{},
+ },
+ {
+ desc: "it returns an UploadPack command",
+ executable: gitlabShellExec,
+ env: buildEnv("git-upload-pack"),
+ config: basicConfig,
+ expectedType: &uploadpack.Command{},
+ },
+ {
+ desc: "it returns an UploadArchive command",
+ executable: gitlabShellExec,
+ env: buildEnv("git-upload-archive"),
+ config: basicConfig,
+ expectedType: &uploadarchive.Command{},
+ },
+ {
+ desc: "it returns a PersonalAccessToken command",
+ executable: gitlabShellExec,
+ env: buildEnv("personal_access_token"),
+ config: basicConfig,
+ expectedType: &personalaccesstoken.Command{},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ command, err := cmd.New(tc.executable, tc.arguments, tc.env, tc.config, nil)
+
+ require.NoError(t, err)
+ require.IsType(t, tc.expectedType, command)
+ })
+ }
+}
+
+func TestFailingNew(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ expectedError error
+ }{
+ {
+ desc: "Parsing environment failed",
+ executable: gitlabShellExec,
+ expectedError: errors.New("Only SSH allowed"),
+ },
+ {
+ desc: "Unknown command given",
+ executable: gitlabShellExec,
+ env: buildEnv("unknown"),
+ expectedError: disallowedcommand.Error,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ command, err := cmd.New(tc.executable, []string{}, tc.env, basicConfig, nil)
+ require.Nil(t, command)
+ require.Equal(t, tc.expectedError, err)
+ })
+ }
+}
+
+func buildEnv(command string) sshenv.Env {
+ return sshenv.Env{
+ IsSSHConnection: true,
+ OriginalCommand: command,
+ }
+}
+
+func TestParseSuccess(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedArgs commandargs.CommandArgs
+ expectError bool
+ }{
+ {
+ desc: "It sets discover as the command when the command string was empty",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{}, CommandType: commandargs.Discover, Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
+ },
+ {
+ desc: "It finds the key id in any passed arguments",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
+ arguments: []string{"hello", "key-123"},
+ expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabKeyId: "123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
+ },
+ {
+ desc: "It finds the key id only if the argument is of <key-id> format",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
+ arguments: []string{"hello", "username-key-123"},
+ expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "username-key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "key-123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
+ },
+ {
+ desc: "It finds the username in any passed arguments",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
+ arguments: []string{"hello", "username-jane-doe"},
+ expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "username-jane-doe"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "jane-doe", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
+ },
+ {
+ desc: "It parses 2fa_recovery_codes command",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "2fa_recovery_codes"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"2fa_recovery_codes"}, CommandType: commandargs.TwoFactorRecover, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "2fa_recovery_codes"}},
+ },
+ {
+ desc: "It parses git-receive-pack command",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack group/repo"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-receive-pack", "group/repo"}, CommandType: commandargs.ReceivePack, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack group/repo"}},
+ },
+ {
+ desc: "It parses git-receive-pack command and a project with single quotes",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack 'group/repo'"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-receive-pack", "group/repo"}, CommandType: commandargs.ReceivePack, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack 'group/repo'"}},
+ },
+ {
+ desc: `It parses "git receive-pack" command`,
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack "group/repo"`},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-receive-pack", "group/repo"}, CommandType: commandargs.ReceivePack, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack "group/repo"`}},
+ },
+ {
+ desc: `It parses a command followed by control characters`,
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack group/repo; any command`},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-receive-pack", "group/repo"}, CommandType: commandargs.ReceivePack, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack group/repo; any command`}},
+ },
+ {
+ desc: "It parses git-upload-pack command",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git upload-pack "group/repo"`},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-upload-pack", "group/repo"}, CommandType: commandargs.UploadPack, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git upload-pack "group/repo"`}},
+ },
+ {
+ desc: "It parses git-upload-archive command",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-upload-archive 'group/repo'"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-upload-archive", "group/repo"}, CommandType: commandargs.UploadArchive, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-upload-archive 'group/repo'"}},
+ },
+ {
+ desc: "It parses git-lfs-authenticate command",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-lfs-authenticate 'group/repo' download"},
+ arguments: []string{},
+ expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"git-lfs-authenticate", "group/repo", "download"}, CommandType: commandargs.LfsAuthenticate, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-lfs-authenticate 'group/repo' download"}},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ result, err := cmd.Parse(tc.executable, tc.arguments, tc.env)
+
+ if !tc.expectError {
+ require.NoError(t, err)
+ require.Equal(t, tc.expectedArgs, result)
+ } else {
+ require.Error(t, err)
+ }
+ })
+ }
+}
+
+func TestParseFailure(t *testing.T) {
+ testCases := []struct {
+ desc string
+ executable *executable.Executable
+ env sshenv.Env
+ arguments []string
+ expectedError string
+ }{
+ {
+ desc: "It fails if SSH connection is not set",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ arguments: []string{},
+ expectedError: "Only SSH allowed",
+ },
+ {
+ desc: "It fails if SSH command is invalid",
+ executable: &executable.Executable{Name: executable.GitlabShell},
+ env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git receive-pack "`},
+ arguments: []string{},
+ expectedError: "Invalid SSH command",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ _, err := cmd.Parse(tc.executable, tc.arguments, tc.env)
+
+ require.EqualError(t, err, tc.expectedError)
+ })
+ }
+}
diff --git a/cmd/gitlab-shell/main.go b/cmd/gitlab-shell/main.go
index fe52bfc..14bd457 100644
--- a/cmd/gitlab-shell/main.go
+++ b/cmd/gitlab-shell/main.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
+ shellCmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command"
"gitlab.com/gitlab-org/gitlab-shell/internal/command/readwriter"
"gitlab.com/gitlab-org/gitlab-shell/internal/config"
@@ -34,7 +35,7 @@ func main() {
ErrOut: os.Stderr,
}
- executable, err := executable.New(executable.GitlabShell, true)
+ executable, err := executable.New(executable.GitlabShell)
if err != nil {
fmt.Fprintln(readWriter.ErrOut, "Failed to determine executable, exiting")
os.Exit(1)
@@ -50,7 +51,7 @@ func main() {
defer logCloser.Close()
env := sshenv.NewFromEnv()
- cmd, err := command.New(executable, os.Args[1:], env, config, readWriter)
+ cmd, err := shellCmd.New(executable, os.Args[1:], env, config, readWriter)
if err != nil {
// For now this could happen if `SSH_CONNECTION` is not set on
// the environment