summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsh McKenzie <ash@the-rebellion.net>2018-07-20 17:11:49 +1000
committerAsh McKenzie <ash@the-rebellion.net>2018-07-24 13:41:06 +1000
commit85c33cec0a0ab192fc013d41663b21def11a27ae (patch)
treea63190d5775b2d48c07f6598be74f3bdc4795802
parentba0b55feb3aad87d0343e5e39a8b106825cdda44 (diff)
downloadgitlab-shell-85c33cec0a0ab192fc013d41663b21def11a27ae.tar.gz
Add support for utilising CustomActionStatus
-rw-r--r--lib/gitlab_net.rb5
-rw-r--r--lib/gitlab_shell.rb54
-rw-r--r--lib/http_helper.rb5
-rw-r--r--spec/gitlab_net_spec.rb25
-rw-r--r--spec/gitlab_shell_spec.rb35
-rw-r--r--spec/vcr_cassettes/allowed-custom-action.yml46
-rw-r--r--spec/vcr_cassettes/allowed-pull.yml6
-rw-r--r--spec/vcr_cassettes/allowed-push.yml6
-rw-r--r--spec/vcr_cassettes/not-allowed-pull.yml46
9 files changed, 192 insertions, 36 deletions
diff --git a/lib/gitlab_net.rb b/lib/gitlab_net.rb
index 8e3e66e..34850cf 100644
--- a/lib/gitlab_net.rb
+++ b/lib/gitlab_net.rb
@@ -2,12 +2,11 @@ require 'net/http'
require 'openssl'
require 'json'
-require_relative 'gitlab_config'
require_relative 'gitlab_logger'
require_relative 'gitlab_access'
require_relative 'gitlab_lfs_authentication'
-require_relative 'httpunix'
require_relative 'http_helper'
+require_relative 'custom_action_status'
class GitlabNet
include HTTPHelper
@@ -37,6 +36,8 @@ class GitlabNet
case resp.code
when HTTP_SUCCESS
GitAccessStatus.create_from_json(resp.body)
+ when HTTP_MULTIPLE_CHOICES
+ CustomActionStatus.create_from_json(resp.body)
else
GitAccessStatus.new(false, 'API is not accessible',
gl_repository: nil,
diff --git a/lib/gitlab_shell.rb b/lib/gitlab_shell.rb
index 9644cf4..74af62a 100644
--- a/lib/gitlab_shell.rb
+++ b/lib/gitlab_shell.rb
@@ -17,6 +17,7 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
}.freeze
API_COMMANDS = %w(2fa_recovery_codes).freeze
GL_PROTOCOL = 'ssh'.freeze
+ HTTP_SUCCESS_CODES = %w{200 201}.freeze
attr_accessor :key_id, :gl_repository, :repo_name, :command, :git_access
attr_reader :repo_path
@@ -38,29 +39,29 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
args = Shellwords.shellwords(origin_cmd)
args = parse_cmd(args)
+ access_result = nil
if GIT_COMMANDS.include?(args.first)
- GitlabMetrics.measure('verify-access') { verify_access }
+ GitlabMetrics.measure('verify-access') { access_result = verify_access }
end
- process_cmd(args)
-
- true
+ process_cmd(access_result, 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)
-
$stderr.puts "GitLab: #{ex.message}"
false
rescue DisallowedCommandError
$logger.warn('Denied disallowed command', command: origin_cmd, user: log_username)
-
$stderr.puts "GitLab: Disallowed command"
false
rescue InvalidRepositoryPathError
$stderr.puts "GitLab: Invalid repository path"
false
+ rescue CustomActionStatus::UnsuccessfulError
+ $stderr.puts "GitLab: A custom action error has occurred"
+ false
end
protected
@@ -101,17 +102,13 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
end
def verify_access
- status = api.check_access(@git_access, nil, @repo_name, @key_id, '_any', GL_PROTOCOL)
+ result = api.check_access(@git_access, nil, @repo_name, @key_id, '_any', GL_PROTOCOL)
+ raise AccessDeniedError, result.message unless result.allowed?
- 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
+ result
end
- def process_cmd(args)
+ def process_cmd(access_result, args)
return send("api_#{@command}") if API_COMMANDS.include?(@command)
if @command == 'git-lfs-authenticate'
@@ -119,9 +116,23 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
$logger.info('Processing LFS authentication', user: log_username)
lfs_authenticate
end
- return
+ return true
end
+ case access_result
+ when GitAccessStatus
+ exec_cmd_for_gitaly(access_result, args)
+ when CustomActionStatus
+ exec_custom_action(access_result)
+ end
+ end
+
+ def exec_cmd_for_gitaly(access_result, args)
+ self.repo_path = access_result.repository_path
+ @gl_repository = access_result.gl_repository
+ @gitaly = access_result.gitaly
+ @username = access_result.gl_username
+
executable = @command
args = [repo_path]
@@ -147,6 +158,16 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
exec_cmd(executable, *args)
end
+ def exec_custom_action(access_result)
+ resp = access_result.execute(@key_id)
+
+ unless resp || HTTP_SUCCESS_CODES.include?(resp.code)
+ raise CustomActionStatus::UnsuccessfulError, resp.body
+ end
+
+ true
+ 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
@@ -183,7 +204,7 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
end
def api
- GitlabNet.new
+ GitlabNet.new # TODO: Can this be memoised?
end
def user
@@ -213,7 +234,6 @@ class GitlabShell # rubocop:disable Metrics/ClassLength
def lfs_authenticate
lfs_access = api.lfs_authenticate(@key_id, @repo_name)
-
return unless lfs_access
puts lfs_access.authentication_payload
diff --git a/lib/http_helper.rb b/lib/http_helper.rb
index 863a0ed..0396ef3 100644
--- a/lib/http_helper.rb
+++ b/lib/http_helper.rb
@@ -1,3 +1,6 @@
+require_relative 'gitlab_config'
+require_relative 'httpunix'
+
module HTTPHelper
READ_TIMEOUT = 300
HTTP_SUCCESS = '200'.freeze
@@ -115,7 +118,7 @@ module HTTPHelper
end
def secret_token
- @secret_token ||= File.read config.secret_file
+ @secret_token ||= File.read(config.secret_file)
end
def read_timeout
diff --git a/spec/gitlab_net_spec.rb b/spec/gitlab_net_spec.rb
index be2f4ba..92b5f82 100644
--- a/spec/gitlab_net_spec.rb
+++ b/spec/gitlab_net_spec.rb
@@ -266,13 +266,21 @@ describe GitlabNet, vcr: true do
describe '#check_access' do
context 'ssh key with access nil, to project' do
- it 'should allow pull access for host' do
- VCR.use_cassette("allowed-pull") do
+ it 'should allow push access for host' do
+ VCR.use_cassette("allowed-push") do
access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh')
+ expect(access).to be_instance_of(GitAccessStatus)
access.allowed?.should be_truthy
end
end
+ it 'should allow a custom action to be created' do
+ VCR.use_cassette("allowed-custom-action") do
+ access = gitlab_net.check_access('git-receive-pack', nil, project, key, changes, 'ssh')
+ expect(access).to be_instance_of(CustomActionStatus)
+ end
+ end
+
it 'adds the secret_token to the request' do
VCR.use_cassette("allowed-pull") do
Net::HTTP::Post.any_instance.should_receive(:set_form_data).with(hash_including(secret_token: secret))
@@ -280,12 +288,21 @@ describe GitlabNet, vcr: true do
end
end
- it 'should allow push access for host' do
- VCR.use_cassette("allowed-push") do
+ it 'should allow pull access for host' do
+ VCR.use_cassette("allowed-pull") do
access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh')
+ expect(access).to be_instance_of(GitAccessStatus)
access.allowed?.should be_truthy
end
end
+
+ it 'should not allow pull access for host' do
+ VCR.use_cassette("not-allowed-pull") do
+ access = gitlab_net.check_access('git-upload-pack', nil, project, key, changes, 'ssh')
+ expect(access).to be_instance_of(GitAccessStatus)
+ access.allowed?.should be_falsey
+ end
+ end
end
context 'ssh access has been disabled' do
diff --git a/spec/gitlab_shell_spec.rb b/spec/gitlab_shell_spec.rb
index af84b29..b3279fd 100644
--- a/spec/gitlab_shell_spec.rb
+++ b/spec/gitlab_shell_spec.rb
@@ -1,6 +1,7 @@
require_relative 'spec_helper'
require_relative '../lib/gitlab_shell'
-require_relative '../lib/gitlab_access_status'
+require_relative '../lib/git_access_status'
+require_relative '../lib/custom_action_status'
describe GitlabShell do
before do
@@ -153,7 +154,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should process the command" do
- subject.should_receive(:process_cmd).with(%W(git-upload-pack gitlab-ci.git))
+ subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git))
end
it "should execute the command" do
@@ -188,7 +189,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should process the command" do
- subject.should_receive(:process_cmd).with(%W(git-upload-pack gitlab-ci.git))
+ subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-pack gitlab-ci.git))
end
it "should execute the command" do
@@ -212,7 +213,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should process the command" do
- subject.should_receive(:process_cmd).with(%W(git-receive-pack gitlab-ci.git))
+ subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git))
end
it "should execute the command" do
@@ -234,7 +235,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should process the command" do
- subject.should_receive(:process_cmd).with(%W(git-receive-pack gitlab-ci.git))
+ subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-receive-pack gitlab-ci.git))
end
it "should execute the command" do
@@ -253,6 +254,28 @@ describe GitlabShell do
end
end
+ context 'custom action' do
+ let(:ssh_cmd) { "git-receive-pack gitlab-ci.git" }
+ let(:custom_action_access_result) { CustomActionStatus.create_from_json('{"status":true,"message":"Attempting to proxy to primary..","payload":{"api_endpoints":["fake/info_refs","fake/push"],"data":{"username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git"}}}') }
+ let(:http_success) { double(Net::HTTPOK, code: '200', body: 'OK') }
+ let(:http_error) { double(Net::HTTPInternalServerError, code: '500', body: 'Internal Server Error') }
+
+ before { api.stub(check_access: custom_action_access_result) }
+ after { subject.exec(ssh_cmd) }
+
+ it "should attempt execute the custom action" do
+ subject.should_receive(:exec_custom_action).with(custom_action_access_result)
+ end
+
+ it "should execute the custom action" do
+ custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_success)
+ end
+
+ it "should raise an exception when the custom action is unsuccessful" do
+ custom_action_access_result.should_receive(:execute).with(key_id).and_return(http_error)
+ end
+ end
+
shared_examples_for 'upload-archive' do |command|
let(:ssh_cmd) { "#{command} gitlab-ci.git" }
let(:exec_cmd_params) { ['git-upload-archive', repo_path] }
@@ -261,7 +284,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should process the command" do
- subject.should_receive(:process_cmd).with(%W(git-upload-archive gitlab-ci.git))
+ subject.should_receive(:exec_cmd_for_gitaly).with(instance_of(GitAccessStatus), %W(git-upload-archive gitlab-ci.git))
end
it "should execute the command" do
diff --git a/spec/vcr_cassettes/allowed-custom-action.yml b/spec/vcr_cassettes/allowed-custom-action.yml
new file mode 100644
index 0000000..bfd16b7
--- /dev/null
+++ b/spec/vcr_cassettes/allowed-custom-action.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: 300
+ message: Multiple Choices
+ 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:
+ - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f
+ X-Runtime:
+ - '0.289759'
+ body:
+ encoding: UTF-8
+ string: '{"status":true,"message":"Attempting to proxy to primary..","payload":{"api_endpoints":["fake/info_refs","fake/push"],"data":{"username":"user1","primary_repo":"http://localhost:3001/user1/repo1.git"}}}'
+ http_version:
+ recorded_at: Wed, 21 Jun 2017 10:44:52 GMT
+recorded_with: VCR 2.4.0
diff --git a/spec/vcr_cassettes/allowed-pull.yml b/spec/vcr_cassettes/allowed-pull.yml
index 1636fd5..b073476 100644
--- a/spec/vcr_cassettes/allowed-pull.yml
+++ b/spec/vcr_cassettes/allowed-pull.yml
@@ -5,7 +5,7 @@ http_interactions:
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
+ 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
@@ -35,9 +35,9 @@ http_interactions:
X-Frame-Options:
- SAMEORIGIN
X-Request-Id:
- - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f
+ - 67ab4954-19e6-42ce-aae6-55c8ae5a365e
X-Runtime:
- - '0.289759'
+ - '0.230871'
body:
encoding: UTF-8
string: '{"status":true,"gl_repository":"project-3","repository_path":"/Users/dzaporozhets/Projects/gitlab-development-kit/repositories/gitlab-org/gitlab-test.git"}'
diff --git a/spec/vcr_cassettes/allowed-push.yml b/spec/vcr_cassettes/allowed-push.yml
index b073476..1636fd5 100644
--- a/spec/vcr_cassettes/allowed-push.yml
+++ b/spec/vcr_cassettes/allowed-push.yml
@@ -5,7 +5,7 @@ http_interactions:
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
+ 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
@@ -35,9 +35,9 @@ http_interactions:
X-Frame-Options:
- SAMEORIGIN
X-Request-Id:
- - 67ab4954-19e6-42ce-aae6-55c8ae5a365e
+ - 8d4b8b06-fb6e-4f94-832f-72f8e0afad5f
X-Runtime:
- - '0.230871'
+ - '0.289759'
body:
encoding: UTF-8
string: '{"status":true,"gl_repository":"project-3","repository_path":"/Users/dzaporozhets/Projects/gitlab-development-kit/repositories/gitlab-org/gitlab-test.git"}'
diff --git a/spec/vcr_cassettes/not-allowed-pull.yml b/spec/vcr_cassettes/not-allowed-pull.yml
new file mode 100644
index 0000000..8876010
--- /dev/null
+++ b/spec/vcr_cassettes/not-allowed-pull.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,"gl_repository":"","repository_path":""}'
+ http_version:
+ recorded_at: Wed, 21 Jun 2017 10:44:52 GMT
+recorded_with: VCR 2.4.0