Commit ecba183b authored by Ash McKenzie's avatar Ash McKenzie

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
parent 252a96d6
......@@ -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"
......
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
......@@ -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
......@@ -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
......
......@@ -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)
......
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
---
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
---
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
---
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
......@@ -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
......
---
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
......@@ -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
......
---
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
......@@ -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
......
---
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
......@@ -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
......
---
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
......@@ -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
......
---
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
---
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
......@@ -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
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment