diff options
author | Ash McKenzie <amckenzie@gitlab.com> | 2018-07-26 19:06:20 +1000 |
---|---|---|
committer | Ash McKenzie <amckenzie@gitlab.com> | 2018-08-01 00:24:16 +1000 |
commit | ecba183b60eb0798ecf1736659ed7d0a995d0f01 (patch) | |
tree | 3606b2d25e914f69f6cc9aab6de7864331b49dbf | |
parent | 252a96d61f52d91486f92f980c2f0e4c7a1b9408 (diff) | |
download | gitlab-shell-ecba183b60eb0798ecf1736659ed7d0a995d0f01.tar.gz |
Utilise new Actions
* Move gitaly, git-lfs and 2FA logic out from gitlab_shell.rb
* Streamline parsing of origin_cmd in GitlabShell
* Utilise proper HTTP status codes sent from the API
* Also support 200 OK with status of true/false (ideally get rid of this)
* Use HTTP status constants
* Use attr_reader definitions (var over @var)
* Rspec deprecation fixes
22 files changed, 730 insertions, 763 deletions
diff --git a/lib/gitlab_access.rb b/lib/gitlab_access.rb index 8994789..4f3f2ad 100644 --- a/lib/gitlab_access.rb +++ b/lib/gitlab_access.rb @@ -20,12 +20,9 @@ class GitlabAccess end def exec - status = GitlabMetrics.measure('check-access:git-receive-pack') do - api.check_access('git-receive-pack', @gl_repository, @repo_path, @key_id, @changes, @protocol, env: ObjectDirsHelper.all_attributes.to_json) + GitlabMetrics.measure('check-access:git-receive-pack') do + api.check_access('git-receive-pack', gl_repository, repo_path, key_id, changes, protocol, env: ObjectDirsHelper.all_attributes.to_json) end - - raise AccessDeniedError, status.message unless status.allowed? - true rescue GitlabNet::ApiUnreachableError $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" diff --git a/lib/gitlab_net.rb b/lib/gitlab_net.rb index 191ecf5..3bc8f2d 100644 --- a/lib/gitlab_net.rb +++ b/lib/gitlab_net.rb @@ -1,15 +1,18 @@ require 'json' +require_relative 'errors' require_relative 'gitlab_logger' require_relative 'gitlab_access' require_relative 'gitlab_lfs_authentication' require_relative 'http_helper' +require_relative 'action' -class GitlabNet # rubocop:disable Metrics/ClassLength +class GitlabNet include HTTPHelper CHECK_TIMEOUT = 5 GL_PROTOCOL = 'ssh'.freeze + API_INACCESSIBLE_ERROR = 'API is not accessible'.freeze def check_access(cmd, gl_repository, repo, key_id, changes, protocol = GL_PROTOCOL, env: {}) changes = changes.join("\n") unless changes.is_a?(String) @@ -26,22 +29,15 @@ class GitlabNet # rubocop:disable Metrics/ClassLength resp = post("#{internal_api_endpoint}/allowed", params) - if resp.code == '200' - GitAccessStatus.create_from_json(resp.body) - else - GitAccessStatus.new(false, - 'API is not accessible', - gl_repository: nil, - gl_username: nil, - repository_path: nil, - gitaly: nil) - end + determine_action(key_id, resp) end def discover(key) key_id = key.gsub("key-", "") resp = get("#{internal_api_endpoint}/discover?key_id=#{key_id}") - JSON.parse(resp.body) rescue nil + JSON.parse(resp.body) + rescue JSON::ParserError, ApiUnreachableError + nil end def lfs_authenticate(key, repo) @@ -97,11 +93,7 @@ class GitlabNet # rubocop:disable Metrics/ClassLength end def post_receive(gl_repository, identifier, changes) - params = { - gl_repository: gl_repository, - identifier: identifier, - changes: changes - } + params = { gl_repository: gl_repository, identifier: identifier, changes: changes } resp = post("#{internal_api_endpoint}/post_receive", params) raise NotFound if resp.code == HTTP_NOT_FOUND @@ -120,4 +112,25 @@ class GitlabNet # rubocop:disable Metrics/ClassLength def sanitize_path(repo) repo.delete("'") end + + def determine_action(key_id, resp) + json = JSON.parse(resp.body) + message = json['message'] + + case resp.code + when HTTP_SUCCESS + # TODO: This raise can be removed once internal API can respond with correct + # HTTP status codes, instead of relying upon parsing the body and + # accessing the 'status' key. + raise AccessDeniedError, message unless json['status'] + + Action::Gitaly.create_from_json(key_id, json) + when HTTP_UNAUTHORIZED, HTTP_NOT_FOUND + raise AccessDeniedError, message + else + raise UnknownError, "#{API_INACCESSIBLE_ERROR}: #{message}" + end + rescue JSON::ParserError + raise UnknownError, API_INACCESSIBLE_ERROR + end end diff --git a/lib/gitlab_shell.rb b/lib/gitlab_shell.rb index aaa0570..5c51bc1 100644 --- a/lib/gitlab_shell.rb +++ b/lib/gitlab_shell.rb @@ -3,18 +3,11 @@ require 'pathname' require_relative 'gitlab_net' require_relative 'gitlab_metrics' +require_relative 'user' -class GitlabShell # rubocop:disable Metrics/ClassLength +class GitlabShell + API_2FA_RECOVERY_CODES_COMMAND = '2fa_recovery_codes'.freeze - GITALY_MIGRATED_COMMANDS = { - 'git-upload-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-pack'), - 'git-upload-archive' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-archive'), - 'git-receive-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-receive-pack') - }.freeze - API_COMMANDS = %w(2fa_recovery_codes).freeze - - attr_accessor :key_id, :gl_repository, :repo_name, :command, :git_access - attr_reader :repo_path GIT_UPLOAD_PACK_COMMAND = 'git-upload-pack'.freeze GIT_RECEIVE_PACK_COMMAND = 'git-receive-pack'.freeze GIT_UPLOAD_ARCHIVE_COMMAND = 'git-upload-archive'.freeze @@ -33,29 +26,23 @@ class GitlabShell # rubocop:disable Metrics/ClassLength # 'evil command'. def exec(origin_cmd) if !origin_cmd || origin_cmd.empty? - puts "Welcome to GitLab, #{username}!" + puts "Welcome to GitLab, #{user.username}!" return true end - args = Shellwords.shellwords(origin_cmd) - args = parse_cmd(args) - - if GIT_COMMANDS.include?(args.first) - GitlabMetrics.measure('verify-access') { verify_access } - end + command, git_access_command, repo_name, args = parse_cmd(origin_cmd) + action = determine_action(command, git_access_command, repo_name) - process_cmd(args) - - true + action.execute(command, args) rescue GitlabNet::ApiUnreachableError $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" false - rescue AccessDeniedError => ex - $logger.warn('Access denied', command: origin_cmd, user: log_username) + rescue AccessDeniedError, UnknownError => ex + $logger.warn('Access denied', command: origin_cmd, user: user.log_username) $stderr.puts "GitLab: #{ex.message}" false rescue DisallowedCommandError - $logger.warn('Denied disallowed command', command: origin_cmd, user: log_username) + $logger.warn('Denied disallowed command', command: origin_cmd, user: user.log_username) $stderr.puts 'GitLab: Disallowed command' false rescue InvalidRepositoryPathError @@ -65,217 +52,67 @@ class GitlabShell # rubocop:disable Metrics/ClassLength private + attr_reader :config, :key_id + + def user + @user ||= User.new(key_id, audit_usernames: config.audit_usernames) + end + + def parse_cmd(cmd) + args = Shellwords.shellwords(cmd) - def parse_cmd(args) # Handle Git for Windows 2.14 using "git upload-pack" instead of git-upload-pack if args.length == 3 && args.first == 'git' - @command = "git-#{args[1]}" - args = [@command, args.last] + command = "git-#{args[1]}" + args = [command, args.last] else - @command = args.first + command = args.first end - @git_access = @command + git_access_command = command - return args if API_COMMANDS.include?(@command) + return [command, git_access_command, nil, args] if command == API_2FA_RECOVERY_CODES_COMMAND - raise DisallowedCommandError unless GIT_COMMANDS.include?(@command) + raise DisallowedCommandError unless GIT_COMMANDS.include?(command) - case @command + case command when 'git-lfs-authenticate' raise DisallowedCommandError unless args.count >= 2 - @repo_name = args[1] - case args[2] - when 'download' - @git_access = 'git-upload-pack' - when 'upload' - @git_access = 'git-receive-pack' - else - raise DisallowedCommandError - end + repo_name = args[1] + git_access_command = case args[2] + when 'download' + GIT_UPLOAD_PACK_COMMAND + when 'upload' + GIT_RECEIVE_PACK_COMMAND + else + raise DisallowedCommandError + end else raise DisallowedCommandError unless args.count == 2 - @repo_name = args.last + repo_name = args.last end - args + [command, git_access_command, repo_name, args] end - def verify_access - status = api.check_access(@git_access, nil, @repo_name, @key_id, '_any', GitlabNet::GL_PROTOCOL) - - raise AccessDeniedError, status.message unless status.allowed? - - self.repo_path = status.repository_path - @gl_repository = status.gl_repository - @gitaly = status.gitaly - @username = status.gl_username - end + def determine_action(command, git_access_command, repo_name) + return Action::API2FARecovery.new(key_id) if command == API_2FA_RECOVERY_CODES_COMMAND - def process_cmd(args) - return send("api_#{@command}") if API_COMMANDS.include?(@command) + GitlabMetrics.measure('verify-access') do + # GitlatNet#check_access will raise exception in the event of a problem + initial_action = api.check_access(git_access_command, nil, + repo_name, key_id, '_any') - if @command == 'git-lfs-authenticate' - GitlabMetrics.measure('lfs-authenticate') do - $logger.info('Processing LFS authentication', user: log_username) - lfs_authenticate + case command + when GIT_LFS_AUTHENTICATE_COMMAND + Action::GitLFSAuthenticate.new(key_id, repo_name) + else + initial_action end - return end - - executable = @command - args = [repo_path] - - if GITALY_MIGRATED_COMMANDS.key?(executable) && @gitaly - executable = GITALY_MIGRATED_COMMANDS[executable] - - gitaly_address = @gitaly['address'] - - # The entire gitaly_request hash should be built in gitlab-ce and passed - # on as-is. For now we build a fake one on the spot. - gitaly_request = { - 'repository' => @gitaly['repository'], - 'gl_repository' => @gl_repository, - 'gl_id' => @key_id, - 'gl_username' => @username - } - - args = [gitaly_address, JSON.dump(gitaly_request)] - end - - args_string = [File.basename(executable), *args].join(' ') - $logger.info('executing git command', command: args_string, user: log_username) - exec_cmd(executable, *args) - end - - # This method is not covered by Rspec because it ends the current Ruby process. - def exec_cmd(*args) - # If you want to call a command without arguments, use - # exec_cmd(['my_command', 'my_command']) . Otherwise use - # exec_cmd('my_command', 'my_argument', ...). - if args.count == 1 && !args.first.is_a?(Array) - raise DisallowedCommandError - end - - env = { - 'HOME' => ENV['HOME'], - 'PATH' => ENV['PATH'], - 'LD_LIBRARY_PATH' => ENV['LD_LIBRARY_PATH'], - 'LANG' => ENV['LANG'], - 'GL_ID' => @key_id, - 'GL_PROTOCOL' => GitlabNet::GL_PROTOCOL, - 'GL_REPOSITORY' => @gl_repository, - 'GL_USERNAME' => @username - } - if @gitaly && @gitaly.include?('token') - env['GITALY_TOKEN'] = @gitaly['token'] - end - - if git_trace_available? - env.merge!( - 'GIT_TRACE' => @config.git_trace_log_file, - 'GIT_TRACE_PACKET' => @config.git_trace_log_file, - 'GIT_TRACE_PERFORMANCE' => @config.git_trace_log_file - ) - end - - # We use 'chdir: ROOT_PATH' to let the next executable know where config.yml is. - Kernel.exec(env, *args, unsetenv_others: true, chdir: ROOT_PATH) end def api GitlabNet.new end - - def user - return @user if defined?(@user) - - begin - @user = api.discover(@key_id) - rescue GitlabNet::ApiUnreachableError - @user = nil - end - end - - def username_from_discover - return nil unless user && user['username'] - - "@#{user['username']}" - end - - def username - @username ||= username_from_discover || 'Anonymous' - end - - # User identifier to be used in log messages. - def log_username - @config.audit_usernames ? username : "user with key #{@key_id}" - end - - def lfs_authenticate - lfs_access = api.lfs_authenticate(@key_id, @repo_name) - - return unless lfs_access - - puts lfs_access.authentication_payload - end - - private - - def continue?(question) - puts "#{question} (yes/no)" - STDOUT.flush # Make sure the question gets output before we wait for input - continue = STDIN.gets.chomp - puts '' # Add a buffer in the output - continue == 'yes' - end - - def api_2fa_recovery_codes - continue = continue?( - "Are you sure you want to generate new two-factor recovery codes?\n" \ - "Any existing recovery codes you saved will be invalidated." - ) - - unless continue - puts 'New recovery codes have *not* been generated. Existing codes will remain valid.' - return - end - - resp = api.two_factor_recovery_codes(key_id) - if resp['success'] - codes = resp['recovery_codes'].join("\n") - puts "Your two-factor authentication recovery codes are:\n\n" \ - "#{codes}\n\n" \ - "During sign in, use one of the codes above when prompted for\n" \ - "your two-factor code. Then, visit your Profile Settings and add\n" \ - "a new device so you do not lose access to your account again." - else - puts "An error occurred while trying to generate new recovery codes.\n" \ - "#{resp['message']}" - end - end - - def git_trace_available? - return false unless @config.git_trace_log_file - - if Pathname(@config.git_trace_log_file).relative? - $logger.warn('git trace log path must be absolute, ignoring', git_trace_log_file: @config.git_trace_log_file) - return false - end - - begin - File.open(@config.git_trace_log_file, 'a') { nil } - return true - rescue => ex - $logger.warn('Failed to open git trace log file', git_trace_log_file: @config.git_trace_log_file, error: ex.to_s) - return false - end - end - - def repo_path=(repo_path) - raise ArgumentError, "Repository path not provided. Please make sure you're using GitLab v8.10 or later." unless repo_path - raise InvalidRepositoryPathError if File.absolute_path(repo_path) != repo_path - - @repo_path = repo_path - end end diff --git a/spec/gitlab_access_spec.rb b/spec/gitlab_access_spec.rb index bec7f25..e529a66 100644 --- a/spec/gitlab_access_spec.rb +++ b/spec/gitlab_access_spec.rb @@ -7,12 +7,7 @@ describe GitlabAccess do let(:repo_path) { File.join(repository_path, repo_name) + ".git" } let(:api) do double(GitlabNet).tap do |api| - api.stub(check_access: GitAccessStatus.new(true, - 'ok', - gl_repository: 'project-1', - gl_username: 'testuser', - repository_path: '/home/git/repositories', - gitaly: nil)) + allow(api).to receive(:check_access).and_return(Action::Gitaly.new('key-1', 'project-1', 'testuser', '/home/git/repositories', nil)) end end subject do @@ -26,12 +21,6 @@ describe GitlabAccess do allow_any_instance_of(GitlabConfig).to receive(:repos_path).and_return(repository_path) end - describe :initialize do - it { expect(subject.send(:repo_path)).to eql repo_path } # FIXME: don't access private instance variables - it { expect(subject.send(:changes)).to eql ['wow'] } # FIXME: don't access private instance variables - it { expect(subject.send(:protocol)).to eql 'ssh' } # FIXME: don't access private instance variables - end - describe "#exec" do context "access is granted" do @@ -41,16 +30,8 @@ describe GitlabAccess do end context "access is denied" do - before do - api.stub(check_access: GitAccessStatus.new( - false, - 'denied', - gl_repository: nil, - gl_username: nil, - repository_path: nil, - gitaly: nil - )) + allow(api).to receive(:check_access).and_raise(AccessDeniedError) end it "returns false" do diff --git a/spec/gitlab_net_spec.rb b/spec/gitlab_net_spec.rb index 291e895..a2760aa 100644 --- a/spec/gitlab_net_spec.rb +++ b/spec/gitlab_net_spec.rb @@ -57,7 +57,7 @@ describe GitlabNet, vcr: true do it "raises an exception if the connection fails" do VCR.use_cassette("discover-ok") do allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(StandardError) - expect { gitlab_net.discover(key) }.to raise_error(GitlabNet::ApiUnreachableError) + expect(gitlab_net.discover(key)).to be_nil end end end @@ -263,11 +263,33 @@ describe GitlabNet, vcr: true do end describe '#check_access' do + context 'something is wrong with the API response' do + context 'but response is JSON parsable' do + it 'raises an UnknownError exception' do + VCR.use_cassette('failed-push') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + end.to raise_error(UnknownError, 'API is not accessible: An internal server error occurred') + end + end + end + + context 'but response is not JSON parsable' do + it 'raises an UnknownError exception' do + VCR.use_cassette('failed-push-unparsable') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + end.to raise_error(UnknownError, 'API is not accessible') + end + end + end + end + context 'ssh key with access nil, to project' do - it 'should allow pull access for host' do - VCR.use_cassette("allowed-pull") do - access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') - access.allowed?.should be_truthy + it 'should allow push access for host' do + VCR.use_cassette('allowed-push') do + action = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + expect(action).to be_instance_of(Action::Gitaly) end end @@ -278,75 +300,120 @@ describe GitlabNet, vcr: true do end end - it 'should allow push access for host' do - VCR.use_cassette("allowed-push") do - access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh') - access.allowed?.should be_truthy + it 'should allow pull access for host' do + VCR.use_cassette("allowed-pull") do + action = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh') + expect(action).to be_instance_of(Action::Gitaly) end end end context 'ssh access has been disabled' do it 'should deny pull access for host' do + VCR.use_cassette('ssh-pull-disabled-old') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') + end + VCR.use_cassette('ssh-pull-disabled') do - access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh') - access.allowed?.should be_falsey - access.message.should eq 'Git access over SSH is not allowed' + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') end end it 'should deny push access for host' do + VCR.use_cassette('ssh-push-disabled-old') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') + end + VCR.use_cassette('ssh-push-disabled') do - access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') - access.allowed?.should be_falsey - access.message.should eq 'Git access over SSH is not allowed' + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') end end end context 'http access has been disabled' do it 'should deny pull access for host' do + VCR.use_cassette('http-pull-disabled-old') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Pulling over HTTP is not allowed.') + end + VCR.use_cassette('http-pull-disabled') do - access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') - access.allowed?.should be_falsey - access.message.should eq 'Pulling over HTTP is not allowed.' + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Pulling over HTTP is not allowed.') end end it 'should deny push access for host' do - VCR.use_cassette("http-push-disabled") do - access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'http') - access.allowed?.should be_falsey - access.message.should eq 'Pushing over HTTP is not allowed.' + VCR.use_cassette('http-push-disabled-old') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Pushing over HTTP is not allowed.') + end + + VCR.use_cassette('http-push-disabled') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'http') + end.to raise_error(AccessDeniedError, 'Pushing over HTTP is not allowed.') end end end context 'ssh key without access to project' do it 'should deny pull access for host' do - VCR.use_cassette("ssh-pull-project-denied") do - access = gitlab_net.check_access('git-receive-pack', nil, project, key2, changes, 'ssh') - access.allowed?.should be_falsey + VCR.use_cassette('ssh-pull-project-denied-old') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key2, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') + end + + VCR.use_cassette('ssh-pull-project-denied') do + expect do + gitlab_net.check_access('git-receive-pack', nil, project, key2, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') end end it 'should deny push access for host' do - VCR.use_cassette("ssh-push-project-denied") do - access = gitlab_net.check_access('git-upload-pack', nil, project, key2, changes, 'ssh') - access.allowed?.should be_falsey + VCR.use_cassette('ssh-push-project-denied-old') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key2, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') + end + + VCR.use_cassette('ssh-push-project-denied') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, key2, changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') end end it 'should deny push access for host (with user)' do - VCR.use_cassette("ssh-push-project-denied-with-user") do - access = gitlab_net.check_access('git-upload-pack', nil, project, 'user-2', changes, 'ssh') - access.allowed?.should be_falsey + VCR.use_cassette('ssh-push-project-denied-with-user-old') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, 'user-2', changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') + end + + VCR.use_cassette('ssh-push-project-denied-with-user') do + expect do + gitlab_net.check_access('git-upload-pack', nil, project, 'user-2', changes, 'ssh') + end.to raise_error(AccessDeniedError, 'Git access over SSH is not allowed') end end end it "raises an exception if the connection fails" do - Net::HTTP.any_instance.stub(:request).and_raise(StandardError) + allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(StandardError) expect { gitlab_net.check_access('git-upload-pack', nil, project, 'user-1', changes, 'ssh') }.to raise_error(GitlabNet::ApiUnreachableError) diff --git a/spec/gitlab_shell_spec.rb b/spec/gitlab_shell_spec.rb index af84b29..b7c0746 100644 --- a/spec/gitlab_shell_spec.rb +++ b/spec/gitlab_shell_spec.rb @@ -1,6 +1,6 @@ require_relative 'spec_helper' require_relative '../lib/gitlab_shell' -require_relative '../lib/gitlab_access_status' +require_relative '../lib/action' describe GitlabShell do before do @@ -8,544 +8,202 @@ describe GitlabShell do FileUtils.mkdir_p(tmp_repos_path) end - after do - FileUtils.rm_rf(tmp_repos_path) - end + after { FileUtils.rm_rf(tmp_repos_path) } - 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 - end + subject { described_class.new(key_id) } let(:key_id) { "key-#{rand(100) + 100}" } - let(:ssh_cmd) { nil } let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') } - let(:repo_name) { 'gitlab-ci.git' } let(:repo_path) { File.join(tmp_repos_path, repo_name) } let(:gl_repository) { 'project-1' } let(:gl_username) { 'testuser' } - before do - GitlabConfig.any_instance.stub(audit_usernames: false) - end + let(:api) { double(GitlabNet) } - describe :initialize do - let(:ssh_cmd) { 'git-receive-pack' } + 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(:api_2fa_recovery_action) { Action::API2FARecovery.new(key_id) } + let(:git_lfs_authenticate_action) { Action::GitLFSAuthenticate.new(key_id, repo_name) } - its(:key_id) { should == key_id } + before do + allow(GitlabNet).to receive(:new).and_return(api) + allow(api).to receive(:discover).with(key_id).and_return('username' => gl_username) 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.command).to eq('2fa_recovery_codes') - end - - it 'does not set repo name' do - expect(subject.repo_name).to be_nil - 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) } - + describe '#exec' do + context "when we don't have a valid user" do before do - subject.send :parse_cmd, ssh_args + allow(api).to receive(:discover).with(key_id).and_return(nil) 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 - 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(:process_cmd).with(%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')) + it 'prints Welcome.. and returns true' do + expect { + expect(subject.exec(nil)).to be_truthy + }.to output("Welcome to GitLab, Anonymous!\n").to_stdout 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(:process_cmd).with(%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) + context 'when we have a valid user' do + context 'when origin_cmd is nil' do + it 'prints Welcome.. and returns true' do + expect { + expect(subject.exec(nil)).to be_truthy + }.to output("Welcome to GitLab, @testuser!\n").to_stdout + end 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 { + expect(subject.exec('')).to be_truthy + }.to output("Welcome to GitLab, @testuser!\n").to_stdout + end 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(:process_cmd).with(%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 { + expect(subject.exec("git-invalid-command #{repo_name}")).to be_falsey + }.to output("GitLab: Disallowed command\n").to_stderr 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(:process_cmd).with(%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 { + expect(subject.exec('git-upload-pack')).to be_falsey + }.to output("GitLab: Disallowed command\n").to_stderr 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(:process_cmd).with(%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) + context 'when origin_cmd is git-lfs-authenticate' do + context 'but incomplete' do + it 'prints a message to stderr and returns false' do + expect { + expect(subject.exec('git-lfs-authenticate')).to be_falsey + }.to output("GitLab: Disallowed command\n").to_stderr + end 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 'but invalid' do + it 'prints a message to stderr and returns false' do + expect { + expect(subject.exec("git-lfs-authenticate #{repo_name} invalid")).to be_falsey + }.to output("GitLab: Disallowed command\n").to_stderr + end 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 'when origin_cmd is 2fa_recovery_codes' do + let(:origin_cmd) { '2fa_recovery_codes' } + let(:git_access) { '2fa_recovery_codes' } - context 'gitaly-upload-archive' do before do - api.stub(check_access: gitaly_check_access) + expect(Action::API2FARecovery).to receive(:new).with(key_id).and_return(api_2fa_recovery_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 + it 'returns true' do + expect(api_2fa_recovery_action).to receive(:execute).with('2fa_recovery_codes', %w{ 2fa_recovery_codes }).and_return(true) + expect(subject.exec(origin_cmd)).to be_truthy 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 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 - 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: Sorry, access denied') + 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 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 - 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: Failed to authorize your Git request: internal API unreachable') + 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(:origin_cmd) { 'git-upload-pack' } + 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("#{origin_cmd} #{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("#{origin_cmd} #{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) } - - 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 + context "but we're using an old git version for Windows 2.14" do + 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 #NOTE: 'git upload-pack' vs. 'git-upload-pack' + end 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.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' } + context 'when origin_cmd is git-lfs-authenticate' do + let(:origin_cmd) { 'git-lfs-authenticate' } + # let(:fake_payload) { 'FAKE PAYLOAD' } + let(:lfs_access) { double(GitlabLfsAuthentication, authentication_payload: fake_payload)} - 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(Action::GitLFSAuthenticate).to receive(:new).with(key_id, repo_name).and_return(git_lfs_authenticate_action) 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(git_lfs_authenticate_action).to receive(:execute).with('git-lfs-authenticate', %w{ git-lfs-authenticate gitlab-ci.git upload }).and_return(true) + # expect($stdout).to receive(:puts).with(fake_payload) + expect(subject.exec("#{origin_cmd} #{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' + context 'download' do + let(:git_access) { 'git-upload-pack' } - expect($logger).to receive(:warn). - with(message, git_trace_log_file: git_trace_log_file, error: error) + it 'returns true' do + expect(git_lfs_authenticate_action).to receive(:execute).with('git-lfs-authenticate', %w{ git-lfs-authenticate gitlab-ci.git download }).and_return(true) + # expect($stdout).to receive(:puts).with(fake_payload) + expect(subject.exec("#{origin_cmd} #{repo_name} download")).to be_truthy + end - Kernel.should_receive(:exec).with(env, [1, 2], exec_options).once - shell.send :exec_cmd, [1, 2] + context 'for old git-lfs clients' do + it 'returns true' do + expect(git_lfs_authenticate_action).to receive(:execute).with('git-lfs-authenticate', %w{ git-lfs-authenticate gitlab-ci.git download long_oid }).and_return(true) + # expect($stdout).to receive(:puts).with(fake_payload) + expect(subject.exec("#{origin_cmd} #{repo_name} download long_oid")).to be_truthy + end + end end end end end - - describe :api do - let(:shell) { GitlabShell.new(key_id) } - subject { shell.send :api } - - it { should be_a(GitlabNet) } - end end diff --git a/spec/vcr_cassettes/failed-push-unparsable.yml b/spec/vcr_cassettes/failed-push-unparsable.yml new file mode 100644 index 0000000..fbc09ec --- /dev/null +++ b/spec/vcr_cassettes/failed-push-unparsable.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 500 + message: Internal Server Error + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 67ab4954-19e6-42ce-aae6-55c8ae5a365e + X-Runtime: + - '0.230871' + body: + encoding: UTF-8 + string: '""' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/failed-push.yml b/spec/vcr_cassettes/failed-push.yml new file mode 100644 index 0000000..334aabd --- /dev/null +++ b/spec/vcr_cassettes/failed-push.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 500 + message: Internal Server Error + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '155' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:44:52 GMT + Etag: + - W/"45654cae433b5a9c5fbba1d45d382e52" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 67ab4954-19e6-42ce-aae6-55c8ae5a365e + X-Runtime: + - '0.230871' + body: + encoding: UTF-8 + string: '{"status":false,"message":"An internal server error occurred"}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:44:52 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/http-pull-disabled-old.yml b/spec/vcr_cassettes/http-pull-disabled-old.yml new file mode 100644 index 0000000..23ef3e5 --- /dev/null +++ b/spec/vcr_cassettes/http-pull-disabled-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=http&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '62' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:32:01 GMT + Etag: + - W/"71e09fcf8a60a03cd1acc22806386ead" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 70bdecc9-0078-4a4b-aa6b-cac1b2578886 + X-Runtime: + - '0.324202' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Pulling over HTTP is not allowed."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:32:01 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/http-pull-disabled.yml b/spec/vcr_cassettes/http-pull-disabled.yml index 23ef3e5..34cf634 100644 --- a/spec/vcr_cassettes/http-pull-disabled.yml +++ b/spec/vcr_cassettes/http-pull-disabled.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/http-push-disabled-old.yml b/spec/vcr_cassettes/http-push-disabled-old.yml new file mode 100644 index 0000000..676e5b8 --- /dev/null +++ b/spec/vcr_cassettes/http-push-disabled-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=http&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '62' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 10:32:01 GMT + Etag: + - W/"7f14e23ac07cc8b0a53c567fcf9432fd" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 573f3584-87c6-41cb-a5bf-5e7ee76d4250 + X-Runtime: + - '0.266135' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Pushing over HTTP is not allowed."}' + http_version: + recorded_at: Wed, 21 Jun 2017 10:32:01 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/http-push-disabled.yml b/spec/vcr_cassettes/http-push-disabled.yml index 676e5b8..e7e185e 100644 --- a/spec/vcr_cassettes/http-push-disabled.yml +++ b/spec/vcr_cassettes/http-push-disabled.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/ssh-pull-disabled-old.yml b/spec/vcr_cassettes/ssh-pull-disabled-old.yml new file mode 100644 index 0000000..55ce261 --- /dev/null +++ b/spec/vcr_cassettes/ssh-pull-disabled-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:23:57 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 096ae253-c6fe-4360-b4d4-48f4b5435ca6 + X-Runtime: + - '6.377187' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:23:57 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/ssh-pull-disabled.yml b/spec/vcr_cassettes/ssh-pull-disabled.yml index 55ce261..92fc36a 100644 --- a/spec/vcr_cassettes/ssh-pull-disabled.yml +++ b/spec/vcr_cassettes/ssh-pull-disabled.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/ssh-pull-project-denied-old.yml b/spec/vcr_cassettes/ssh-pull-project-denied-old.yml new file mode 100644 index 0000000..c16e608 --- /dev/null +++ b/spec/vcr_cassettes/ssh-pull-project-denied-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - c843a5a3-fc08-46eb-aa45-caceae515638 + X-Runtime: + - '7.359835' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/ssh-pull-project-denied.yml b/spec/vcr_cassettes/ssh-pull-project-denied.yml index c16e608..61a71db 100644 --- a/spec/vcr_cassettes/ssh-pull-project-denied.yml +++ b/spec/vcr_cassettes/ssh-pull-project-denied.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/ssh-push-disabled-old.yml b/spec/vcr_cassettes/ssh-push-disabled-old.yml new file mode 100644 index 0000000..c061791 --- /dev/null +++ b/spec/vcr_cassettes/ssh-push-disabled-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-receive-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=1&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:23:57 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 93620e06-fda9-4be5-855e-300f5d62fa3c + X-Runtime: + - '0.207159' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:23:57 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/ssh-push-disabled.yml b/spec/vcr_cassettes/ssh-push-disabled.yml index c061791..5ca2642 100644 --- a/spec/vcr_cassettes/ssh-push-disabled.yml +++ b/spec/vcr_cassettes/ssh-push-disabled.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/ssh-push-project-denied-old.yml b/spec/vcr_cassettes/ssh-push-project-denied-old.yml new file mode 100644 index 0000000..5107d15 --- /dev/null +++ b/spec/vcr_cassettes/ssh-push-project-denied-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&key_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:04 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 8ce54f29-9ed0-46e5-aedb-37edaa3d52da + X-Runtime: + - '0.228256' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:04 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/ssh-push-project-denied-with-user-old.yml b/spec/vcr_cassettes/ssh-push-project-denied-with-user-old.yml new file mode 100644 index 0000000..b461b5b --- /dev/null +++ b/spec/vcr_cassettes/ssh-push-project-denied-with-user-old.yml @@ -0,0 +1,46 @@ +--- +http_interactions: +- request: + method: post + uri: http://localhost:3000/api/v4/internal/allowed + body: + encoding: US-ASCII + string: action=git-upload-pack&changes=0000000000000000000000000000000000000000+92d0970eefd7acb6d548878925ce2208cfe2d2ec+refs%2Fheads%2Fbranch4&gl_repository&project=gitlab-org%2Fgitlab-test.git&protocol=ssh&env=%7B%7D&user_id=2&secret_token=0a3938d9d95d807e94d937af3a4fbbea%0A + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Content-Type: + - application/x-www-form-urlencoded + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0, private, must-revalidate + Content-Length: + - '63' + Content-Type: + - application/json + Date: + - Wed, 21 Jun 2017 12:24:05 GMT + Etag: + - W/"76a32010244f80700d5e1ba8a55d094c" + Vary: + - Origin + X-Frame-Options: + - SAMEORIGIN + X-Request-Id: + - 3b242d73-d860-48ac-8fef-80e2d0d3daca + X-Runtime: + - '0.342469' + body: + encoding: UTF-8 + string: '{"status":false,"message":"Git access over SSH is not allowed"}' + http_version: + recorded_at: Wed, 21 Jun 2017 12:24:05 GMT +recorded_with: VCR 2.4.0 diff --git a/spec/vcr_cassettes/ssh-push-project-denied-with-user.yml b/spec/vcr_cassettes/ssh-push-project-denied-with-user.yml index b461b5b..01be21b 100644 --- a/spec/vcr_cassettes/ssh-push-project-denied-with-user.yml +++ b/spec/vcr_cassettes/ssh-push-project-denied-with-user.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate diff --git a/spec/vcr_cassettes/ssh-push-project-denied.yml b/spec/vcr_cassettes/ssh-push-project-denied.yml index 5107d15..b23dd8d 100644 --- a/spec/vcr_cassettes/ssh-push-project-denied.yml +++ b/spec/vcr_cassettes/ssh-push-project-denied.yml @@ -17,8 +17,8 @@ http_interactions: - application/x-www-form-urlencoded response: status: - code: 200 - message: OK + code: 401 + message: Unauthorized headers: Cache-Control: - max-age=0, private, must-revalidate |