diff options
author | Ash McKenzie <amckenzie@gitlab.com> | 2018-07-25 23:53:24 +1000 |
---|---|---|
committer | Ash McKenzie <amckenzie@gitlab.com> | 2018-07-25 23:53:24 +1000 |
commit | 5e04d2613f6cecd41407e5037d8e2a36fe241151 (patch) | |
tree | d9250aa2c5492bd7e3373e8cff5bc6f7122ba4db /spec/gitlab_shell_spec.rb | |
parent | cf27364efc75388de805adc368eb6124c180b1b4 (diff) | |
download | gitlab-shell-ash.mckenzie/srp-refactor.tar.gz |
Diffstat (limited to 'spec/gitlab_shell_spec.rb')
-rw-r--r-- | spec/gitlab_shell_spec.rb | 1106 |
1 files changed, 619 insertions, 487 deletions
diff --git a/spec/gitlab_shell_spec.rb b/spec/gitlab_shell_spec.rb index e02e452..4da5c52 100644 --- a/spec/gitlab_shell_spec.rb +++ b/spec/gitlab_shell_spec.rb @@ -13,41 +13,44 @@ describe GitlabShell do end subject do - ARGV[0] = key_id - GitlabShell.new(key_id).tap do |shell| - shell.stub(exec_cmd: :exec_called) - shell.stub(api: api) - end - end - - let(:gitaly_check_access) { GitAccessStatus.new( - true, - 'ok', - gl_repository: gl_repository, - gl_username: gl_username, - repository_path: repo_path, - gitaly: { 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default'} , 'address' => 'unix:gitaly.socket' } - ) - } - - let(:api) do - double(GitlabNet).tap do |api| - api.stub(discover: { 'name' => 'John Doe', 'username' => 'testuser' }) - api.stub(check_access: GitAccessStatus.new( - true, - 'ok', - gl_repository: gl_repository, - gl_username: gl_username, - repository_path: repo_path, - gitaly: nil)) - api.stub(two_factor_recovery_codes: { - 'success' => true, - 'recovery_codes' => ['f67c514de60c4953', '41278385fc00c1e0'] - }) - end + # ARGV[0] = key_id + # GitlabShell.new(key_id).tap do |shell| + # shell.stub(exec_cmd: :exec_called) + # shell.stub(api: api) + # end + described_class.new(key_id) end let(:key_id) { "key-#{rand(100) + 100}" } + let(:gitaly_action) { Action::Gitaly.new( + key_id, + gl_repository, + gl_username, + repo_path, + { 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default'} , 'address' => 'unix:gitaly.socket' }) + } + + # let(:gitaly_nil_action) { Action::Gitaly.new( + # key_id, + # gl_repository, + # gl_username, + # repo_path, + # nil) + # } + + let(:api) { double(GitlabNet) } + + # let(:api) do + # double(GitlabNet).tap do |api| + # api.stub(discover: { 'name' => 'John Doe', 'username' => 'testuser' }) + # api.stub(check_access: gitaly_nil_action) # FIXME: need two different? + # api.stub(two_factor_recovery_codes: { + # 'success' => true, + # 'recovery_codes' => ['f67c514de60c4953', '41278385fc00c1e0'] + # }) + # end + # end + let(:ssh_cmd) { nil } let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') } @@ -57,517 +60,646 @@ describe GitlabShell do let(:gl_username) { 'testuser' } before do - GitlabConfig.any_instance.stub(audit_usernames: false) - end - - describe :initialize do - let(:ssh_cmd) { 'git-receive-pack' } - - its(:key_id) { should == key_id } - end - - describe :parse_cmd do - describe 'git' do - context 'w/o namespace' do - let(:ssh_args) { %W(git-upload-pack gitlab-ci.git) } - - before do - subject.send :parse_cmd, ssh_args - end - - its(:repo_name) { should == 'gitlab-ci.git' } - its(:command) { should == 'git-upload-pack' } - end - - context 'namespace' do - let(:repo_name) { 'dmitriy.zaporozhets/gitlab-ci.git' } - let(:ssh_args) { %W(git-upload-pack dmitriy.zaporozhets/gitlab-ci.git) } - - before do - subject.send :parse_cmd, ssh_args - end - - its(:repo_name) { should == 'dmitriy.zaporozhets/gitlab-ci.git' } - its(:command) { should == 'git-upload-pack' } - end - - context 'with an invalid number of arguments' do - let(:ssh_args) { %W(foobar) } - - it "should raise an DisallowedCommandError" do - expect { subject.send :parse_cmd, ssh_args }.to raise_error(GitlabShell::DisallowedCommandError) - end - end - - context 'with an API command' do - before do - subject.send :parse_cmd, ssh_args - end - - context 'when generating recovery codes' do - let(:ssh_args) { %w(2fa_recovery_codes) } - - it 'sets the correct command' do - expect(subject.send(:command)).to eq('2fa_recovery_codes') # FIXME: don't access private instance variables - end - - it 'does not set repo name' do - expect(subject.send(:repo_name)).to be_nil # FIXME: don't access private instance variables - end - end - end - end - - describe 'git-lfs' do - let(:repo_name) { 'dzaporozhets/gitlab.git' } - let(:ssh_args) { %W(git-lfs-authenticate dzaporozhets/gitlab.git download) } - - before do - subject.send :parse_cmd, ssh_args - end - - its(:repo_name) { should == 'dzaporozhets/gitlab.git' } - its(:command) { should == 'git-lfs-authenticate' } - its(:git_access) { should == 'git-upload-pack' } - end - - describe 'git-lfs old clients' do - let(:repo_name) { 'dzaporozhets/gitlab.git' } - let(:ssh_args) { %W(git-lfs-authenticate dzaporozhets/gitlab.git download long_oid) } - - before do - subject.send :parse_cmd, ssh_args - end - - its(:repo_name) { should == 'dzaporozhets/gitlab.git' } - its(:command) { should == 'git-lfs-authenticate' } - its(:git_access) { should == 'git-upload-pack' } - end + # GitlabConfig.any_instance.stub(audit_usernames: false) + allow(GitlabNet).to receive(:new).and_return(api) + allow(api).to receive(:discover).with(key_id).and_return('username' => gl_username) end - describe :exec do - let(:gitaly_message) { JSON.dump({ 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' }, 'gl_repository' => gl_repository, 'gl_id' => key_id, 'gl_username' => gl_username}) } - - shared_examples_for 'upload-pack' do |command| - let(:ssh_cmd) { "#{command} gitlab-ci.git" } - after { subject.exec(ssh_cmd) } - - it "should process the command" do - subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git)) + describe '#exec' do + context 'when origin_cmd is nil' do + it 'prints Welcome.. and returns true' do + expect($stdout).to receive(:puts).with('Welcome to GitLab, testuser!') + expect(subject.exec(nil)).to be_truthy end - - it "should execute the command" do - subject.should_receive(:exec_cmd).with('git-upload-pack', repo_path) - end - - it "should log the command execution" do - message = "executing git command" - user_string = "user with key #{key_id}" - $logger.should_receive(:info).with(message, command: "git-upload-pack #{repo_path}", user: user_string) - end - - it "should use usernames if configured to do so" do - GitlabConfig.any_instance.stub(audit_usernames: true) - $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) - end - end - - context 'git-upload-pack' do - it_behaves_like 'upload-pack', 'git-upload-pack' end - context 'git upload-pack' do - it_behaves_like 'upload-pack', 'git upload-pack' - end - - context 'gitaly-upload-pack' do - let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } - before { - api.stub(check_access: gitaly_check_access) - } - after { subject.exec(ssh_cmd) } - - it "should process the command" do - subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git)) - end - - it "should execute the command" do - subject.should_receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-upload-pack"), 'unix:gitaly.socket', gitaly_message) - end - - it "should log the command execution" do - message = "executing git command" - user_string = "user with key #{key_id}" - $logger.should_receive(:info).with(message, command: "gitaly-upload-pack unix:gitaly.socket #{gitaly_message}", user: user_string) - end - - it "should use usernames if configured to do so" do - GitlabConfig.any_instance.stub(audit_usernames: true) - $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + context 'when origin_cmd is empty' do + it 'prints Welcome.. and returns true' do + expect($stdout).to receive(:puts).with('Welcome to GitLab, testuser!') + expect(subject.exec('')).to be_truthy end end - context 'git-receive-pack' do - let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } - after { subject.exec(ssh_cmd) } - - it "should process the command" do - subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git)) - end - - it "should execute the command" do - subject.should_receive(:exec_cmd).with('git-receive-pack', repo_path) - end - - it "should log the command execution" do - message = "executing git command" - user_string = "user with key #{key_id}" - $logger.should_receive(:info).with(message, command: "git-receive-pack #{repo_path}", user: user_string) + context 'when origin_cmd is invalid' do + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Disallowed command') + expect(subject.exec("git-invalid-command #{repo_name}")).to be_falsey end end - context 'gitaly-receive-pack' do - let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } - before { - api.stub(check_access: gitaly_check_access) - } - after { subject.exec(ssh_cmd) } - - it "should process the command" do - subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git)) - end - - it "should execute the command" do - subject.should_receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-receive-pack"), 'unix:gitaly.socket', gitaly_message) - end - - it "should log the command execution" do - message = "executing git command" - user_string = "user with key #{key_id}" - $logger.should_receive(:info).with(message, command: "gitaly-receive-pack unix:gitaly.socket #{gitaly_message}", user: user_string) - end - - it "should use usernames if configured to do so" do - GitlabConfig.any_instance.stub(audit_usernames: true) - $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + context 'when origin_cmd is valid, but incomplete' do + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Disallowed command') + expect(subject.exec('git-upload-pack')).to be_falsey end end - context 'custom action' do - let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } - let(:custom_action_access_result) { Action::Custom.create_from_json('{"status":true,"message":"Attempting to proxy to primary..","payload":{"api_endpoints":["fake/info_refs","fake/push"],"data":{"username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git"}}}') } - let(:http_success) { double(Net::HTTPOK, code: '200', body: 'OK') } - let(:http_error) { double(Net::HTTPInternalServerError, code: '500', body: 'Internal Server Error') } - - before { api.stub(check_access: custom_action_access_result) } - after { subject.exec(ssh_cmd) } - - it "should attempt execute the custom action" do - subject.should_receive(:exec_custom_action).with(custom_action_access_result) - end - - it "should execute the custom action" do - custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_success) - end - - it "should raise an exception when the custom action is unsuccessful" do - custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_error) - end - end - - shared_examples_for 'upload-archive' do |command| - let(:ssh_cmd) { "#{command} gitlab-ci.git" } - let(:exec_cmd_params) { ['git-upload-archive', repo_path] } - let(:exec_cmd_log_params) { exec_cmd_params } - - after { subject.exec(ssh_cmd) } - - it "should process the command" do - subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-archive gitlab-ci.git)) - end - - it "should execute the command" do - subject.should_receive(:exec_cmd).with(*exec_cmd_params) - end - - it "should log the command execution" do - message = "executing git command" - user_string = "user with key #{key_id}" - $logger.should_receive(:info).with(message, command: exec_cmd_log_params.join(' '), user: user_string) - end - - it "should use usernames if configured to do so" do - GitlabConfig.any_instance.stub(audit_usernames: true) - $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) - end - end - - context 'git-upload-archive' do - it_behaves_like 'upload-archive', 'git-upload-archive' - end - - context 'git upload-archive' do - it_behaves_like 'upload-archive', 'git upload-archive' - end - - context 'gitaly-upload-archive' do - before do - api.stub(check_access: gitaly_check_access) + context 'when origin_cmd is git-lfs-authenticate' do + context 'but incomplete' do + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Disallowed command') + expect(subject.exec('git-lfs-authenticate')).to be_falsey + end end - it_behaves_like 'upload-archive', 'git-upload-archive' do - let(:gitaly_executable) { "gitaly-upload-archive" } - let(:exec_cmd_params) do - [ - File.join(ROOT_PATH, "bin", gitaly_executable), - 'unix:gitaly.socket', - gitaly_message - ] - end - let(:exec_cmd_log_params) do - [gitaly_executable, 'unix:gitaly.socket', gitaly_message] + context 'but invalid' do + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Disallowed command') + expect(subject.exec("git-lfs-authenticate #{repo_name} invalid")).to be_falsey end end end - context 'arbitrary command' do - let(:ssh_cmd) { 'arbitrary command' } - after { subject.exec(ssh_cmd) } - - it "should not process the command" do - subject.should_not_receive(:process_cmd) - end - - it "should not execute the command" do - subject.should_not_receive(:exec_cmd) - end - - it "should log the attempt" do - message = 'Denied disallowed command' - user_string = "user with key #{key_id}" - $logger.should_receive(:warn).with(message, command: 'arbitrary command', user: user_string) + context 'when the API is unavailable' do + before do + expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, key_id, '_any').and_raise(GitlabNet::ApiUnreachableError) end - end - - context 'no command' do - after { subject.exec(nil) } - it "should call api.discover" do - api.should_receive(:discover).with(key_id) + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Failed to authorize your Git request: internal API unreachable') + expect(subject.exec("git-upload-pack #{repo_name}")).to be_falsey end end - context "failed connection" do - let(:ssh_cmd) { 'git-upload-pack gitlab-ci.git' } - - before { - api.stub(:check_access).and_raise(GitlabNet::ApiUnreachableError) - } - after { subject.exec(ssh_cmd) } - - it "should not process the command" do - subject.should_not_receive(:process_cmd) + context 'when access to the repo is denied' do + before do + expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, key_id, '_any').and_raise(AccessDeniedError, 'Sorry, access denied') end - it "should not execute the command" do - subject.should_not_receive(:exec_cmd) + it 'prints a message to stderr and returns false' do + expect($stderr).to receive(:puts).with('GitLab: Sorry, access denied') + expect(subject.exec("git-upload-pack #{repo_name}")).to be_falsey end end - context 'with an API command' do + context 'when access has been verified OK' do before do - allow(subject).to receive(:continue?).and_return(true) + expect(api).to receive(:check_access).with(git_access, nil, repo_name, key_id, '_any').and_return(gitaly_action) end - context 'when generating recovery codes' do - let(:ssh_cmd) { '2fa_recovery_codes' } - after do - subject.exec(ssh_cmd) - end - - it 'does not call verify_access' do - expect(subject).not_to receive(:verify_access) - end - - it 'calls the corresponding method' do - expect(subject).to receive(:api_2fa_recovery_codes) - end + context 'when origin_cmd is git-upload-pack' do + let(:git_access) { 'git-upload-pack'} - it 'outputs recovery codes' do - expect($stdout).to receive(:puts) - .with(/f67c514de60c4953\n41278385fc00c1e0/) + it 'returns true' do + expect(gitaly_action).to receive(:execute).with('git-upload-pack', %W{git-upload-pack #{repo_name}}).and_return(true) + expect(subject.exec("git-upload-pack #{repo_name}")).to be_truthy end - context 'when the process is unsuccessful' do - it 'displays the error to the user' do - api.stub(two_factor_recovery_codes: { - 'success' => false, - 'message' => 'Could not find the given key' - }) - - expect($stdout).to receive(:puts) - .with(/Could not find the given key/) + context 'but repo path is invalid' do + it 'prints a message to stderr and returns false' do + expect(gitaly_action).to receive(:execute).with('git-upload-pack', %W{git-upload-pack #{repo_name}}).and_raise(InvalidRepositoryPathError) + expect($stderr).to receive(:puts).with('GitLab: Invalid repository path') + expect(subject.exec("git-upload-pack #{repo_name}")).to be_falsey end end end - end - end - - describe :validate_access do - let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } - describe 'check access with api' do - after { subject.exec(ssh_cmd) } + context 'when origin_cmd is git upload-pack (git for Windows 2.14' do + let(:git_access) { 'git-upload-pack'} - it "should call api.check_access" do - api.should_receive(:check_access).with('git-upload-pack', nil, 'gitlab-ci.git', key_id, '_any', 'ssh') - end - - it "should disallow access and log the attempt if check_access returns false status" do - api.stub(check_access: GitAccessStatus.new( - false, - 'denied', - gl_repository: nil, - gl_username: nil, - repository_path: nil, - gitaly: nil)) - message = 'Access denied' - user_string = "user with key #{key_id}" - $logger.should_receive(:warn).with(message, command: 'git-upload-pack gitlab-ci.git', user: user_string) - end - end - - describe 'set the repository path' do - context 'with a correct path' do - before { subject.exec(ssh_cmd) } - - its(:repo_path) { should == repo_path } - end - - context "with a path that doesn't match an absolute path" do - before do - File.stub(:absolute_path) { 'y/gitlab-ci.git' } - end - - it "refuses to assign the path" do - $stderr.should_receive(:puts).with("GitLab: Invalid repository path") - expect(subject.exec(ssh_cmd)).to be_falsey + it 'returns true' do + expect(gitaly_action).to receive(:execute).with('git-upload-pack', %W{git-upload-pack #{repo_name}}).and_return(true) + expect(subject.exec("git upload-pack #{repo_name}")).to be_truthy end end - end - end - - describe :exec_cmd do - let(:shell) { GitlabShell.new(key_id) } - let(:env) do - { - 'HOME' => ENV['HOME'], - 'PATH' => ENV['PATH'], - 'LD_LIBRARY_PATH' => ENV['LD_LIBRARY_PATH'], - 'LANG' => ENV['LANG'], - 'GL_ID' => key_id, - 'GL_PROTOCOL' => 'ssh', - 'GL_REPOSITORY' => gl_repository, - 'GL_USERNAME' => 'testuser' - } - end - let(:exec_options) { { unsetenv_others: true, chdir: ROOT_PATH } } - before do - Kernel.stub(:exec) - shell.instance_variable_set(:@gl_repository, gl_repository) - shell.instance_variable_set(:@username, gl_username) - end - it "uses Kernel::exec method" do - Kernel.should_receive(:exec).with(env, 1, 2, exec_options).once - shell.send :exec_cmd, 1, 2 - end - - it "refuses to execute a lone non-array argument" do - expect { shell.send :exec_cmd, 1 }.to raise_error(GitlabShell::DisallowedCommandError) - end - - it "allows one argument if it is an array" do - Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once - shell.send :exec_cmd, [1, 2] - end + context 'when origin_cmd is git-lfs-authenticate' do + let(:fake_payload) { 'FAKE PAYLOAD' } + let(:lfs_access) { double(GitlabLfsAuthentication, authentication_payload: fake_payload)} - context "when specifying a git_tracing log file" do - let(:git_trace_log_file) { '/tmp/git_trace_performance.log' } - - before do - GitlabConfig.any_instance.stub(git_trace_log_file: git_trace_log_file) - shell - end - - it "uses GIT_TRACE_PERFORMANCE" do - expected_hash = hash_including( - 'GIT_TRACE' => git_trace_log_file, - 'GIT_TRACE_PACKET' => git_trace_log_file, - 'GIT_TRACE_PERFORMANCE' => git_trace_log_file - ) - Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once - - shell.send :exec_cmd, [1, 2] - end - - context "when provides a relative path" do - let(:git_trace_log_file) { 'git_trace_performance.log' } - - it "does not uses GIT_TRACE*" do - # If we try to use it we'll show a warning to the users - expected_hash = hash_excluding( - 'GIT_TRACE', 'GIT_TRACE_PACKET', 'GIT_TRACE_PERFORMANCE' - ) - Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once - - shell.send :exec_cmd, [1, 2] - end - - it "writes an entry on the log" do - message = 'git trace log path must be absolute, ignoring' - - expect($logger).to receive(:warn). - with(message, git_trace_log_file: git_trace_log_file) - - Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once - shell.send :exec_cmd, [1, 2] - end - end - - context "when provides a file not writable" do before do - expect(File).to receive(:open).with(git_trace_log_file, 'a').and_raise(Errno::EACCES) + expect(api).to receive(:lfs_authenticate).with(key_id, repo_name).and_return(lfs_access) end - it "does not uses GIT_TRACE*" do - # If we try to use it we'll show a warning to the users - expected_hash = hash_excluding( - 'GIT_TRACE', 'GIT_TRACE_PACKET', 'GIT_TRACE_PERFORMANCE' - ) - Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once + context 'upload' do + let(:git_access) { 'git-receive-pack'} - shell.send :exec_cmd, [1, 2] + it 'returns true' do + expect($stdout).to receive(:puts).with(fake_payload) + expect(subject.exec("git-lfs-authenticate #{repo_name} upload")).to be_truthy + end end - it "writes an entry on the log" do - message = 'Failed to open git trace log file' - error = 'Permission denied' - - expect($logger).to receive(:warn). - with(message, git_trace_log_file: git_trace_log_file, error: error) + context 'download' do + let(:git_access) { 'git-upload-pack'} - Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once - shell.send :exec_cmd, [1, 2] + it 'returns true' do + expect($stdout).to receive(:puts).with(fake_payload) + expect(subject.exec("git-lfs-authenticate #{repo_name} download")).to be_truthy + end end end end end - describe :api do - let(:shell) { GitlabShell.new(key_id) } - subject { shell.send :api } + # describe :initialize do + # let(:ssh_cmd) { 'git-receive-pack' } + + # its(:key_id) { should == key_id } + # end - it { should be_a(GitlabNet) } - end + # describe '#parse_cmd' do + # describe 'git' do + # context 'w/o namespace' do + # let(:ssh_args) { %W(git-upload-pack gitlab-ci.git) } + + # before do + # subject.send(:parse_cmd, ssh_args) # FIXME: don't access private methods + # end + + # its(:repo_name) { should == 'gitlab-ci.git' } + # its(:command) { should == 'git-upload-pack' } + # end + + # context 'namespace' do + # let(:repo_name) { 'dmitriy.zaporozhets/gitlab-ci.git' } + # let(:ssh_args) { %W(git-upload-pack dmitriy.zaporozhets/gitlab-ci.git) } + + # before do + # subject.send(:parse_cmd, ssh_args) # FIXME: don't access private methods + # end + + # its(:repo_name) { should == 'dmitriy.zaporozhets/gitlab-ci.git' } + # its(:command) { should == 'git-upload-pack' } + # end + + # context 'with an invalid number of arguments' do + # let(:ssh_args) { %W(foobar) } + + # it "should raise an DisallowedCommandError" do + # expect { subject.send :parse_cmd, ssh_args }.to raise_error(GitlabShell::DisallowedCommandError) + # end + # end + + # context 'with an API command' do + # before do + # subject.send(:parse_cmd, ssh_args) # FIXME: don't access private methods + # end + + # context 'when generating recovery codes' do + # let(:ssh_args) { %w(2fa_recovery_codes) } + + # it 'sets the correct command' do + # expect(subject.send(:command)).to eq('2fa_recovery_codes') # FIXME: don't access private instance variables + # end + + # it 'does not set repo name' do + # expect(subject.send(:repo_name)).to be_nil # FIXME: don't access private instance variables + # end + # end + # end + # end + + # describe 'git-lfs' do + # let(:repo_name) { 'dzaporozhets/gitlab.git' } + # let(:ssh_args) { %W(git-lfs-authenticate dzaporozhets/gitlab.git download) } + + # before do + # subject.send(:parse_cmd, ssh_args) # FIXME: don't access private methods + # end + + # its(:repo_name) { should == 'dzaporozhets/gitlab.git' } + # its(:command) { should == 'git-lfs-authenticate' } + # its(:git_access) { should == 'git-upload-pack' } + # end + + # describe 'git-lfs old clients' do + # let(:repo_name) { 'dzaporozhets/gitlab.git' } + # let(:ssh_args) { %W(git-lfs-authenticate dzaporozhets/gitlab.git download long_oid) } + + # before do + # subject.send(:parse_cmd, ssh_args) # FIXME: don't access private methods + # end + + # its(:repo_name) { should == 'dzaporozhets/gitlab.git' } + # its(:command) { should == 'git-lfs-authenticate' } + # its(:git_access) { should == 'git-upload-pack' } + # end + # end + + # describe '#exec' do + # let(:gitaly_message) { JSON.dump({ 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' }, 'gl_repository' => gl_repository, 'gl_id' => key_id, 'gl_username' => gl_username}) } + + # shared_examples_for 'upload-pack' do |command| + # let(:ssh_cmd) { "#{command} gitlab-ci.git" } + # after { subject.exec(ssh_cmd) } + + # it "should process the command" do + # subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git)) + # end + + # it "should execute the command" do + # subject.should_receive(:exec_cmd).with('git-upload-pack', repo_path) + # end + + # it "should log the command execution" do + # message = "executing git command" + # user_string = "user with key #{key_id}" + # $logger.should_receive(:info).with(message, command: "git-upload-pack #{repo_path}", user: user_string) + # end + + # it "should use usernames if configured to do so" do + # GitlabConfig.any_instance.stub(audit_usernames: true) + # $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + # end + # end + + # context 'git-upload-pack' do + # it_behaves_like 'upload-pack', 'git-upload-pack' + # end + + # context 'git upload-pack' do + # it_behaves_like 'upload-pack', 'git upload-pack' + # end + + # context 'gitaly-upload-pack' do + # let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } + # before { + # api.stub(check_access: gitaly_action) + # } + # after { subject.exec(ssh_cmd) } + + # it "should process the command" do + # subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git)) + # end + + # it "should execute the command" do + # subject.should_receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-upload-pack"), 'unix:gitaly.socket', gitaly_message) + # end + + # it "should log the command execution" do + # message = "executing git command" + # user_string = "user with key #{key_id}" + # $logger.should_receive(:info).with(message, command: "gitaly-upload-pack unix:gitaly.socket #{gitaly_message}", user: user_string) + # end + + # it "should use usernames if configured to do so" do + # GitlabConfig.any_instance.stub(audit_usernames: true) + # $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + # end + # end + + # context 'git-receive-pack' do + # let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } + # after { subject.exec(ssh_cmd) } + + # it "should process the command" do + # subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git)) + # end + + # it "should execute the command" do + # subject.should_receive(:exec_cmd).with('git-receive-pack', repo_path) + # end + + # it "should log the command execution" do + # message = "executing git command" + # user_string = "user with key #{key_id}" + # $logger.should_receive(:info).with(message, command: "git-receive-pack #{repo_path}", user: user_string) + # end + # end + + # context 'gitaly-receive-pack' do + # let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } + # before { + # api.stub(check_access: gitaly_action) + # } + # after { subject.exec(ssh_cmd) } + + # it "should process the command" do + # subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git)) + # end + + # it "should execute the command" do + # subject.should_receive(:exec_cmd).with(File.join(ROOT_PATH, "bin/gitaly-receive-pack"), 'unix:gitaly.socket', gitaly_message) + # end + + # it "should log the command execution" do + # message = "executing git command" + # user_string = "user with key #{key_id}" + # $logger.should_receive(:info).with(message, command: "gitaly-receive-pack unix:gitaly.socket #{gitaly_message}", user: user_string) + # end + + # it "should use usernames if configured to do so" do + # GitlabConfig.any_instance.stub(audit_usernames: true) + # $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + # end + # end + + # context 'custom action' do + # let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" } + # let(:custom_action_access_result) { Action::Custom.create_from_json('{"status":true,"message":"Attempting to proxy to primary..","payload":{"api_endpoints":["fake/info_refs","fake/push"],"data":{"username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git"}}}') } + # let(:http_success) { double(Net::HTTPOK, code: '200', body: 'OK') } + # let(:http_error) { double(Net::HTTPInternalServerError, code: '500', body: 'Internal Server Error') } + + # before { api.stub(check_access: custom_action_access_result) } + # after { subject.exec(ssh_cmd) } + + # it "should attempt execute the custom action" do + # subject.should_receive(:exec_custom_action).with(custom_action_access_result) + # end + + # it "should execute the custom action" do + # custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_success) + # end + + # it "should raise an exception when the custom action is unsuccessful" do + # custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_error) + # end + # end + + # shared_examples_for 'upload-archive' do |command| + # let(:ssh_cmd) { "#{command} gitlab-ci.git" } + # let(:exec_cmd_params) { ['git-upload-archive', repo_path] } + # let(:exec_cmd_log_params) { exec_cmd_params } + + # after { subject.exec(ssh_cmd) } + + # it "should process the command" do + # subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-archive gitlab-ci.git)) + # end + + # it "should execute the command" do + # subject.should_receive(:exec_cmd).with(*exec_cmd_params) + # end + + # it "should log the command execution" do + # message = "executing git command" + # user_string = "user with key #{key_id}" + # $logger.should_receive(:info).with(message, command: exec_cmd_log_params.join(' '), user: user_string) + # end + + # it "should use usernames if configured to do so" do + # GitlabConfig.any_instance.stub(audit_usernames: true) + # $logger.should_receive(:info).with("executing git command", hash_including(user: 'testuser')) + # end + # end + + # context 'git-upload-archive' do + # it_behaves_like 'upload-archive', 'git-upload-archive' + # end + + # context 'git upload-archive' do + # it_behaves_like 'upload-archive', 'git upload-archive' + # end + + # context 'gitaly-upload-archive' do + # before do + # api.stub(check_access: gitaly_action) + # end + + # it_behaves_like 'upload-archive', 'git-upload-archive' do + # let(:gitaly_executable) { "gitaly-upload-archive" } + # let(:exec_cmd_params) do + # [ + # File.join(ROOT_PATH, "bin", gitaly_executable), + # 'unix:gitaly.socket', + # gitaly_message + # ] + # end + # let(:exec_cmd_log_params) do + # [gitaly_executable, 'unix:gitaly.socket', gitaly_message] + # end + # end + # end + + # context 'arbitrary command' do + # let(:ssh_cmd) { 'arbitrary command' } + # after { subject.exec(ssh_cmd) } + + # it "should not process the command" do + # subject.should_not_receive(:process_cmd) + # end + + # it "should not execute the command" do + # subject.should_not_receive(:exec_cmd) + # end + + # it "should log the attempt" do + # message = 'Denied disallowed command' + # user_string = "user with key #{key_id}" + # $logger.should_receive(:warn).with(message, command: 'arbitrary command', user: user_string) + # end + # end + + # context 'no command' do + # after { subject.exec(nil) } + + # it "should call api.discover" do + # api.should_receive(:discover).with(key_id) + # end + # end + + # context "failed connection" do + # let(:ssh_cmd) { 'git-upload-pack gitlab-ci.git' } + + # before { + # api.stub(:check_access).and_raise(GitlabNet::ApiUnreachableError) + # } + # after { subject.exec(ssh_cmd) } + + # it "should not process the command" do + # subject.should_not_receive(:process_cmd) + # end + + # it "should not execute the command" do + # subject.should_not_receive(:exec_cmd) + # end + # end + + # context 'with an API command' do + # before do + # allow(subject).to receive(:continue?).and_return(true) + # end + + # context 'when generating recovery codes' do + # let(:ssh_cmd) { '2fa_recovery_codes' } + # after do + # subject.exec(ssh_cmd) + # end + + # it 'does not call verify_access' do + # expect(subject).not_to receive(:verify_access) + # end + + # it 'calls the corresponding method' do + # expect(subject).to receive(:api_2fa_recovery_codes) + # end + + # it 'outputs recovery codes' do + # expect($stdout).to receive(:puts) + # .with(/f67c514de60c4953\n41278385fc00c1e0/) + # end + + # context 'when the process is unsuccessful' do + # it 'displays the error to the user' do + # api.stub(two_factor_recovery_codes: { + # 'success' => false, + # 'message' => 'Could not find the given key' + # }) + + # expect($stdout).to receive(:puts) + # .with(/Could not find the given key/) + # end + # end + # end + # end + # end + + # describe '#validate_access' do + # let(:ssh_cmd) { "git-upload-pack gitlab-ci.git" } + + # describe 'check access with api' do + # after { subject.exec(ssh_cmd) } + + # it "should call api.check_access" do + # api.should_receive(:check_access).with('git-upload-pack', nil, 'gitlab-ci.git', key_id, '_any', 'ssh') + # end + + # it "should disallow access and log the attempt if check_access returns false status" do + # api.stub(check_access: GitAccessStatus.new( + # false, + # 'denied', + # gl_repository: nil, + # gl_username: nil, + # repository_path: nil, + # gitaly: nil)) + # message = 'Access denied' + # user_string = "user with key #{key_id}" + # $logger.should_receive(:warn).with(message, command: 'git-upload-pack gitlab-ci.git', user: user_string) + # end + # end + + # describe 'set the repository path' do + # context 'with a correct path' do + # before { subject.exec(ssh_cmd) } + + # its(:repo_path) { should == repo_path } + # end + + # context "with a path that doesn't match an absolute path" do + # before do + # File.stub(:absolute_path) { 'y/gitlab-ci.git' } + # end + + # it "refuses to assign the path" do + # $stderr.should_receive(:puts).with("GitLab: Invalid repository path") + # expect(subject.exec(ssh_cmd)).to be_falsey + # end + # end + # end + # end + + # describe '#exec_cmd' do + # let(:shell) { GitlabShell.new(key_id) } + # let(:env) do + # { + # 'HOME' => ENV['HOME'], + # 'PATH' => ENV['PATH'], + # 'LD_LIBRARY_PATH' => ENV['LD_LIBRARY_PATH'], + # 'LANG' => ENV['LANG'], + # 'GL_ID' => key_id, + # 'GL_PROTOCOL' => 'ssh', + # 'GL_REPOSITORY' => gl_repository, + # 'GL_USERNAME' => 'testuser' + # } + # end + # let(:exec_options) { { unsetenv_others: true, chdir: ROOT_PATH } } + # before do + # Kernel.stub(:exec) + # shell.instance_variable_set(:@gl_repository, gl_repository) + # shell.instance_variable_set(:@username, gl_username) + # end + + # it "uses Kernel::exec method" do + # Kernel.should_receive(:exec).with(env, 1, 2, exec_options).once + # shell.send :exec_cmd, 1, 2 + # end + + # it "refuses to execute a lone non-array argument" do + # expect { shell.send :exec_cmd, 1 }.to raise_error(GitlabShell::DisallowedCommandError) + # end + + # it "allows one argument if it is an array" do + # Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once + # shell.send :exec_cmd, [1, 2] + # end + + # context "when specifying a git_tracing log file" do + # let(:git_trace_log_file) { '/tmp/git_trace_performance.log' } + + # before do + # GitlabConfig.any_instance.stub(git_trace_log_file: git_trace_log_file) + # shell + # end + + # it "uses GIT_TRACE_PERFORMANCE" do + # expected_hash = hash_including( + # 'GIT_TRACE' => git_trace_log_file, + # 'GIT_TRACE_PACKET' => git_trace_log_file, + # 'GIT_TRACE_PERFORMANCE' => git_trace_log_file + # ) + # Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once + + # shell.send :exec_cmd, [1, 2] + # end + + # context "when provides a relative path" do + # let(:git_trace_log_file) { 'git_trace_performance.log' } + + # it "does not uses GIT_TRACE*" do + # # If we try to use it we'll show a warning to the users + # expected_hash = hash_excluding( + # 'GIT_TRACE', 'GIT_TRACE_PACKET', 'GIT_TRACE_PERFORMANCE' + # ) + # Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once + + # shell.send :exec_cmd, [1, 2] + # end + + # it "writes an entry on the log" do + # message = 'git trace log path must be absolute, ignoring' + + # expect($logger).to receive(:warn). + # with(message, git_trace_log_file: git_trace_log_file) + + # Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once + # shell.send :exec_cmd, [1, 2] + # end + # end + + # context "when provides a file not writable" do + # before do + # expect(File).to receive(:open).with(git_trace_log_file, 'a').and_raise(Errno::EACCES) + # end + + # it "does not uses GIT_TRACE*" do + # # If we try to use it we'll show a warning to the users + # expected_hash = hash_excluding( + # 'GIT_TRACE', 'GIT_TRACE_PACKET', 'GIT_TRACE_PERFORMANCE' + # ) + # Kernel.should_receive(:exec).with(expected_hash, [1, 2], exec_options).once + + # shell.send :exec_cmd, [1, 2] + # end + + # it "writes an entry on the log" do + # message = 'Failed to open git trace log file' + # error = 'Permission denied' + + # expect($logger).to receive(:warn). + # with(message, git_trace_log_file: git_trace_log_file, error: error) + + # Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once + # shell.send :exec_cmd, [1, 2] + # end + # end + # end + # end + + # describe '#api' do + # let(:shell) { GitlabShell.new(key_id) } + # subject { shell.send(:api) } # FIXME: don't access private methods + + # it { should be_instance_of(GitlabNet) } + # end end |