/cmd/gitlab-shell/command/command_test.go

https://gitlab.com/shaneutt/gitlab-shell · Go · 302 lines · 287 code · 15 blank · 0 comment · 6 complexity · 2e77fd3d0588d4f149d1870963740f71 MD5 · raw file

  1. package command_test
  2. import (
  3. "errors"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. cmd "gitlab.com/gitlab-org/gitlab-shell/cmd/gitlab-shell/command"
  7. "gitlab.com/gitlab-org/gitlab-shell/internal/command/commandargs"
  8. "gitlab.com/gitlab-org/gitlab-shell/internal/command/discover"
  9. "gitlab.com/gitlab-org/gitlab-shell/internal/command/lfsauthenticate"
  10. "gitlab.com/gitlab-org/gitlab-shell/internal/command/personalaccesstoken"
  11. "gitlab.com/gitlab-org/gitlab-shell/internal/command/receivepack"
  12. "gitlab.com/gitlab-org/gitlab-shell/internal/command/shared/disallowedcommand"
  13. "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorrecover"
  14. "gitlab.com/gitlab-org/gitlab-shell/internal/command/twofactorverify"
  15. "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadarchive"
  16. "gitlab.com/gitlab-org/gitlab-shell/internal/command/uploadpack"
  17. "gitlab.com/gitlab-org/gitlab-shell/internal/config"
  18. "gitlab.com/gitlab-org/gitlab-shell/internal/executable"
  19. "gitlab.com/gitlab-org/gitlab-shell/internal/sshenv"
  20. )
  21. var (
  22. gitlabShellExec = &executable.Executable{Name: executable.GitlabShell}
  23. basicConfig = &config.Config{GitlabUrl: "http+unix://gitlab.socket"}
  24. )
  25. func TestNew(t *testing.T) {
  26. testCases := []struct {
  27. desc string
  28. executable *executable.Executable
  29. env sshenv.Env
  30. arguments []string
  31. config *config.Config
  32. expectedType interface{}
  33. }{
  34. {
  35. desc: "it returns a Discover command",
  36. executable: gitlabShellExec,
  37. env: buildEnv(""),
  38. config: basicConfig,
  39. expectedType: &discover.Command{},
  40. },
  41. {
  42. desc: "it returns a TwoFactorRecover command",
  43. executable: gitlabShellExec,
  44. env: buildEnv("2fa_recovery_codes"),
  45. config: basicConfig,
  46. expectedType: &twofactorrecover.Command{},
  47. },
  48. {
  49. desc: "it returns a TwoFactorVerify command",
  50. executable: gitlabShellExec,
  51. env: buildEnv("2fa_verify"),
  52. config: basicConfig,
  53. expectedType: &twofactorverify.Command{},
  54. },
  55. {
  56. desc: "it returns an LfsAuthenticate command",
  57. executable: gitlabShellExec,
  58. env: buildEnv("git-lfs-authenticate"),
  59. config: basicConfig,
  60. expectedType: &lfsauthenticate.Command{},
  61. },
  62. {
  63. desc: "it returns a ReceivePack command",
  64. executable: gitlabShellExec,
  65. env: buildEnv("git-receive-pack"),
  66. config: basicConfig,
  67. expectedType: &receivepack.Command{},
  68. },
  69. {
  70. desc: "it returns an UploadPack command",
  71. executable: gitlabShellExec,
  72. env: buildEnv("git-upload-pack"),
  73. config: basicConfig,
  74. expectedType: &uploadpack.Command{},
  75. },
  76. {
  77. desc: "it returns an UploadArchive command",
  78. executable: gitlabShellExec,
  79. env: buildEnv("git-upload-archive"),
  80. config: basicConfig,
  81. expectedType: &uploadarchive.Command{},
  82. },
  83. {
  84. desc: "it returns a PersonalAccessToken command",
  85. executable: gitlabShellExec,
  86. env: buildEnv("personal_access_token"),
  87. config: basicConfig,
  88. expectedType: &personalaccesstoken.Command{},
  89. },
  90. }
  91. for _, tc := range testCases {
  92. t.Run(tc.desc, func(t *testing.T) {
  93. command, err := cmd.New(tc.arguments, tc.env, tc.config, nil)
  94. require.NoError(t, err)
  95. require.IsType(t, tc.expectedType, command)
  96. })
  97. }
  98. }
  99. func TestFailingNew(t *testing.T) {
  100. testCases := []struct {
  101. desc string
  102. executable *executable.Executable
  103. env sshenv.Env
  104. expectedError error
  105. }{
  106. {
  107. desc: "Parsing environment failed",
  108. executable: gitlabShellExec,
  109. expectedError: errors.New("Only SSH allowed"),
  110. },
  111. {
  112. desc: "Unknown command given",
  113. executable: gitlabShellExec,
  114. env: buildEnv("unknown"),
  115. expectedError: disallowedcommand.Error,
  116. },
  117. }
  118. for _, tc := range testCases {
  119. t.Run(tc.desc, func(t *testing.T) {
  120. command, err := cmd.New([]string{}, tc.env, basicConfig, nil)
  121. require.Nil(t, command)
  122. require.Equal(t, tc.expectedError, err)
  123. })
  124. }
  125. }
  126. func buildEnv(command string) sshenv.Env {
  127. return sshenv.Env{
  128. IsSSHConnection: true,
  129. OriginalCommand: command,
  130. }
  131. }
  132. func TestParseSuccess(t *testing.T) {
  133. testCases := []struct {
  134. desc string
  135. executable *executable.Executable
  136. env sshenv.Env
  137. arguments []string
  138. expectedArgs commandargs.CommandArgs
  139. expectError bool
  140. }{
  141. {
  142. desc: "It sets discover as the command when the command string was empty",
  143. executable: &executable.Executable{Name: executable.GitlabShell},
  144. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  145. arguments: []string{},
  146. expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{}, CommandType: commandargs.Discover, Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  147. },
  148. {
  149. desc: "It finds the key id in any passed arguments",
  150. executable: &executable.Executable{Name: executable.GitlabShell},
  151. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  152. arguments: []string{"hello", "key-123"},
  153. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabKeyId: "123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  154. },
  155. {
  156. desc: "It finds the key id only if the argument is of <key-id> format",
  157. executable: &executable.Executable{Name: executable.GitlabShell},
  158. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  159. arguments: []string{"hello", "username-key-123"},
  160. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "username-key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "key-123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  161. },
  162. {
  163. desc: "It finds the key id if the key is listed as the last argument",
  164. executable: &executable.Executable{Name: executable.GitlabShell},
  165. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  166. arguments: []string{"hello", "gitlab-shell -c key-123"},
  167. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "gitlab-shell -c key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabKeyId: "123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  168. },
  169. {
  170. desc: "It finds the username if the username is listed as the last argument",
  171. executable: &executable.Executable{Name: executable.GitlabShell},
  172. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  173. arguments: []string{"hello", "gitlab-shell -c username-jane-doe"},
  174. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "gitlab-shell -c username-jane-doe"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "jane-doe", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  175. },
  176. {
  177. desc: "It finds the key id only if the last argument is of <key-id> format",
  178. executable: &executable.Executable{Name: executable.GitlabShell},
  179. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  180. arguments: []string{"hello", "gitlab-shell -c username-key-123"},
  181. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "gitlab-shell -c username-key-123"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "key-123", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  182. },
  183. {
  184. desc: "It finds the username in any passed arguments",
  185. executable: &executable.Executable{Name: executable.GitlabShell},
  186. env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"},
  187. arguments: []string{"hello", "username-jane-doe"},
  188. expectedArgs: &commandargs.Shell{Arguments: []string{"hello", "username-jane-doe"}, SshArgs: []string{}, CommandType: commandargs.Discover, GitlabUsername: "jane-doe", Env: sshenv.Env{IsSSHConnection: true, RemoteAddr: "1"}},
  189. },
  190. {
  191. desc: "It parses 2fa_recovery_codes command",
  192. executable: &executable.Executable{Name: executable.GitlabShell},
  193. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "2fa_recovery_codes"},
  194. arguments: []string{},
  195. expectedArgs: &commandargs.Shell{Arguments: []string{}, SshArgs: []string{"2fa_recovery_codes"}, CommandType: commandargs.TwoFactorRecover, Env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "2fa_recovery_codes"}},
  196. },
  197. {
  198. desc: "It parses git-receive-pack command",
  199. executable: &executable.Executable{Name: executable.GitlabShell},
  200. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack group/repo"},
  201. arguments: []string{},
  202. 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"}},
  203. },
  204. {
  205. desc: "It parses git-receive-pack command and a project with single quotes",
  206. executable: &executable.Executable{Name: executable.GitlabShell},
  207. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-receive-pack 'group/repo'"},
  208. arguments: []string{},
  209. 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'"}},
  210. },
  211. {
  212. desc: `It parses "git receive-pack" command`,
  213. executable: &executable.Executable{Name: executable.GitlabShell},
  214. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack "group/repo"`},
  215. arguments: []string{},
  216. 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"`}},
  217. },
  218. {
  219. desc: `It parses a command followed by control characters`,
  220. executable: &executable.Executable{Name: executable.GitlabShell},
  221. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git-receive-pack group/repo; any command`},
  222. arguments: []string{},
  223. 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`}},
  224. },
  225. {
  226. desc: "It parses git-upload-pack command",
  227. executable: &executable.Executable{Name: executable.GitlabShell},
  228. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git upload-pack "group/repo"`},
  229. arguments: []string{},
  230. 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"`}},
  231. },
  232. {
  233. desc: "It parses git-upload-archive command",
  234. executable: &executable.Executable{Name: executable.GitlabShell},
  235. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-upload-archive 'group/repo'"},
  236. arguments: []string{},
  237. 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'"}},
  238. },
  239. {
  240. desc: "It parses git-lfs-authenticate command",
  241. executable: &executable.Executable{Name: executable.GitlabShell},
  242. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: "git-lfs-authenticate 'group/repo' download"},
  243. arguments: []string{},
  244. 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"}},
  245. },
  246. }
  247. for _, tc := range testCases {
  248. t.Run(tc.desc, func(t *testing.T) {
  249. result, err := cmd.Parse(tc.arguments, tc.env)
  250. if !tc.expectError {
  251. require.NoError(t, err)
  252. require.Equal(t, tc.expectedArgs, result)
  253. } else {
  254. require.Error(t, err)
  255. }
  256. })
  257. }
  258. }
  259. func TestParseFailure(t *testing.T) {
  260. testCases := []struct {
  261. desc string
  262. executable *executable.Executable
  263. env sshenv.Env
  264. arguments []string
  265. expectedError string
  266. }{
  267. {
  268. desc: "It fails if SSH connection is not set",
  269. executable: &executable.Executable{Name: executable.GitlabShell},
  270. arguments: []string{},
  271. expectedError: "Only SSH allowed",
  272. },
  273. {
  274. desc: "It fails if SSH command is invalid",
  275. executable: &executable.Executable{Name: executable.GitlabShell},
  276. env: sshenv.Env{IsSSHConnection: true, OriginalCommand: `git receive-pack "`},
  277. arguments: []string{},
  278. expectedError: "Invalid SSH command: invalid command line string",
  279. },
  280. }
  281. for _, tc := range testCases {
  282. t.Run(tc.desc, func(t *testing.T) {
  283. _, err := cmd.Parse(tc.arguments, tc.env)
  284. require.EqualError(t, err, tc.expectedError)
  285. })
  286. }
  287. }