Skip to content
Snippets Groups Projects
Verified Commit 86f3d411 authored by Francisco Javier López's avatar Francisco Javier López :red_circle:
Browse files

Moved git project endpoint to namespace

parent 6ea57e76
No related branches found
No related tags found
No related merge requests found
Pipeline #103336697 failed
Showing
with 960 additions and 26 deletions
# frozen_string_literal: true
module Namespaces
class ApplicationController < ApplicationController
skip_before_action :authenticate_user!
end
end
# frozen_string_literal: true
module Namespaces
class GitHttpClientController < Namespaces::ApplicationController
include ActionController::HttpAuthentication::Basic
include Gitlab::Utils::StrongMemoize
include KerberosSpnegoHelper
attr_reader :authentication_result, :redirected_path
delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true
delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result
alias_method :user, :actor
alias_method :authenticated_user, :actor
# Git clients will not know what authenticity token to send along
skip_around_action :set_session_storage
skip_before_action :verify_authenticity_token
before_action :authenticate_user
private
def download_request?
raise NotImplementedError
end
def upload_request?
raise NotImplementedError
end
def authenticate_user
@authentication_result = Gitlab::Auth::Result.new
if allow_basic_auth? && basic_auth_provided?
login, password = user_name_and_password(request)
if handle_basic_authentication(login, password)
return # Allow access
end
elsif allow_kerberos_spnego_auth? && spnego_provided?
kerberos_user = find_kerberos_user
if kerberos_user
@authentication_result = Gitlab::Auth::Result.new(
kerberos_user, nil, :kerberos, Gitlab::Auth.full_authentication_abilities)
send_final_spnego_response
return # Allow access
end
elsif project && download_request? && http_allowed? && Guest.can?(:download_code, project)
@authentication_result = Gitlab::Auth::Result.new(nil, project, :none, [:download_code])
return # Allow access
end
send_challenges
render plain: "HTTP Basic: Access denied\n", status: :unauthorized
rescue Gitlab::Auth::MissingPersonalAccessTokenError
render_missing_personal_access_token
end
def basic_auth_provided?
has_basic_credentials?(request)
end
def send_challenges
challenges = []
challenges << 'Basic realm="GitLab"' if allow_basic_auth?
challenges << spnego_challenge if allow_kerberos_spnego_auth?
headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
end
def project
parse_repo_path unless defined?(@project)
@project
end
def parse_repo_path
@project, @repo_type, @redirected_path, @suffix = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}")
end
def render_missing_personal_access_token
render plain: "HTTP Basic: Access denied\n" \
"You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}",
status: :unauthorized
end
def repository
render_404 if snippet? && !snippet
repo_type.repository_for(snippet || project)
end
def snippet?
repo_type.snippet?
end
def snippet
strong_memoize(:snippet) do
next unless snippet?
snippet_id = repo_type.fetch_id(@suffix)
project&.snippets&.find_by_id(snippet_id)
# SnippetsFinder.new(authenticated_user, project: project, ids: snippet_id).execute.first
end
end
def repo_type
parse_repo_path unless defined?(@repo_type)
@repo_type
end
def handle_basic_authentication(login, password)
@authentication_result = Gitlab::Auth.find_for_git_client(
login, password, project: project, ip: request.ip)
@authentication_result.success?
end
def ci?
authentication_result.ci?(project)
end
def http_allowed?
Gitlab::ProtocolAccess.allowed?('http')
end
end
end
Namespaces::GitHttpClientController.prepend_if_ee('EE::Namespaces::GitHttpClientController')
# frozen_string_literal: true
module Namespaces
class GitHttpController < Namespaces::GitHttpClientController
include WorkhorseRequest
before_action :access_check
prepend_before_action :deny_head_requests, only: [:info_refs]
rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403_with_exception
rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception
rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception
rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs
log_user_activity if upload_pack?
render_ok
end
# POST /foo/bar.git/git-upload-pack (git pull)
def git_upload_pack
enqueue_fetch_statistics_update
render_ok
end
# POST /foo/bar.git/git-receive-pack" (git push)
def git_receive_pack
render_ok
end
private
def deny_head_requests
head :forbidden if request.head?
end
def download_request?
upload_pack?
end
def upload_pack?
git_command == 'git-upload-pack'
end
def git_command
if action_name == 'info_refs'
params[:service]
else
action_name.dasherize
end
end
def render_ok
set_workhorse_internal_api_content_type
render json: Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name)
end
def render_403_with_exception(exception)
render plain: exception.message, status: :forbidden
end
def render_404_with_exception(exception)
render plain: exception.message, status: :not_found
end
def render_422_with_exception(exception)
render plain: exception.message, status: :unprocessable_entity
end
def render_503_with_exception(exception)
render plain: exception.message, status: :service_unavailable
end
def enqueue_fetch_statistics_update
return if wiki? || snippet?
return unless project.daily_statistics_enabled?
ProjectDailyStatisticsWorker.perform_async(project.id)
end
def access
@access ||= access_klass.new(access_actor, project,
'http', authentication_abilities: authentication_abilities,
namespace_path: params[:namespace_id], project_path: project_path,
redirected_path: redirected_path, auth_result_type: auth_result_type)
end
def access_actor
return user if user
return :ci if ci?
end
def access_check
access.check(git_command, Gitlab::GitAccess::ANY)
@project ||= access.project
end
def access_klass
@access_klass ||= repo_type.access_checker_class
end
def project_path
@project_path ||= params[:project_id].sub(/\.git$/, '')
end
def log_user_activity
Users::ActivityService.new(user, 'pull').execute
end
end
end
Namespaces::GitHttpController.prepend_if_ee('EE::Namespaces::GitHttpController')
# frozen_string_literal: true
module Namespaces
class LfsApiController < Namespaces::GitHttpClientController
include LfsRequest
include Gitlab::Utils::StrongMemoize
LFS_TRANSFER_CONTENT_TYPE = 'application/octet-stream'
skip_before_action :lfs_check_access!, only: [:deprecated]
before_action :lfs_check_batch_operation!, only: [:batch]
def batch
unless objects.present?
render_lfs_not_found
return
end
if download_request?
render json: { objects: download_objects! }
elsif upload_request?
render json: { objects: upload_objects! }
else
raise "Never reached"
end
end
def deprecated
render(
json: {
message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'),
documentation_url: "#{Gitlab.config.gitlab.url}/help"
},
status: :not_implemented
)
end
private
def download_request?
params[:operation] == 'download'
end
def upload_request?
params[:operation] == 'upload'
end
# rubocop: disable CodeReuse/ActiveRecord
def existing_oids
@existing_oids ||= begin
project.all_lfs_objects.where(oid: objects.map { |o| o['oid'].to_s }).pluck(:oid)
end
end
# rubocop: enable CodeReuse/ActiveRecord
def download_objects!
objects.each do |object|
if existing_oids.include?(object[:oid])
object[:actions] = download_actions(object)
if Guest.can?(:download_code, project)
object[:authenticated] = true
end
else
object[:error] = {
code: 404,
message: _("Object does not exist on the server or you don't have permissions to access it")
}
end
end
objects
end
def upload_objects!
objects.each do |object|
object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid])
end
objects
end
def download_actions(object)
{
download: {
href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}",
header: {
Authorization: authorization_header
}.compact
}
}
end
def upload_actions(object)
{
upload: {
href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}/#{object[:size]}",
header: {
Authorization: authorization_header,
# git-lfs v2.5.0 sets the Content-Type based on the uploaded file. This
# ensures that Workhorse can intercept the request.
'Content-Type': LFS_TRANSFER_CONTENT_TYPE
}.compact
}
}
end
def lfs_check_batch_operation!
if batch_operation_disallowed?
render(
json: {
message: lfs_read_only_message
},
content_type: LfsRequest::CONTENT_TYPE,
status: :forbidden
)
end
end
# Overridden in EE
def batch_operation_disallowed?
upload_request? && Gitlab::Database.read_only?
end
# Overridden in EE
def lfs_read_only_message
_('You cannot write to this read-only GitLab instance.')
end
def authorization_header
strong_memoize(:authorization_header) do
lfs_auth_header || request.headers['Authorization']
end
end
def lfs_auth_header
return unless user.is_a?(User)
Gitlab::LfsToken.new(user).basic_encoding
end
end
end
# Projects::LfsApiController.prepend_if_ee('EE::Projects::LfsApiController')
# frozen_string_literal: true
module Namespaces
class LfsLocksApiController < Namespaces::GitHttpClientController
include LfsRequest
def create
@result = Lfs::LockFileService.new(project, user, lfs_params).execute
render_json(@result[:lock])
end
def unlock
@result = Lfs::UnlockFileService.new(project, user, lfs_params).execute
render_json(@result[:lock])
end
def index
@result = Lfs::LocksFinderService.new(project, user, lfs_params).execute
render_json(@result[:locks])
end
def verify
@result = Lfs::LocksFinderService.new(project, user, {}).execute
ours, theirs = split_by_owner(@result[:locks])
render_json({ ours: ours, theirs: theirs }, false)
end
private
def render_json(data, process = true)
render json: build_payload(data, process),
content_type: LfsRequest::CONTENT_TYPE,
status: @result[:http_status]
end
def build_payload(data, process)
data = LfsFileLockSerializer.new.represent(data) if process
return data if @result[:status] == :success
# When the locking failed due to an existent Lock, the existent record
# is returned in `@result[:lock]`
error_payload(@result[:message], @result[:lock] ? data : {})
end
def error_payload(message, custom_attrs = {})
custom_attrs.merge({
message: message,
documentation_url: help_url
})
end
def split_by_owner(locks)
groups = locks.partition { |lock| lock.user_id == user.id }
groups.map! do |records|
LfsFileLockSerializer.new.represent(records, root: false)
end
end
def download_request?
params[:action] == 'index'
end
def upload_request?
%w(create unlock verify).include?(params[:action])
end
def lfs_params
params.permit(:id, :path, :force)
end
end
end
# frozen_string_literal: true
module Namespaces
class LfsStorageController < Namespaces::GitHttpClientController
include LfsRequest
include WorkhorseRequest
include SendFileUpload
skip_before_action :verify_workhorse_api!, only: :download
def download
lfs_object = LfsObject.find_by_oid(oid)
unless lfs_object && lfs_object.file.exists?
render_lfs_not_found
return
end
send_upload(lfs_object.file, send_params: { content_type: "application/octet-stream" })
end
def upload_authorize
set_workhorse_internal_api_content_type
authorized = LfsObjectUploader.workhorse_authorize(has_length: true)
authorized.merge!(LfsOid: oid, LfsSize: size)
render json: authorized
end
def upload_finalize
if store_file!(oid, size)
head 200
else
render plain: 'Unprocessable entity', status: :unprocessable_entity
end
rescue ActiveRecord::RecordInvalid
render_lfs_forbidden
rescue UploadedFile::InvalidPathError
render_lfs_forbidden
rescue ObjectStorage::RemoteStoreError
render_lfs_forbidden
end
private
def download_request?
action_name == 'download'
end
def upload_request?
%w[upload_authorize upload_finalize].include? action_name
end
def oid
params[:oid].to_s
end
def size
params[:size].to_i
end
# rubocop: disable CodeReuse/ActiveRecord
def store_file!(oid, size)
object = LfsObject.find_by(oid: oid, size: size)
unless object&.file&.exists?
object = create_file!(oid, size)
end
return unless object
link_to_project!(object)
end
# rubocop: enable CodeReuse/ActiveRecord
def create_file!(oid, size)
uploaded_file = UploadedFile.from_params(
params, :file, LfsObjectUploader.workhorse_local_upload_path)
return unless uploaded_file
LfsObject.create!(oid: oid, size: size, file: uploaded_file)
end
# rubocop: disable CodeReuse/ActiveRecord
def link_to_project!(object)
if object && !object.projects.exists?(storage_project.id)
object.lfs_objects_projects.create!(project: storage_project)
end
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
scope(path: '*namespace_id/:project_id',
format: nil,
constraints: { namespace_id: Gitlab::PathRegex.full_namespace_route_regex }) do
scope(constraints: { project_id: Gitlab::PathRegex.project_git_route_regex }, module: :projects) do
scope(constraints: { project_id: Gitlab::PathRegex.project_git_route_regex }, module: :namespaces) do
# Git HTTP clients ('git clone' etc.)
scope(controller: :git_http) do
get '/info/refs', action: :info_refs
......
# frozen_string_literal: true
module EE
module Namespaces
module GitHttpClientController
extend ActiveSupport::Concern
# This module is responsible for determining if an incoming secondary bound
# HTTP request should be redirected to the primary.
#
# Why? A secondary is not allowed to perform any write actions, so any
# request of this type need to be sent through to the primary. By
# redirecting within code, we allow clients to git pull/push using their
# secondary git remote without needing an additional primary remote.
#
# Current secondary HTTP requests to redirect: -
#
# * git push
# * GET /repo.git/info/refs?service=git-receive-pack
# * POST /repo.git/git-receive-pack
#
# * git lfs push (usually happens automatically as part of a `git push`)
# * POST /repo.git/info/lfs/objects/batch (and we examine
# params[:operation] to ensure we're dealing with an upload request)
#
# For more detail, see the following links:
#
# git: https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols
# git-lfs: https://github.com/git-lfs/git-lfs/blob/master/docs/api
#
prepended do
prepend_before_action do
redirect_to(primary_full_url) if redirect?
end
end
private
class RouteHelper
attr_reader :controller_name, :action_name
CONTROLLER_AND_ACTIONS_TO_REDIRECT = {
'git_http' => %w{git_receive_pack},
'lfs_locks_api' => %w{create unlock verify}
}.freeze
def initialize(controller_name, action_name, service)
@controller_name = controller_name
@action_name = action_name
@service = service
end
def match?(c_name, a_name)
controller_name == c_name && action_name == a_name
end
def redirect?
!!CONTROLLER_AND_ACTIONS_TO_REDIRECT[controller_name]&.include?(action_name) ||
git_receive_pack_request?
end
private
attr_reader :service
# Examples:
#
# /repo.git/info/refs?service=git-receive-pack returns 'git-receive-pack'
# /repo.git/info/refs?service=git-upload-pack returns 'git-upload-pack'
# /repo.git/git-receive-pack returns 'git-receive-pack'
# /repo.git/git-upload-pack returns 'git-upload-pack'
#
def service_or_action_name
info_refs_request? ? service : action_name.dasherize
end
# Matches:
#
# GET /repo.git/info/refs?service=git-receive-pack
# POST /repo.git/git-receive-pack
#
def git_receive_pack_request?
service_or_action_name == 'git-receive-pack'
end
# Matches:
#
# GET /repo.git/info/refs
#
def info_refs_request?
action_name == 'info_refs'
end
end
class GitLFSHelper
MINIMUM_GIT_LFS_VERSION = '2.4.2'.freeze
def initialize(route_helper, operation, current_version)
@route_helper = route_helper
@operation = operation
@current_version = current_version
end
def incorrect_version_response
{
json: { message: incorrect_version_message },
content_type: ::LfsRequest::CONTENT_TYPE,
status: 403
}
end
def redirect?
return false unless route_helper.match?('lfs_api', 'batch')
return true if upload?
false
end
def version_ok?
return false unless current_version
::Gitlab::VersionInfo.parse(current_version) >= wanted_version
end
private
attr_reader :route_helper, :operation, :current_version
def incorrect_version_message
translation = _("You need git-lfs version %{min_git_lfs_version} (or greater) to continue. Please visit https://git-lfs.github.com")
translation % { min_git_lfs_version: MINIMUM_GIT_LFS_VERSION }
end
def upload?
operation == 'upload'
end
def wanted_version
::Gitlab::VersionInfo.parse(MINIMUM_GIT_LFS_VERSION)
end
end
def route_helper
@route_helper ||= RouteHelper.new(controller_name, action_name, params[:service])
end
def git_lfs_helper
# params[:operation] explained: https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md#requests
@git_lfs_helper ||= GitLFSHelper.new(route_helper, params[:operation], request.headers['User-Agent'])
end
def request_fullpath_for_primary
relative_url_root = ::Gitlab.config.gitlab.relative_url_root.chomp('/')
request.fullpath.sub(relative_url_root, '')
end
def primary_full_url
path = File.join(secondary_referrer_path_prefix, request_fullpath_for_primary)
::Gitlab::Utils.append_path(::Gitlab::Geo.primary_node.internal_url, path)
end
def secondary_referrer_path_prefix
File.join(::Gitlab::Geo::GitPushHttp::PATH_PREFIX, ::Gitlab::Geo.current_node.id.to_s)
end
def redirect?
# Don't redirect if we're not a secondary with a primary
return false unless ::Gitlab::Geo.secondary_with_primary?
# Redirect as the request matches RouteHelper::CONTROLLER_AND_ACTIONS_TO_REDIRECT
return true if route_helper.redirect?
# Look to redirect, as we're an LFS batch upload request
if git_lfs_helper.redirect?
# Redirect as git-lfs version is at least 2.4.2
return true if git_lfs_helper.version_ok?
# git-lfs 2.4.2 is really only required for requests that involve
# redirection, so we only render if it's an LFS upload operation
#
render(git_lfs_helper.incorrect_version_response)
# Don't redirect
return false
end
# Don't redirect
false
end
end
end
end
# frozen_string_literal: true
module EE
module Namespaces
module GitHttpController
extend ::Gitlab::Utils::Override
include ::Gitlab::Utils::StrongMemoize
override :render_ok
def render_ok
set_workhorse_internal_api_content_type
render json: ::Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name, show_all_refs: geo_request?)
end
override :git_receive_pack
def git_receive_pack
# Authentication/authorization already happened in `before_action`s
if ::Gitlab::Geo.primary?
# This ID is used by the /internal/post_receive API call
gl_id = ::Gitlab::GlId.gl_id(user)
gl_repository = repo_type.identifier_for_subject(project)
node_id = params["geo_node_id"]
::Gitlab::Geo::GitPushHttp.new(gl_id, gl_repository).cache_referrer_node(node_id)
end
super
end
private
def user
super || geo_push_user&.user
end
def geo_push_user
@geo_push_user ||= ::Geo::PushUser.new_from_headers(request.headers)
end
def geo_push_user_headers_provided?
::Geo::PushUser.needed_headers_provided?(request.headers)
end
def geo_request?
::Gitlab::Geo::JwtRequestDecoder.geo_auth_attempt?(request.headers['Authorization'])
end
def geo?
authentication_result.geo?(project)
end
override :access_actor
def access_actor
return super unless geo?
return :geo unless geo_push_user_headers_provided?
return geo_push_user.user if geo_push_user.user
raise ::Gitlab::GitAccess::UnauthorizedError, 'Geo push user is invalid.'
end
override :authenticate_user
def authenticate_user
return super unless geo_request?
return render_bad_geo_response('Request from this IP is not allowed') unless ip_allowed?
return render_bad_geo_jwt('Bad token') unless decoded_authorization
return render_bad_geo_jwt('Unauthorized scope') unless jwt_scope_valid?
# grant access
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code, :push_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
rescue ::Gitlab::Geo::InvalidDecryptionKeyError
render_bad_geo_jwt("Invalid decryption key")
rescue ::Gitlab::Geo::InvalidSignatureTimeError
render_bad_geo_jwt("Invalid signature time ")
end
def jwt_scope_valid?
decoded_authorization[:scope] == repository_full_path
end
def repository_full_path
File.join(params[:namespace_id], project_path)
end
def decoded_authorization
strong_memoize(:decoded_authorization) do
::Gitlab::Geo::JwtRequestDecoder.new(request.headers['Authorization']).decode
end
end
def render_bad_geo_jwt(message)
render_bad_geo_response("Geo JWT authentication failed: #{message}")
end
def render_bad_geo_response(message)
render plain: message, status: :unauthorized
end
def ip_allowed?
::Gitlab::Geo.allowed_ip?(request.ip)
end
end
end
end
# frozen_string_literal: true
module EE
module Namespaces
module LfsApiController
extend ::Gitlab::Utils::Override
include GitlabRoutingHelper
override :batch_operation_disallowed?
def batch_operation_disallowed?
super_result = super
return true if super_result && !::Gitlab::Geo.enabled?
if super_result && ::Gitlab::Geo.enabled?
return true if !::Gitlab::Geo.primary? && !::Gitlab::Geo.secondary?
return true if ::Gitlab::Geo.secondary? && !::Gitlab::Geo.primary_node_configured?
end
false
end
override :lfs_read_only_message
def lfs_read_only_message
return super unless ::Gitlab::Geo.secondary_with_primary?
translation = _('You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead.')
message = translation % { link_to_primary_node: geo_primary_default_url_to_repo(project) }
message.html_safe
end
end
end
end
......@@ -43,11 +43,12 @@ class GitAccess
PUSH_COMMANDS = %w{git-receive-pack}.freeze
ALL_COMMANDS = DOWNLOAD_COMMANDS + PUSH_COMMANDS
attr_reader :actor, :project, :protocol, :authentication_abilities, :namespace_path, :project_path, :redirected_path, :auth_result_type, :changes, :logger
attr_reader :actor, :protocol, :subject, :authentication_abilities, :namespace_path, :project_path, :redirected_path, :auth_result_type, :changes, :logger
alias_method :project, :subject
def initialize(actor, project, protocol, authentication_abilities:, namespace_path: nil, project_path: nil, redirected_path: nil, auth_result_type: nil)
def initialize(actor, subject, protocol, authentication_abilities:, namespace_path: nil, project_path: nil, redirected_path: nil, auth_result_type: nil)
@actor = actor
@project = project
@subject = subject
@protocol = protocol
@authentication_abilities = authentication_abilities
@namespace_path = namespace_path
......
......@@ -7,28 +7,14 @@ class GitAccessSnippet < GitAccess
write_to_snippet: "You are not allowed to write to this project's snippet."
}.freeze
def guest_can_read_snippet?
Guest.can?(:read_project_snippet, project)
end
def user_can_read_snippet?
authentication_abilities.include?(:read_project_snippet) && user_access.can_do_action?(:read_project_snippet)
end
def check_change_access!
unless user_access.can_do_action?(:create_project_snippet)
raise UnauthorizedError, ERROR_MESSAGES[:write_to_snippet]
end
if Gitlab::Database.read_only?
raise UnauthorizedError, push_to_read_only_message
end
true
end
def push_to_read_only_message
ERROR_MESSAGES[:read_only]
def check(cmd, _changes)
binding.pry
# unless geo?
# check_protocol!
# check_can_create_design!
# end
success_result(cmd)
end
private
......
# frozen_string_literal: true
require 'spec_helper'
describe Namespaces::GitHttpController do
let_it_be(:project) { create(:project, :public, :repository) }
describe 'HEAD #info_refs' do
it 'returns 403' do
head :info_refs, params: { namespace_id: project.namespace.to_param, project_id: project.path + '.git' }
expect(response.status).to eq(403)
end
end
describe 'GET #info_refs' do
it 'returns 401 for unauthenticated requests to public repositories when http protocol is disabled' do
stub_application_setting(enabled_git_access_protocol: 'ssh')
get :info_refs, params: { service: 'git-upload-pack', namespace_id: project.namespace.to_param, project_id: project.path + '.git' }
expect(response.status).to eq(401)
end
context 'with exceptions' do
before do
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
end
it 'returns 503 with GRPC Unavailable' do
allow(controller).to receive(:access_check).and_raise(GRPC::Unavailable)
get :info_refs, params: { service: 'git-upload-pack', namespace_id: project.namespace.to_param, project_id: project.path + '.git' }
expect(response.status).to eq(503)
end
it 'returns 503 with timeout error' do
allow(controller).to receive(:access_check).and_raise(Gitlab::GitAccess::TimeoutError)
get :info_refs, params: { service: 'git-upload-pack', namespace_id: project.namespace.to_param, project_id: project.path + '.git' }
expect(response.status).to eq(503)
expect(response.body).to eq 'Gitlab::GitAccess::TimeoutError'
end
end
end
end
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