Skip to content
Snippets Groups Projects
Unverified Commit 5ae4430e authored by Tiago Botelho's avatar Tiago Botelho
Browse files

Adds more fine grained logging of the access checks in ChangeAccess

parent 6d08cb8a
No related branches found
No related tags found
No related merge requests found
Loading
@@ -8,7 +8,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
Loading
@@ -8,7 +8,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403 rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403
rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404 rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404
rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422 rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422
rescue_from Gitlab::GitAccess::TimeoutError, with: :render_408 rescue_from Gitlab::GitAccess::TimeoutError, with: :render_504
   
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push) # GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
Loading
@@ -63,8 +63,8 @@ class Projects::GitHttpController < Projects::GitHttpClientController
Loading
@@ -63,8 +63,8 @@ class Projects::GitHttpController < Projects::GitHttpClientController
render plain: exception.message, status: :unprocessable_entity render plain: exception.message, status: :unprocessable_entity
end end
   
def render_408(exception) def render_504(exception)
render plain: exception.message, status: :request_timeout render plain: exception.message, status: :gateway_timeout
end end
   
def access def access
Loading
Loading
Loading
@@ -66,7 +66,7 @@ module API
Loading
@@ -66,7 +66,7 @@ module API
rescue Gitlab::GitAccess::UnauthorizedError => e rescue Gitlab::GitAccess::UnauthorizedError => e
break response_with_status(code: 401, success: false, message: e.message) break response_with_status(code: 401, success: false, message: e.message)
rescue Gitlab::GitAccess::TimeoutError => e rescue Gitlab::GitAccess::TimeoutError => e
break response_with_status(code: 408, success: false, message: e.message) break response_with_status(code: 504, success: false, message: e.message)
rescue Gitlab::GitAccess::NotFoundError => e rescue Gitlab::GitAccess::NotFoundError => e
break response_with_status(code: 404, success: false, message: e.message) break response_with_status(code: 404, success: false, message: e.message)
end end
Loading
Loading
Loading
@@ -21,9 +21,14 @@ module Gitlab
Loading
@@ -21,9 +21,14 @@ module Gitlab
LOG_MESSAGES = { LOG_MESSAGES = {
push_checks: "Checking push ability...", push_checks: "Checking push ability...",
branch_checks: "Checking branch abilities...", branch_checks: "Checking branch abilities...",
protected_branch_checks: "Checking protected branch abilities...",
protected_branch_push_checks: "Checking push abilities for protected branch...",
protected_branch_deletion_checks: "Checking deletion abilities for protected branch...",
tag_checks: "Checking tag abilities...", tag_checks: "Checking tag abilities...",
lfs_objects_exist_check: "Checking LFS object abilities...", protected_tag_checks: "Checking protected tag abilities...",
commits_check: "Checking commits abilities..." lfs_objects_exist_check: "Scanning for LFS objects...",
commits_check: "Validating commits...",
commits_check_file_paths_validation: "Validating commits' file paths..."
}.freeze }.freeze
   
attr_accessor :check_log attr_accessor :check_log
Loading
@@ -45,23 +50,17 @@ module Gitlab
Loading
@@ -45,23 +50,17 @@ module Gitlab
@skip_lfs_integrity_check = skip_lfs_integrity_check @skip_lfs_integrity_check = skip_lfs_integrity_check
@protocol = protocol @protocol = protocol
@start_time = start_time @start_time = start_time
@check_log = ["Running checks for branch: #{@branch_name || @tag_name}"] @check_log = ["Running checks for ref: #{@branch_name || @tag_name}"]
end end
   
def exec(skip_commits_check: false) def exec(skip_commits_check: false)
return true if skip_authorization return true if skip_authorization
   
log_timed(:push_checks) { push_checks } push_checks
log_timed(:branch_checks) { branch_checks } branch_checks
log_timed(:tag_checks) { tag_checks } tag_checks
lfs_objects_exist_check unless skip_lfs_integrity_check
unless skip_lfs_integrity_check commits_check unless skip_commits_check
log_timed(:lfs_objects_exist_check) { lfs_objects_exist_check }
end
unless skip_commits_check
log_timed(:commits_check) { commits_check }
end
   
true true
end end
Loading
@@ -69,19 +68,23 @@ module Gitlab
Loading
@@ -69,19 +68,23 @@ module Gitlab
protected protected
   
def push_checks def push_checks
unless can_push? log_timed(:push_checks) do
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code] unless can_push?
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code]
end
end end
end end
   
def branch_checks def branch_checks
return unless branch_name return unless branch_name
   
if deletion? && branch_name == project.default_branch log_timed(:branch_checks) do
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:delete_default_branch] if deletion? && branch_name == project.default_branch
end raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:delete_default_branch]
end
   
protected_branch_checks log_timed(:protected_branch_checks) { protected_branch_checks }
end
end end
   
def protected_branch_checks def protected_branch_checks
Loading
@@ -92,9 +95,13 @@ module Gitlab
Loading
@@ -92,9 +95,13 @@ module Gitlab
end end
   
if deletion? if deletion?
protected_branch_deletion_checks log_timed(:protected_branch_deletion_checks) do
protected_branch_deletion_checks
end
else else
protected_branch_push_checks log_timed(:protected_branch_push_checks) do
protected_branch_push_checks
end
end end
end end
   
Loading
@@ -123,11 +130,13 @@ module Gitlab
Loading
@@ -123,11 +130,13 @@ module Gitlab
def tag_checks def tag_checks
return unless tag_name return unless tag_name
   
if tag_exists? && user_access.cannot_do_action?(:admin_project) log_timed(:tag_checks) do
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:change_existing_tags] if tag_exists? && user_access.cannot_do_action?(:admin_project)
end raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:change_existing_tags]
end
   
protected_tag_checks log_timed(:protected_tag_checks) { protected_tag_checks }
end
end end
   
def protected_tag_checks def protected_tag_checks
Loading
@@ -145,16 +154,24 @@ module Gitlab
Loading
@@ -145,16 +154,24 @@ module Gitlab
return if deletion? || newrev.nil? return if deletion? || newrev.nil?
return unless should_run_commit_validations? return unless should_run_commit_validations?
   
# n+1: https://gitlab.com/gitlab-org/gitlab-ee/issues/3593 start = Time.now
::Gitlab::GitalyClient.allow_n_plus_1_calls do log_timed(:commits_check, start) do
commits.each do |commit| # n+1: https://gitlab.com/gitlab-org/gitlab-ee/issues/3593
raise TimeoutError unless time_left > 0 ::Gitlab::GitalyClient.allow_n_plus_1_calls do
commits.each do |commit|
unless time_left > 0
check_log << LOG_MESSAGES[:commits_check] + time_suffix_message(cancelled: true, start: start)
raise TimeoutError
end
commit_check.validate(commit, validations_for_commit(commit))
end
end
   
commit_check.validate(commit, validations_for_commit(commit)) log_timed(:commits_check_file_paths_validation) do
commit_check.validate_file_paths
end end
end end
commit_check.validate_file_paths
end end
   
# Method overwritten in EE to inject custom validations # Method overwritten in EE to inject custom validations
Loading
@@ -216,10 +233,12 @@ module Gitlab
Loading
@@ -216,10 +233,12 @@ module Gitlab
end end
   
def lfs_objects_exist_check def lfs_objects_exist_check
lfs_check = Checks::LfsIntegrity.new(project, newrev, time_left) log_timed(:lfs_objects_exist_check) do
lfs_check = Checks::LfsIntegrity.new(project, newrev, time_left)
   
if lfs_check.objects_missing? if lfs_check.objects_missing?
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:lfs_objects_missing] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:lfs_objects_missing]
end
end end
end end
   
Loading
@@ -236,16 +255,38 @@ module Gitlab
Loading
@@ -236,16 +255,38 @@ module Gitlab
user_access.can_push_to_branch?(branch_name) user_access.can_push_to_branch?(branch_name)
end end
   
def log_timed(method_name, start = Time.now)
unless time_left > 0
check_log << LOG_MESSAGES[method_name] + time_suffix_message(cancelled: true)
raise TimeoutError
end
yield
check_log << LOG_MESSAGES[method_name] + time_suffix_message(start: start)
rescue GRPC::DeadlineExceeded
check_log << LOG_MESSAGES[method_name] + time_suffix_message(cancelled: true, start: start)
raise TimeoutError
end
def time_suffix_message(cancelled: false, start: nil)
if cancelled
if start
" (cancelled after #{elapsed_time(start)}ms)"
else
" (cancelled)"
end
else
" (#{elapsed_time(start)}ms)"
end
end
def time_left def time_left
(start_time + Gitlab::GitAccess::INTERNAL_TIMEOUT.seconds) - Time.now (start_time + Gitlab::GitAccess::INTERNAL_TIMEOUT.seconds) - Time.now
end end
   
def log_timed(method_name) def elapsed_time(start)
raise TimeoutError unless time_left > 0 to_ms(Time.now - start)
start = Time.now
yield
check_log << LOG_MESSAGES[method_name] + "(#{to_ms(Time.now - start)}ms)"
end end
   
def to_ms(elapsed) def to_ms(elapsed)
Loading
Loading
Loading
@@ -283,9 +283,11 @@ module Gitlab
Loading
@@ -283,9 +283,11 @@ module Gitlab
) )
   
change_access.exec change_access.exec
@trace += change_access.check_log @trace.concat(change_access.check_log)
rescue Checks::ChangeAccess::TimeoutError, GRPC::DeadlineExceeded rescue Checks::ChangeAccess::TimeoutError
@trace += change_access.check_log @trace.concat(change_access.check_log)
@trace << "Push operation timed out"
raise TimeoutError, @trace.join("\n") raise TimeoutError, @trace.join("\n")
end end
   
Loading
Loading
Loading
@@ -85,12 +85,19 @@ module Gitlab
Loading
@@ -85,12 +85,19 @@ module Gitlab
request.not_in_refs += not_in request.not_in_refs += not_in
end end
   
timeout =
if dynamic_timeout
[dynamic_timeout, GitalyClient.medium_timeout].min
else
GitalyClient.medium_timeout
end
response = GitalyClient.call( response = GitalyClient.call(
@gitaly_repo.storage_name, @gitaly_repo.storage_name,
:blob_service, :blob_service,
:get_new_lfs_pointers, :get_new_lfs_pointers,
request, request,
timeout: dynamic_timeout || GitalyClient.medium_timeout timeout: timeout
) )
   
map_lfs_pointers(response) map_lfs_pointers(response)
Loading
Loading
Loading
@@ -935,16 +935,10 @@ describe Gitlab::GitAccess do
Loading
@@ -935,16 +935,10 @@ describe Gitlab::GitAccess do
expect { access.check('git-receive-pack', changes) }.not_to exceed_query_limit(control_count).with_threshold(1) expect { access.check('git-receive-pack', changes) }.not_to exceed_query_limit(control_count).with_threshold(1)
end end
   
it 'raises TimeoutError when #check_single_change_access raises DeadlineExceeded error' do
allow_any_instance_of(Gitlab::Checks::ChangeAccess).to receive(:exec).and_raise(GRPC::DeadlineExceeded)
expect { access.check('git-receive-pack', changes) }.to raise_error(described_class::TimeoutError, "Running checks for branch: wow")
end
it 'raises TimeoutError when #check_single_change_access raises a timeout error' do it 'raises TimeoutError when #check_single_change_access raises a timeout error' do
allow_any_instance_of(Gitlab::Checks::ChangeAccess).to receive(:exec).and_raise(Gitlab::Checks::ChangeAccess::TimeoutError) allow_any_instance_of(Gitlab::Checks::ChangeAccess).to receive(:exec).and_raise(Gitlab::Checks::ChangeAccess::TimeoutError)
   
expect { access.check('git-receive-pack', changes) }.to raise_error(described_class::TimeoutError, "Running checks for branch: wow") expect { access.check('git-receive-pack', changes) }.to raise_error(described_class::TimeoutError, "Running checks for ref: wow\nPush operation timed out")
end end
end end
end end
Loading
Loading
Loading
@@ -495,28 +495,14 @@ describe API::Internal do
Loading
@@ -495,28 +495,14 @@ describe API::Internal do
end end
   
context 'request times out' do context 'request times out' do
let(:personal_project) { create(:project, namespace: user.namespace) }
before do
allow_any_instance_of(Gitlab::GitAccess).to receive(:check).and_raise(Gitlab::GitAccess::TimeoutError, "Foo")
end
context 'git pull' do
it do
pull(key, personal_project)
expect(response).to have_gitlab_http_status(408)
expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq("Foo")
expect(user.reload.last_activity_on).to be_nil
end
end
context 'git push' do context 'git push' do
it do it 'responds with a gateway timeout' do
personal_project = create(:project, namespace: user.namespace)
allow_any_instance_of(Gitlab::GitAccess).to receive(:check).and_raise(Gitlab::GitAccess::TimeoutError, "Foo")
push(key, personal_project) push(key, personal_project)
   
expect(response).to have_gitlab_http_status(408) expect(response).to have_gitlab_http_status(504)
expect(json_response['status']).to be_falsey expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq("Foo") expect(json_response['message']).to eq("Foo")
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment