Commit ee5602f0 authored by Ash McKenzie's avatar Ash McKenzie

Allow GeoGitAccess to perform custom action

parent d67a2497
......@@ -3,9 +3,19 @@ module EE
module GeoGitAccess
include ::Gitlab::ConfigHelper
include ::EE::GitlabRoutingHelper
include GrapePathHelpers::NamedRouteMatcher
extend ::Gitlab::Utils::Override
GEO_SERVER_DOCS_URL = 'https://docs.gitlab.com/ee/administration/geo/replication/using_a_geo_server.html'.freeze
override :check_custom_action
def check_custom_action(cmd)
custom_action = custom_action_for(cmd)
return custom_action if custom_action
super
end
protected
def project_or_wiki
......@@ -14,6 +24,27 @@ module EE
private
def custom_action_for?(cmd)
return unless receive_pack?(cmd)
return unless ::Gitlab::Database.read_only?
::Gitlab::Geo.secondary_with_primary?
end
def custom_action_for(cmd)
return unless custom_action_for?(cmd)
payload = {
'action' => 'geo_proxy_to_primary',
'data' => {
'api_endpoints' => [api_v4_geo_proxy_git_push_ssh_info_refs_path, api_v4_geo_proxy_git_push_ssh_push_path],
'primary_repo' => geo_primary_http_url_to_repo(project_or_wiki)
}
}
::Gitlab::GitAccessResult::CustomAction.new(payload, 'Attempting to proxy to primary.')
end
def push_to_read_only_message
message = super
......
......@@ -18,25 +18,9 @@ describe Gitlab::GitAccess do
allow(Gitlab::Database).to receive(:read_only?) { true }
end
it 'denies push access' do
project.add_maintainer(user)
let(:primary_repo_url) { "https://localhost:3000/gitlab/#{project.full_path}.git" }
expect { push_changes }.to raise_unauthorized("You can't push code to a read-only GitLab instance.")
end
it 'denies push access with primary present' do
error_message = "You can't push code to a read-only GitLab instance."\
"\nPlease use the primary node URL instead: https://localhost:3000/gitlab/#{project.full_path}.git.
For more information: #{EE::Gitlab::GeoGitAccess::GEO_SERVER_DOCS_URL}"
primary_node = create(:geo_node, :primary, url: 'https://localhost:3000/gitlab')
allow(Gitlab::Geo).to receive(:primary).and_return(primary_node)
allow(Gitlab::Geo).to receive(:secondary_with_primary?).and_return(true)
project.add_maintainer(user)
expect { push_changes }.to raise_unauthorized(error_message)
end
it_behaves_like 'a read-only GitLab instance'
end
describe "push_rule_check" do
......
require 'spec_helper'
describe Gitlab::GitAccessWiki do
let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] }
let(:authentication_abilities) { %i[read_project download_code push_code] }
let(:redirected_path) { nil }
let(:authentication_abilities) do
[
:read_project,
:download_code,
:push_code
]
end
let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
context "when in a read-only GitLab instance" do
subject { access.check('git-receive-pack', changes) }
......@@ -22,26 +17,9 @@ describe Gitlab::GitAccessWiki do
allow(Gitlab::Database).to receive(:read_only?) { true }
end
it 'denies push access' do
project.add_maintainer(user)
expect { subject }.to raise_unauthorized("You can't push code to a read-only GitLab instance.")
end
it 'denies push access with primary present' do
error_message = "You can't push code to a read-only GitLab instance.
Please use the primary node URL instead: "\
"https://localhost:3000/gitlab/#{project.full_path}.wiki.git.
For more information: #{EE::Gitlab::GeoGitAccess::GEO_SERVER_DOCS_URL}"
primary_node = create(:geo_node, :primary, url: 'https://localhost:3000/gitlab')
allow(Gitlab::Geo).to receive(:primary).and_return(primary_node)
allow(Gitlab::Geo).to receive(:secondary_with_primary?).and_return(true)
project.add_maintainer(user)
let(:primary_repo_url) { "https://localhost:3000/gitlab/#{project.full_path}.wiki.git" }
expect { subject }.to raise_unauthorized(error_message)
end
it_behaves_like 'a read-only GitLab instance'
end
context 'when wiki is disabled' do
......@@ -58,6 +36,10 @@ For more information: #{EE::Gitlab::GeoGitAccess::GEO_SERVER_DOCS_URL}"
private
def push_changes(changes = '_any')
access.check('git-receive-pack', changes)
end
def raise_unauthorized(message)
raise_error(Gitlab::GitAccess::UnauthorizedError, message)
end
......
# frozen_string_literal: true
shared_examples 'a read-only GitLab instance' do
it 'denies push access' do
project.add_maintainer(user)
expect { push_changes }.to raise_unauthorized("You can't push code to a read-only GitLab instance.")
end
context 'for a Geo setup' do
before do
primary_node = create(:geo_node, :primary, url: 'https://localhost:3000/gitlab')
allow(Gitlab::Geo).to receive(:primary).and_return(primary_node)
allow(Gitlab::Geo).to receive(:secondary_with_primary?).and_return(secondary_with_primary)
end
context 'that is incorrectly setup' do
let(:secondary_with_primary) { false }
let(:error_message) { "You can't push code to a read-only GitLab instance." }
it 'denies push access with primary present' do
project.add_maintainer(user)
expect { push_changes }.to raise_unauthorized(error_message)
end
end
context 'that is correctly setup' do
let(:secondary_with_primary) { true }
let(:payload) do
{
'action' => 'geo_proxy_to_primary',
'data' => {
'api_endpoints' => %w{/api/v4/geo/proxy_git_push_ssh/info_refs /api/v4/geo/proxy_git_push_ssh/push},
'primary_repo' => primary_repo_url
}
}
end
it 'attempts to proxy to the primary' do
project.add_maintainer(user)
expect(push_changes).to be_a(Gitlab::GitAccessResult::CustomAction)
expect(push_changes.message).to eql('Attempting to proxy to primary.')
expect(push_changes.payload).to eql(payload)
end
end
end
end
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