Skip to content
Snippets Groups Projects
Commit 411cc779 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 3e36f70b
No related branches found
No related tags found
No related merge requests found
Showing
with 630 additions and 580 deletions
Loading
Loading
@@ -2,10 +2,6 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
 
## 12.7.2
- No changes.
## 12.7.1
 
### Fixed (6 changes)
Loading
Loading
Loading
Loading
@@ -20,6 +20,8 @@ import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale';
import _ from 'underscore';
 
export const tableDataClass = 'table-col d-flex d-sm-table-cell';
export default {
FIRST_PAGE: 1,
PREV_PAGE: 1,
Loading
Loading
@@ -29,37 +31,37 @@ export default {
key: 'error',
label: __('Error'),
thClass: 'w-60p',
tdClass: 'table-col d-flex d-sm-table-cell px-3',
tdClass: `${tableDataClass} px-3`,
},
{
key: 'events',
label: __('Events'),
thClass: 'text-right',
tdClass: 'table-col d-flex d-sm-table-cell',
tdClass: `${tableDataClass}`,
},
{
key: 'users',
label: __('Users'),
thClass: 'text-right',
tdClass: 'table-col d-flex d-sm-table-cell',
tdClass: `${tableDataClass}`,
},
{
key: 'lastSeen',
label: __('Last seen'),
thClass: '',
tdClass: 'table-col d-flex d-sm-table-cell',
tdClass: `${tableDataClass}`,
},
{
key: 'ignore',
label: '',
thClass: 'w-3rem',
tdClass: 'table-col d-flex pl-0 d-sm-table-cell',
tdClass: `${tableDataClass} pl-0`,
},
{
key: 'resolved',
label: '',
thClass: 'w-3rem',
tdClass: 'table-col d-flex pl-0 d-sm-table-cell',
tdClass: `${tableDataClass} pl-0`,
},
{
key: 'details',
Loading
Loading
Loading
Loading
@@ -119,6 +119,7 @@ export default {
:class="retryButtonClass"
:href="job.retry_path"
data-method="post"
data-qa-selector="retry_button"
rel="nofollow"
>{{ __('Retry') }}</gl-link
>
Loading
Loading
# frozen_string_literal: true
class Projects::GitHttpClientController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper
include Gitlab::Utils::StrongMemoize
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
skip_before_action :repository
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 http_download_allowed?
@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 = 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
strong_memoize(:repository) do
repo_type.repository_for(project)
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_download_allowed?
Gitlab::ProtocolAccess.allowed?('http') &&
download_request? &&
project && Guest.can?(:download_code, project)
end
end
Projects::GitHttpClientController.prepend_if_ee('EE::Projects::GitHttpClientController')
# frozen_string_literal: true
class Projects::GitHttpController < Projects::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 Gitlab::Database.read_only?
return if repo_type.wiki?
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).execute
end
end
Projects::GitHttpController.prepend_if_ee('EE::Projects::GitHttpController')
# frozen_string_literal: true
class Projects::LfsApiController < Projects::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
Projects::LfsApiController.prepend_if_ee('EE::Projects::LfsApiController')
# frozen_string_literal: true
class Projects::LfsLocksApiController < Projects::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
# frozen_string_literal: true
class Projects::LfsStorageController < Projects::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
Loading
Loading
@@ -387,6 +387,7 @@ class ProjectsController < Projects::ApplicationController
:merge_method,
:initialize_with_readme,
:autoclose_referenced_issues,
:suggestion_commit_message,
 
project_feature_attributes: %i[
builds_access_level
Loading
Loading
# frozen_string_literal: true
module Repositories
class ApplicationController < ::ApplicationController
skip_before_action :authenticate_user!
end
end
# frozen_string_literal: true
module Repositories
class GitHttpClientController < Repositories::ApplicationController
include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper
include Gitlab::Utils::StrongMemoize
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 :parse_repo_path
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 http_download_allowed?
@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 = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:repository_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
strong_memoize(:repository) do
repo_type.repository_for(project)
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_download_allowed?
Gitlab::ProtocolAccess.allowed?('http') &&
download_request? &&
project && Guest.can?(:download_code, project)
end
end
end
Repositories::GitHttpClientController.prepend_if_ee('EE::Repositories::GitHttpClientController')
# frozen_string_literal: true
module Repositories
class GitHttpController < Repositories::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 Gitlab::Database.read_only?
return unless repo_type.project?
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[:repository_id].sub(/\.git$/, '')
end
def log_user_activity
Users::ActivityService.new(user).execute
end
end
end
Repositories::GitHttpController.prepend_if_ee('EE::Repositories::GitHttpController')
# frozen_string_literal: true
module Repositories
class LfsApiController < Repositories::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
Repositories::LfsApiController.prepend_if_ee('EE::Repositories::LfsApiController')
# frozen_string_literal: true
module Repositories
class LfsLocksApiController < Repositories::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 Repositories
class LfsStorageController < Repositories::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
Loading
Loading
@@ -11,77 +11,87 @@ module Types
 
field :id, GraphQL::ID_TYPE,
null: false,
description: "ID (global ID) of the error"
description: 'ID (global ID) of the error'
field :sentry_id, GraphQL::STRING_TYPE,
method: :id,
null: false,
description: "ID (Sentry ID) of the error"
description: 'ID (Sentry ID) of the error'
field :title, GraphQL::STRING_TYPE,
null: false,
description: "Title of the error"
description: 'Title of the error'
field :type, GraphQL::STRING_TYPE,
null: false,
description: "Type of the error"
description: 'Type of the error'
field :user_count, GraphQL::INT_TYPE,
null: false,
description: "Count of users affected by the error"
description: 'Count of users affected by the error'
field :count, GraphQL::INT_TYPE,
null: false,
description: "Count of occurrences"
description: 'Count of occurrences'
field :first_seen, Types::TimeType,
null: false,
description: "Timestamp when the error was first seen"
description: 'Timestamp when the error was first seen'
field :last_seen, Types::TimeType,
null: false,
description: "Timestamp when the error was last seen"
description: 'Timestamp when the error was last seen'
field :message, GraphQL::STRING_TYPE,
null: true,
description: "Sentry metadata message of the error"
description: 'Sentry metadata message of the error'
field :culprit, GraphQL::STRING_TYPE,
null: false,
description: "Culprit of the error"
description: 'Culprit of the error'
field :external_base_url, GraphQL::STRING_TYPE,
null: false,
description: 'External Base URL of the Sentry Instance'
field :external_url, GraphQL::STRING_TYPE,
null: false,
description: "External URL of the error"
description: 'External URL of the error'
field :sentry_project_id, GraphQL::ID_TYPE,
method: :project_id,
null: false,
description: "ID of the project (Sentry project)"
description: 'ID of the project (Sentry project)'
field :sentry_project_name, GraphQL::STRING_TYPE,
method: :project_name,
null: false,
description: "Name of the project affected by the error"
description: 'Name of the project affected by the error'
field :sentry_project_slug, GraphQL::STRING_TYPE,
method: :project_slug,
null: false,
description: "Slug of the project affected by the error"
description: 'Slug of the project affected by the error'
field :short_id, GraphQL::STRING_TYPE,
null: false,
description: "Short ID (Sentry ID) of the error"
description: 'Short ID (Sentry ID) of the error'
field :status, Types::ErrorTracking::SentryErrorStatusEnum,
null: false,
description: "Status of the error"
description: 'Status of the error'
field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType],
null: false,
description: "Last 24hr stats of the error"
description: 'Last 24hr stats of the error'
field :first_release_last_commit, GraphQL::STRING_TYPE,
null: true,
description: "Commit the error was first seen"
description: 'Commit the error was first seen'
field :last_release_last_commit, GraphQL::STRING_TYPE,
null: true,
description: "Commit the error was last seen"
description: 'Commit the error was last seen'
field :first_release_short_version, GraphQL::STRING_TYPE,
null: true,
description: "Release version the error was first seen"
description: 'Release version the error was first seen'
field :last_release_short_version, GraphQL::STRING_TYPE,
null: true,
description: "Release version the error was last seen"
description: 'Release version the error was last seen'
field :gitlab_commit, GraphQL::STRING_TYPE,
null: true,
description: "GitLab commit SHA attributed to the Error based on the release version"
description: 'GitLab commit SHA attributed to the Error based on the release version'
field :gitlab_commit_path, GraphQL::STRING_TYPE,
null: true,
description: "Path to the GitLab page for the GitLab commit attributed to the error"
description: 'Path to the GitLab page for the GitLab commit attributed to the error'
field :gitlab_issue_path, GraphQL::STRING_TYPE,
method: :gitlab_issue,
null: true,
description: 'URL of GitLab Issue'
field :tags, Types::ErrorTracking::SentryErrorTagsType,
null: false,
description: 'Tags associated with the Sentry Error'
 
def first_seen
DateTime.parse(object.first_seen)
Loading
Loading
# frozen_string_literal: true
module Types
module ErrorTracking
# rubocop: disable Graphql/AuthorizeTypes
class SentryErrorTagsType < ::Types::BaseObject
graphql_name 'SentryErrorTags'
description 'State of a Sentry error'
field :level, GraphQL::STRING_TYPE,
null: true,
description: "Severity level of the Sentry Error"
field :logger, GraphQL::STRING_TYPE,
null: true,
description: "Logger of the Sentry Error"
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
Loading
Loading
@@ -47,7 +47,7 @@ module BlobHelper
def edit_blob_button(project = @project, ref = @ref, path = @path, options = {})
return unless blob = readable_blob(options, path, project, ref)
 
common_classes = "btn btn-primary js-edit-blob #{options[:extra_class]}"
common_classes = "btn btn-primary js-edit-blob ml-2 #{options[:extra_class]}"
 
edit_button_tag(blob,
common_classes,
Loading
Loading
@@ -62,7 +62,7 @@ module BlobHelper
return unless blob = readable_blob(options, path, project, ref)
 
edit_button_tag(blob,
'btn btn-inverted btn-primary ide-edit-button',
'btn btn-inverted btn-primary ide-edit-button ml-2',
_('Web IDE'),
ide_edit_path(project, ref, path, options),
project,
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ module Clusters
module Applications
class Ingress < ApplicationRecord
VERSION = '1.22.1'
MODSECURITY_LOG_CONTAINER_NAME = 'modsecurity-log'
 
self.table_name = 'clusters_applications_ingress'
 
Loading
Loading
@@ -85,7 +86,7 @@ module Clusters
},
"extraContainers" => [
{
"name" => "modsecurity-log",
"name" => MODSECURITY_LOG_CONTAINER_NAME,
"image" => "busybox",
"args" => [
"/bin/sh",
Loading
Loading
Loading
Loading
@@ -1938,6 +1938,8 @@ class Project < ApplicationRecord
.append(key: 'GITLAB_CI', value: 'true')
.append(key: 'CI_SERVER_URL', value: Gitlab.config.gitlab.url)
.append(key: 'CI_SERVER_HOST', value: Gitlab.config.gitlab.host)
.append(key: 'CI_SERVER_PORT', value: Gitlab.config.gitlab.port.to_s)
.append(key: 'CI_SERVER_PROTOCOL', value: Gitlab.config.gitlab.protocol)
.append(key: 'CI_SERVER_NAME', value: 'GitLab')
.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
.append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s)
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