Commit 854f7123 authored by Luke Bennett's avatar Luke Bennett

Merge remote-tracking branch 'origin/master' into move-plan-badge-groups-scss-to-ee-namespace

parents e7e2f82a 392227ee
......@@ -1190,7 +1190,22 @@ RSpec/SubjectStub:
RSpec/VerifiedDoubles:
Enabled: false
# GitlabSecurity ##############################################################
# Gitlab ###################################################################
Gitlab/ModuleWithInstanceVariables:
Enable: true
Exclude:
# We ignore Rails helpers right now because it's hard to workaround it
- app/helpers/**/*_helper.rb
- ee/app/helpers/**/*_helper.rb
# We ignore Rails mailers right now because it's hard to workaround it
- app/mailers/emails/**/*.rb
- ee/**/emails/**/*.rb
# We ignore spec helpers because it usually doesn't matter
- spec/support/**/*.rb
- features/steps/**/*.rb
# GitlabSecurity ###########################################################
GitlabSecurity/DeepMunge:
Enabled: true
......
......@@ -323,7 +323,7 @@ group :development, :test do
gem 'fuubar', '~> 2.2.0'
gem 'database_cleaner', '~> 1.5.0'
gem 'factory_girl_rails', '~> 4.7.0'
gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.6.0'
gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1'
......
......@@ -216,10 +216,10 @@ GEM
excon (0.57.1)
execjs (2.6.0)
expression_parser (0.9.0)
factory_girl (4.7.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
factory_girl_rails (4.7.0)
factory_girl (~> 4.7.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
......@@ -1054,7 +1054,7 @@ DEPENDENCIES
elasticsearch-rails (~> 0.1.9)
email_reply_trimmer (~> 0.1)
email_spec (~> 1.6.0)
factory_girl_rails (~> 4.7.0)
factory_bot_rails (~> 4.8.2)
faraday (~> 0.12)
faraday_middleware-aws-signers-v4
ffaker (~> 2.4)
......
......@@ -3,7 +3,7 @@ import axios from 'axios';
import SmartInterval from '~/smart_interval';
import { s__ } from '~/locale';
import { parseSeconds, stringifyTime } from './lib/utils/pretty_time';
import { timeIntervalInWords } from './lib/utils/datetime_utility';
import { formatDate, timeIntervalInWords } from './lib/utils/datetime_utility';
import timeago from './vue_shared/mixins/timeago';
const healthyClass = 'geo-node-healthy';
......@@ -115,7 +115,7 @@ class GeoNodeStatus {
let eventDate = notAvailable;
if (eventTimestamp && eventTimestamp > 0) {
eventDate = gl.utils.formatDate(new Date(eventTimestamp * 1000));
eventDate = formatDate(new Date(eventTimestamp * 1000));
}
if (eventId) {
......
......@@ -24,11 +24,11 @@ module BoardsResponses
end
def respond_with_boards
respond_with(@boards)
respond_with(@boards) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def respond_with_board
respond_with(@board)
respond_with(@board) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def respond_with(resource)
......
module CreatesCommit
extend ActiveSupport::Concern
include Gitlab::Utils::StrongMemoize
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
if can?(current_user, :push_code, @project)
@project_to_commit_into = @project
......@@ -45,6 +47,7 @@ module CreatesCommit
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def authorize_edit_tree!
return if can_collaborate_with_project?
......@@ -77,6 +80,7 @@ module CreatesCommit
end
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def new_merge_request_path
project_new_merge_request_path(
@project_to_commit_into,
......@@ -88,20 +92,28 @@ module CreatesCommit
}
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def existing_merge_request_path
project_merge_request_path(@project, @merge_request)
project_merge_request_path(@project, @merge_request) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def merge_request_exists?
return @merge_request if defined?(@merge_request)
@merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened
.find_by(source_project_id: @project_to_commit_into, source_branch: @branch_name, target_branch: @start_branch)
strong_memoize(:merge_request) do
MergeRequestsFinder.new(current_user, project_id: @project.id)
.execute
.opened
.find_by(
source_project_id: @project_to_commit_into,
source_branch: @branch_name,
target_branch: @start_branch)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def different_project?
@project_to_commit_into != @project
@project_to_commit_into != @project # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def create_merge_request?
......@@ -109,6 +121,6 @@ module CreatesCommit
# as the target branch in the same project,
# we don't want to create a merge request.
params[:create_merge_request].present? &&
(different_project? || @start_branch != @branch_name)
(different_project? || @start_branch != @branch_name) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
module GroupTree
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def render_group_tree(groups)
@groups = if params[:filter].present?
Gitlab::GroupHierarchy.new(groups.search(params[:filter]))
......@@ -20,5 +21,6 @@ module GroupTree
render json: serializer.represent(@groups)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
end
......@@ -17,7 +17,7 @@ module IssuableActions
end
def update
@issuable = update_service.execute(issuable)
@issuable = update_service.execute(issuable) # rubocop:disable Gitlab/ModuleWithInstanceVariables
respond_to do |format|
format.html do
......@@ -81,7 +81,7 @@ module IssuableActions
private
def recaptcha_check_if_spammable(should_redirect = true, &block)
return yield unless @issuable.is_a? Spammable
return yield unless issuable.is_a? Spammable
recaptcha_check_with_fallback(should_redirect, &block)
end
......@@ -89,7 +89,7 @@ module IssuableActions
def render_conflict_response
respond_to do |format|
format.html do
@conflict = true
@conflict = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
render :edit
end
......@@ -104,7 +104,7 @@ module IssuableActions
end
def labels
@labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
@labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def authorize_destroy_issuable!
......@@ -114,7 +114,7 @@ module IssuableActions
end
def authorize_admin_issuable!
unless can?(current_user, :"admin_#{resource_name}", @project)
unless can?(current_user, :"admin_#{resource_name}", @project) # rubocop:disable Gitlab/ModuleWithInstanceVariables
return access_denied!
end
end
......@@ -149,6 +149,7 @@ module IssuableActions
@resource_name ||= controller_name.singularize
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def render_entity_json
if @issuable.valid?
render json: serializer.represent(@issuable)
......@@ -156,6 +157,7 @@ module IssuableActions
render json: { errors: @issuable.errors.full_messages }, status: :unprocessable_entity
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def serializer
raise NotImplementedError
......@@ -166,6 +168,6 @@ module IssuableActions
end
def parent
@project || @group
@project || @group # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
......@@ -2,6 +2,7 @@ module IssuableCollections
extend ActiveSupport::Concern
include SortingHelper
include Gitlab::IssuableMetadata
include Gitlab::Utils::StrongMemoize
included do
helper_method :finder
......@@ -9,6 +10,7 @@ module IssuableCollections
private
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def set_issuables_index
@issuables = issuables_collection
@issuables = @issuables.page(params[:page])
......@@ -33,6 +35,7 @@ module IssuableCollections
@users.push(author) if author
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def issuables_collection
finder.execute.preload(preload_for_collection)
......@@ -41,7 +44,7 @@ module IssuableCollections
def redirect_out_of_range(total_pages)
return false if total_pages.zero?
out_of_range = @issuables.current_page > total_pages
out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables
if out_of_range
redirect_to(url_for(params.merge(page: total_pages, only_path: true)))
......@@ -51,7 +54,7 @@ module IssuableCollections
end
def issuable_page_count
page_count_for_relation(@issuables, finder.row_count)
page_count_for_relation(@issuables, finder.row_count) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def page_count_for_relation(relation, row_count)
......@@ -66,6 +69,7 @@ module IssuableCollections
finder_class.new(current_user, filter_params)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def filter_params
set_sort_order_from_cookie
set_default_state
......@@ -90,6 +94,7 @@ module IssuableCollections
@filter_params.permit(IssuableFinder::VALID_PARAMS)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def set_default_state
params[:state] = 'opened' if params[:state].blank?
......@@ -131,9 +136,9 @@ module IssuableCollections
end
def finder
return @finder if defined?(@finder)
@finder = issuable_finder_for(@finder_type)
strong_memoize(:finder) do
issuable_finder_for(@finder_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
def collection_type
......
......@@ -2,6 +2,7 @@ module IssuesAction
extend ActiveSupport::Concern
include IssuableCollections
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues
@finder_type = IssuesFinder
@label = finder.labels.first
......@@ -17,4 +18,5 @@ module IssuesAction
format.atom { render layout: 'xml.atom' }
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
......@@ -2,6 +2,7 @@ module MergeRequestsAction
extend ActiveSupport::Concern
include IssuableCollections
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def merge_requests
@finder_type = MergeRequestsFinder
@label = finder.labels.first
......@@ -10,6 +11,7 @@ module MergeRequestsAction
@issuable_meta_data = issuable_meta_data(@merge_requests, collection_type)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
......
......@@ -6,7 +6,7 @@ module MilestoneActions
format.html { redirect_to milestone_redirect_path }
format.json do
render json: tabs_json("shared/milestones/_merge_requests_tab", {
merge_requests: @milestone.sorted_merge_requests,
merge_requests: @milestone.sorted_merge_requests, # rubocop:disable Gitlab/ModuleWithInstanceVariables
show_project_name: true
})
end
......@@ -18,7 +18,7 @@ module MilestoneActions
format.html { redirect_to milestone_redirect_path }
format.json do
render json: tabs_json("shared/milestones/_participants_tab", {
users: @milestone.participants
users: @milestone.participants # rubocop:disable Gitlab/ModuleWithInstanceVariables
})
end
end
......@@ -29,7 +29,7 @@ module MilestoneActions
format.html { redirect_to milestone_redirect_path }
format.json do
render json: tabs_json("shared/milestones/_labels_tab", {
labels: @milestone.labels
labels: @milestone.labels # rubocop:disable Gitlab/ModuleWithInstanceVariables
})
end
end
......@@ -43,6 +43,7 @@ module MilestoneActions
}
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def milestone_redirect_path
if @project
project_milestone_path(@project, @milestone)
......@@ -52,4 +53,5 @@ module MilestoneActions
dashboard_milestone_path(@milestone.safe_title, title: @milestone.title)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
module NotesActions
include RendersNotes
include Gitlab::Utils::StrongMemoize
extend ActiveSupport::Concern
included do
......@@ -30,6 +31,7 @@ module NotesActions
render json: notes_json
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def create
create_params = note_params.merge(
merge_request_diff_head_sha: params[:merge_request_diff_head_sha],
......@@ -47,7 +49,9 @@ module NotesActions
format.html { redirect_back_or_default }
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
......@@ -60,6 +64,7 @@ module NotesActions
format.html { redirect_back_or_default }
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def destroy
if note.editable?
......@@ -138,7 +143,7 @@ module NotesActions
end
else
template = "discussions/_diff_discussion"
@fresh_discussion = true
@fresh_discussion = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
locals = { discussions: [discussion], on_image: on_image }
end
......@@ -191,7 +196,7 @@ module NotesActions
end
def noteable
@noteable ||= notes_finder.target || @note&.noteable
@noteable ||= notes_finder.target || @note&.noteable # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def require_noteable!
......@@ -211,20 +216,21 @@ module NotesActions
end
def note_project
return @note_project if defined?(@note_project)
return nil unless project
strong_memoize(:note_project) do
return nil unless project
note_project_id = params[:note_project_id]
note_project_id = params[:note_project_id]
@note_project =
if note_project_id.present?
Project.find(note_project_id)
else
project
end
the_project =
if note_project_id.present?
Project.find(note_project_id)
else
project
end
return access_denied! unless can?(current_user, :create_note, @note_project)
return access_denied! unless can?(current_user, :create_note, the_project)
@note_project
the_project
end
end
end
......@@ -14,6 +14,6 @@ module OauthApplications
end
def load_scopes
@scopes = Doorkeeper.configuration.scopes
@scopes ||= Doorkeeper.configuration.scopes
end
end
module PreviewMarkdown
extend ActiveSupport::Concern
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def preview_markdown
result = PreviewMarkdownService.new(@project, current_user, params).execute
......@@ -20,4 +21,5 @@ module PreviewMarkdown
}
}
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
module RendersCommits
def prepare_commits_for_rendering(commits)
Banzai::CommitRenderer.render(commits, @project, current_user)
Banzai::CommitRenderer.render(commits, @project, current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
commits
end
......
module RendersNotes
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def prepare_notes_for_rendering(notes, noteable = nil)
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
......@@ -7,6 +8,7 @@ module RendersNotes
notes
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
......
......@@ -67,7 +67,7 @@ module ServiceParams
FILTER_BLANK_PARAMS = [:password].freeze
def service_params
dynamic_params = @service.event_channel_names + @service.event_names
dynamic_params = @service.event_channel_names + @service.event_names # rubocop:disable Gitlab/ModuleWithInstanceVariables
service_params = params.permit(:id, service: allowed_service_params + dynamic_params)
if service_params[:service].is_a?(Hash)
......
......@@ -4,6 +4,7 @@ module SnippetsActions
def edit
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def raw
disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
......@@ -14,6 +15,7 @@ module SnippetsActions
filename: @snippet.sanitized_file_name
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
......
......@@ -2,6 +2,7 @@ module SpammableActions
extend ActiveSupport::Concern
include Recaptcha::Verify
include Gitlab::Utils::StrongMemoize
included do
before_action :authorize_submit_spammable!, only: :mark_as_spam
......@@ -18,9 +19,9 @@ module SpammableActions
private
def ensure_spam_config_loaded!
return @spam_config_loaded if defined?(@spam_config_loaded)
@spam_config_loaded = Gitlab::Recaptcha.load_configurations!
strong_memoize(:spam_config_loaded) do
Gitlab::Recaptcha.load_configurations!
end
end
def recaptcha_check_with_fallback(should_redirect = true, &fallback)
......
......@@ -12,7 +12,7 @@ module ToggleSubscriptionAction
private
def subscribable_project
@project || raise(NotImplementedError)
@project ||= raise(NotImplementedError)
end
def subscribable_resource
......
......@@ -11,7 +11,7 @@ class Projects::NotesController < Projects::ApplicationController
# Controller actions are returned from AbstractController::Base and methods of parent classes are
# excluded in order to return only specific controller related methods.
# That is ok for the app (no :create method in ancestors)
# but fails for tests because there is a :create method on FactoryGirl (one of the ancestors)
# but fails for tests because there is a :create method on FactoryBot (one of the ancestors)
#
# see https://github.com/rails/rails/blob/v4.2.7/actionpack/lib/abstract_controller/base.rb#L78
#
......
class AuditEvent < ActiveRecord::Base
prepend EE::AuditEvent
include Gitlab::Utils::StrongMemoize
serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
......
......@@ -44,13 +44,11 @@ module Mentionable
end
def all_references(current_user = nil, extractor: nil)
@extractors ||= {}
# Use custom extractor if it's passed in the function parameters.
if extractor
@extractors[current_user] = extractor
extractors[current_user] = extractor
else
extractor = @extractors[current_user] ||= Gitlab::ReferenceExtractor.new(project, current_user)
extractor = extractors[current_user] ||= Gitlab::ReferenceExtractor.new(project, current_user)
extractor.reset_memoized_values
end
......@@ -69,6 +67,10 @@ module Mentionable
extractor
end
def extractors
@extractors ||= {}
end
def mentioned_users(current_user = nil)
all_references(current_user).users
end
......
......@@ -103,9 +103,11 @@ module Milestoneish
end
def memoize_per_user(user, method_name)
@memoized ||= {}
@memoized[method_name] ||= {}
@memoized[method_name][user&.id] ||= yield
memoized_users[method_name][user&.id] ||= yield
end
def memoized_users
@memoized_users ||= Hash.new { |h, k| h[k] = {} }
end
# override in a class that includes this module to get a faster query
......
......@@ -46,6 +46,7 @@ module Noteable
notes.inc_relations_for_view.grouped_diff_discussions(*args)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def resolvable_discussions
@resolvable_discussions ||=
if defined?(@discussions)
......@@ -54,6 +55,7 @@ module Noteable
discussion_notes.resolvable.discussions(self)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def discussions_resolvable?
resolvable_discussions.any?(&:resolvable?)
......
......@@ -56,15 +56,17 @@ module Participable
#
# Returns an Array of User instances.
def participants(current_user = nil)
@participants ||= Hash.new do |hash, user|
hash[user] = raw_participants(user)
end
@participants[current_user]
all_participants[current_user]
end
private
def all_participants
@all_participants ||= Hash.new do |hash, user|
hash[user] = raw_participants(user)
end
end
def raw_participants(current_user = nil)
current_user ||= author
ext = Gitlab::ReferenceExtractor.new(project, current_user)
......
......@@ -52,7 +52,7 @@ module RelativePositioning
# to its predecessor. This process will recursively move all the predecessors until we have a place
if (after.relative_position - before.relative_position) < 2
before.move_before
@positionable_neighbours = [before]
@positionable_neighbours = [before] # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
self.relative_position = position_between(before.relative_position, after.relative_position)
......@@ -65,7 +65,7 @@ module RelativePositioning
if before.shift_after?
issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_after)
issue_to_move.move_after
@positionable_neighbours = [issue_to_move]
@positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
pos_after = issue_to_move.relative_position
end
......@@ -80,7 +80,7 @@ module RelativePositioning
if after.shift_before?
issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_before)
issue_to_move.move_before
@positionable_neighbours = [issue_to_move]
@positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
pos_before = issue_to_move.relative_position
end
......@@ -132,6 +132,7 @@ module RelativePositioning
end
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def save_positionable_neighbours
return unless @positionable_neighbours
......@@ -140,4 +141,5 @@ module RelativePositioning
status
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
......@@ -31,15 +31,11 @@ module ResolvableDiscussion
end
def resolvable?
return @resolvable if @resolvable.present?
@resolvable = potentially_resolvable? && notes.any?(&:resolvable?)
@resolvable ||= potentially_resolvable? && notes.any?(&:resolvable?)
end
def resolved?
return @resolved if @resolved.present?
@resolved = resolvable? && notes.none?(&:to_be_resolved?)
@resolved ||= resolvable? && notes.none?(&:to_be_resolved?)
end
def first_note
......@@ -49,13 +45,13 @@ module ResolvableDiscussion
def first_note_to_resolve
return unless resolvable?
@first_note_to_resolve ||= notes.find(&:to_be_resolved?)
@first_note_to_resolve ||= notes.find(&:to_be_resolved?) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def last_resolved_note
return unless resolved?
@last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last
@last_resolved_note ||= resolved_notes.sort_by(&:resolved_at).last # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def resolved_notes
......@@ -95,7 +91,7 @@ module ResolvableDiscussion
yield(notes_relation)
# Set the notes array to the updated notes
@notes = notes_relation.fresh.to_a
@notes = notes_relation.fresh.to_a # rubocop:disable Gitlab/ModuleWithInstanceVariables
self.class.memoized_values.each do |var|
instance_variable_set(:"@#{var}", nil)
......
......@@ -88,7 +88,7 @@ module Routable
def full_name
if route && route.name.present?
@full_name ||= route.name
@full_name ||= route.name # rubocop:disable Gitlab/ModuleWithInstanceVariables
else
update_route if persisted?
......@@ -112,7 +112,7 @@ module Routable
def expires_full_path_cache
RequestStore.delete(full_path_key) if RequestStore.active?
@full_path = nil
@full_path = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def build_full_path
......@@ -127,7 +127,7 @@ module Routable
def uncached_full_path
if route && route.path.present?
@full_path ||= route.path
@full_path ||= route.path # rubocop:disable Gitlab/ModuleWithInstanceVariables
else
update_route if persisted?
......@@ -166,7 +166,7 @@ module Routable
route || build_route(source: self)
route.path = build_full_path
route.name = build_full_name
@full_path = nil
@full_name = nil
@full_path = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
@full_name = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
......@@ -12,6 +12,7 @@ module Spammable
attr_accessor :spam
attr_accessor :spam_log
alias_method :spam?, :spam
after_validation :check_for_spam, on: [:create, :update]
......@@ -34,10 +35,6 @@ module Spammable
end
end
def spam?
@spam
end
def check_for_spam
error_msg = if Gitlab::Recaptcha.enabled?
"Your #{spammable_entity_type} has been recognized as spam. "\
......
......@@ -39,7 +39,7 @@ module Taskable
def task_list_items
return [] if description.blank?
@task_list_items ||= Taskable.get_tasks(description)
@task_list_items ||= Taskable.get_tasks(description) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def tasks
......
......@@ -21,6 +21,7 @@ module TimeTrackable
has_many :timelogs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def spend_time(options)
@time_spent = options[:duration]
@time_spent_user = options[:user]
......@@ -36,6 +37,7 @@ module TimeTrackable
end
end
alias_method :spend_time=, :spend_time
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def total_time_spent
timelogs.sum(:time_spent)
......@@ -52,9 +54,10 @@ module TimeTrackable
private
def reset_spent_time
timelogs.new(time_spent: total_time_spent * -1, user: @time_spent_user)
timelogs.new(time_spent: total_time_spent * -1, user: @time_spent_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def add_or_subtract_spent_time
timelogs.new(
time_spent: time_spent,
......@@ -62,16 +65,19 @@ module TimeTrackable
spent_at: @spent_at
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def check_negative_time_spent
return if time_spent.nil? || time_spent == :reset
# we need to cache the total time spent so multiple calls to #valid?
# doesn't give a false error
@original_total_time_spent ||= total_time_spent
if time_spent < 0 && (time_spent.abs > @original_total_time_spent)
if time_spent < 0 && (time_spent.abs > original_total_time_spent)
errors.add(:time_spent, 'Time to subtract exceeds the total time spent')
end
end
# we need to cache the total time spent so multiple calls to #valid?
# doesn't give a false error
def original_total_time_spent
@original_total_time_spent ||= total_time_spent
end
end
......@@ -14,7 +14,7 @@ module WithPagination
# we shouldn't try to paginate single resources
def represent(resource, opts = {})
if paginated? && resource.respond_to?(:page)
super(@paginator.paginate(resource), opts)
super(paginator.paginate(resource), opts)
else
super(resource, opts)
end
......
module Issues
module ResolveDiscussions
include Gitlab::Utils::StrongMemoize
attr_reader :merge_request_to_resolve_discussions_of_iid, :discussion_to_resolve_id
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def filter_resolve_discussion_params
@merge_request_to_resolve_discussions_of_iid ||= params.delete(:merge_request_to_resolve_discussions_of)
@discussion_to_resolve_id ||= params.delete(:discussion_to_resolve)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def merge_request_to_resolve_discussions_of
return @merge_request_to_resolve_discussions_of if defined?(@merge_request_to_resolve_discussions_of)
@merge_request_to_resolve_discussions_of = MergeRequestsFinder.new(current_user, project_id: project.id)
.execute
.find_by(iid: merge_request_to_resolve_discussions_of_iid)
strong_memoize(:merge_request_to_resolve_discussions_of) do
MergeRequestsFinder.new(current_user, project_id: project.id)
.execute
.find_by(iid: merge_request_to_resolve_discussions_of_iid)
end
end
def discussions_to_resolve
return [] unless merge_request_to_resolve_discussions_of
@discussions_to_resolve ||=
@discussions_to_resolve ||= # rubocop:disable Gitlab/ModuleWithInstanceVariables
if discussion_to_resolve_id
discussion_or_nil = merge_request_to_resolve_discussions_of
.find_discussion(discussion_to_resolve_id)
......
......@@ -7,16 +7,19 @@
# - params with :request
#
module SpamCheckService
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def filter_spam_check_params
@request = params.delete(:request)
@api = params.delete(:api)
@recaptcha_verified = params.delete(:recaptcha_verified)
@spam_log_id = params.delete(:spam_log_id)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# In order to be proceed to the spam check process, @spammable has to be
# a dirty instance, which means it should be already assigned with the new
# attribute values.
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def spam_check(spammable, user)
spam_service = SpamService.new(spammable, @request)
......@@ -24,4 +27,5 @@ module SpamCheckService
user.spam_logs.find_by(id: @spam_log_id)&.update!(recaptcha_verified: true)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
%div
- if current_application_settings.help_text.present?
= markdown(current_application_settings.help_text)
- if current_application_settings.help_page_text.present?
= markdown(current_application_settings.help_page_text)
%hr
- unless current_application_settings.help_page_hide_commercial_content?
......
......@@ -9,15 +9,15 @@ module NewIssuable
end
def set_user(user_id)
@user = User.find_by(id: user_id)
@user = User.find_by(id: user_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables
log_error(User, user_id) unless @user
log_error(User, user_id) unless @user # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def set_issuable(issuable_id)
@issuable = issuable_class.find_by(id: issuable_id)
@issuable = issuable_class.find_by(id: issuable_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables
log_error(issuable_class, issuable_id) unless @issuable
log_error(issuable_class, issuable_id) unless @issuable # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def log_error(record_class, record_id)
......
---
title: 'Geo: Added Authorized Keys specific checks'
merge_request: 3728
author:
type: added
---
title: Import some code and functionality from gitlab-shell to improve subprocess
handling
merge_request:
author:
type: other
......@@ -180,7 +180,7 @@ module Gitlab
config.middleware.insert_after ActionDispatch::Flash, 'Gitlab::Middleware::ReadOnly'
config.generators do |g|
g.factory_girl false
g.factory_bot false
end
config.after_initialize do
......
......@@ -10,8 +10,8 @@ module Prependable
super
base.singleton_class.send(:prepend, const_get('ClassMethods')) if const_defined?(:ClassMethods)
@_dependencies.each { |dep| base.send(:prepend, dep) }
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
@_dependencies.each { |dep| base.send(:prepend, dep) } # rubocop:disable Gitlab/ModuleWithInstanceVariables
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
end
......
......@@ -6,7 +6,7 @@ module LocalCacheRegistryCleanupWithEnsure
def call(env)
LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
response = @app.call(env)
response = @app.call(env) # rubocop:disable Gitlab/ModuleWithInstanceVariables
response[2] = ::Rack::BodyProxy.new(response[2]) do
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
end
......
......@@ -19,10 +19,10 @@ module RspecProfilingExt
def example_finished(*args)
super
rescue => err
return if @already_logged_example_finished_error
return if @already_logged_example_finished_error # rubocop:disable Gitlab/ModuleWithInstanceVariables
$stderr.puts "rspec_profiling couldn't collect an example: #{err}. Further warnings suppressed."
@already_logged_example_finished_error = true
@already_logged_example_finished_error = true # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
alias_method :example_passed, :example_finished
......
......@@ -15,8 +15,11 @@ module Rugged
class Repository
module UseGitlabGitAttributes
def fetch_attributes(name, *)
attributes.attributes(name)
end
def attributes
@attributes ||= Gitlab::Git::Attributes.new(path)
@attributes.attributes(name)
end
end
......
......@@ -140,8 +140,8 @@ class Gitlab::Seeder::CycleAnalytics
issue.update(milestone: @project.milestones.sample)
else
label_name = "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}"
list_label = FactoryGirl.create(:label, title: label_name, project: issue.project)
FactoryGirl.create(:list, board: FactoryGirl.create(:board, project: issue.project), label: list_label)
list_label = FactoryBot.create(:label, title: label_name, project: issue.project)
FactoryBot.create(:list, board: FactoryBot.create(:board, project: issue.project), label: list_label)
issue.update(labels: [list_label])
end
......
......@@ -107,6 +107,7 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
- [Work In Progress Merge Requests](user/project/merge_requests/work_in_progress_merge_requests.md)
- [Merge Request discussion resolution](user/discussions/index.md#moving-a-single-discussion-to-a-new-issue): Resolve discussions, move discussions in a merge request to an issue, only allow merge requests to be merged if all discussions are resolved.
- **(EES/EEP)** [Merge Request approval](user/project/merge_requests/merge_request_approvals.md): Make sure every merge request is approved by one or more people before getting merged.
- **(EEU)** [Static Application Security Testing](user/project/merge_requests/sast.md): Scan your code for vulnerabilities and display the results in merge requests.
- [Checkout merge requests locally](user/project/merge_requests/index.md#checkout-merge-requests-locally)
- [Cherry-pick](user/project/merge_requests/cherry_pick_changes.md)
- [Milestones](user/project/milestones/index.md): Organize issues and merge requests into a cohesive group, optionally setting a due date.
......
# Fast lookup of authorized SSH keys in the database
Regular SSH operations become slow as the number of users grows because OpenSSH
searches for a key to authorize a user via a linear search. In the worst case,
such as when the user is not authorized to access GitLab, OpenSSH will scan the
entire file to search for a key. This can take significant time and disk I/O,
which will delay users attempting to push or pull to a repository. Making
matters worse, if users add or remove keys frequently, the operating system may
not be able to cache the `authorized_keys` file, which causes the disk to be
accessed repeatedly.
GitLab Shell solves this by providing a way to authorize SSH users via a fast,
indexed lookup in the GitLab database. This page describes how to enable the fast
lookup of authorized SSH keys.
> **Warning:** OpenSSH version 6.9+ is required because
`AuthorizedKeysCommand` must be able to accept a fingerprint. These
instructions will break installations using older versions of OpenSSH, such as
those included with CentOS 6 as of September 2017. If you want to use this
feature for CentOS 6, follow [the instructions on how to build and install a custom OpenSSH package](#compiling-a-custom-version-of-openssh-for-centos-6) before continuing.
## Fast lookup is required for GitLab Geo
By default, GitLab manages an `authorized_keys` file, which contains all the
public SSH keys for users allowed to access GitLab. However, to maintain a
single source of truth, [Geo](../../gitlab-geo/README.md) needs to be configured to perform SSH fingerprint
lookups via database lookup.
As part of [setting up GitLab Geo](../../gitlab-geo/README.md#setup-instructions),
you will be required to follow the steps outlined below for both the primary and
secondary nodes, but note that the `Write to "authorized keys" file` checkbox
only needs to be unchecked on the primary node since it will be reflected
automatically on the secondary if database replication is working.
## Setting up fast lookup via GitLab Shell
GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup
to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to
check whether the user is authorized to access GitLab.
Create the directory `/opt/gitlab-shell` first:
```bash
sudo mkdir -p /opt/gitlab-shell
```
Create this file at `/opt/gitlab-shell/authorized_keys`:
```
#!/bin/bash
if [[ "$1" == "git" ]]; then
/opt/gitlab/embedded/service/gitlab-shell/bin/authorized_keys $2
fi
```
Set appropriate ownership and permissions:
```
sudo chown root:git /opt/gitlab-shell/authorized_keys
sudo chmod 0650 /opt/gitlab-shell/authorized_keys
```
Add the following to `/etc/ssh/sshd_config` or to `/assets/sshd_config` if you
are using Omnibus Docker:
```
AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
AuthorizedKeysCommandUser git
```
Reload OpenSSH:
```bash
# Debian or Ubuntu installations
sudo service ssh reload
# CentOS installations
sudo service sshd reload
```
Confirm that SSH is working by removing your user's SSH key in the UI, adding a
new one, and attempting to pull a repo.
> **Warning:** Do not disable writes until SSH is confirmed to be working
perfectly because the file will quickly become out-of-date.
In the case of lookup failures (which are not uncommon), the `authorized_keys`
file will still be scanned. So git SSH performance will still be slow for many
users as long as a large file exists.
You can disable any more writes to the `authorized_keys` file by unchecking
`Write to "authorized_keys" file` in the Application Settings of your GitLab
installation.
![Write to authorized keys setting](img/write_to_authorized_keys_setting.png)
Again, confirm that SSH is working by removing your user's SSH key in the UI,
adding a new one, and attempting to pull a repo.
Then you can backup and delete your `authorized_keys` file for best performance.
## How to go back to using the `authorized_keys` file
This is a brief overview. Please refer to the above instructions for more context.
1. [Rebuild the `authorized_keys` file](../raketasks/maintenance.md#rebuild-authorized_keys-file)
1. Enable writes to the `authorized_keys` file in Application Settings
1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config` or from `/assets/sshd_config` if you are using Omnibus Docker.
1. Reload sshd: `sudo service sshd reload`
1. Remove the `/opt/gitlab-shell/authorized_keys` file
## Compiling a custom version of OpenSSH for CentOS 6
Building a custom version of OpenSSH is not necessary for Ubuntu 16.04 users,
since Ubuntu 16.04 ships with OpenSSH 7.2.
It is also unnecessary for CentOS 7.4 users, as that version ships with
OpenSSH 7.4. If you are using CentOS 7.0 - 7.3, we strongly recommend that you
upgrade to CentOS 7.4 instead of following this procedure. This should be as
simple as running `yum update`.
CentOS 6 users must build their own OpenSSH package to enable SSH lookups via
the database. The following instructions can be used to build OpenSSH 7.5:
1. First, download the package and install the required packages:
```
sudo su -
cd /tmp
curl --remote-name https://mirrors.evowise.com/pub/OpenBSD/OpenSSH/portable/openssh-7.5p1.tar.gz
tar xzvf openssh-7.5p1.tar.gz
yum install rpm-build gcc make wget openssl-devel krb5-devel pam-devel libX11-devel xmkmf libXt-devel
```
3. Prepare the build by copying files to the right place:
```
mkdir -p /root/rpmbuild/{SOURCES,SPECS}
cp ./openssh-7.5p1/contrib/redhat/openssh.spec /root/rpmbuild/SPECS/
cp openssh-7.5p1.tar.gz /root/rpmbuild/SOURCES/
cd /root/rpmbuild/SPECS
```
3. Next, set the spec settings properly:
```
sed -i -e "s/%define no_gnome_askpass 0/%define no_gnome_askpass 1/g" openssh.spec
sed -i -e "s/%define no_x11_askpass 0/%define no_x11_askpass 1/g" openssh.spec
sed -i -e "s/BuildPreReq/BuildRequires/g" openssh.spec
```
3. Build the RPMs:
```
rpmbuild -bb openssh.spec
```
4. Ensure the RPMs were built:
```
ls -al /root/rpmbuild/RPMS/x86_64/
```
You should see something as the following:
```
total 1324
drwxr-xr-x. 2 root root 4096 Jun 20 19:37 .
drwxr-xr-x. 3 root root 19 Jun 20 19:37 ..
-rw-r--r--. 1 root root 470828 Jun 20 19:37 openssh-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 490716 Jun 20 19:37 openssh-clients-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 17020 Jun 20 19:37 openssh-debuginfo-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 367516 Jun 20 19:37 openssh-server-7.5p1-1.x86_64.rpm
```
5. Install the packages. OpenSSH packages will replace `/etc/pam.d/sshd`
with its own version, which may prevent users from logging in, so be sure
that the file is backed up and restored after installation:
```
timestamp=$(date +%s)
cp /etc/pam.d/sshd pam-ssh-conf-$timestamp
rpm -Uvh /root/rpmbuild/RPMS/x86_64/*.rpm
yes | cp pam-ssh-conf-$timestamp /etc/pam.d/sshd
```
6. Verify the installed version. In another window, attempt to login to the server:
```
ssh -v <your-centos-machine>
```
You should see a line that reads: "debug1: Remote protocol version 2.0, remote software version OpenSSH_7.5"
If not, you may need to restart sshd (e.g. `systemctl restart sshd.service`).
7. *IMPORTANT!* Open a new SSH session to your server before exiting to make
sure everything is working! If you need to downgrade, simple install the
older package:
```
# Only run this if you run into a problem logging in
yum downgrade openssh-server openssh openssh-clients
```
......@@ -15,5 +15,4 @@ that to prioritize important jobs.
to restart Sidekiq.
- **(EES/EEP)** [Extra Sidekiq operations](extra_sidekiq_processes.md): Configure an extra set of Sidekiq processes to ensure certain queues always have dedicated workers, no matter the amount of jobs that need to be processed.
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
- **(EES/EEP)** [Speed up SSH operations](speed_up_ssh.md): Authorize SSH users via a fast, indexed lookup to the GitLab database.
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
- **(EES/EEP)** [Speed up SSH operations](fast_ssh_key_lookup.md): Authorize SSH users via a fast, indexed lookup to the GitLab database.
# Speed up SSH operations
>
- [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/250) in GitLab Enterprise Edition 8.7.
- Available in GitLab Enterprise Edition Starter.
## The problem
SSH operations become slow as the number of users grows.
## The reason
OpenSSH searches for a key to authorize a user via a linear search. In the worst case, such as when the user is not authorized to access GitLab, OpenSSH will scan the entire file to search for a key. This can take significant time and disk I/O, which will delay users attempting to push or pull to a repository. Making matters worse, if users add or remove keys frequently, the operating system may not be able to cache the authorized_keys file, which causes the disk to be accessed repeatedly.
## The solution
GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to check whether the user is authorized to access GitLab.
> **Warning:** OpenSSH version 6.9+ is required because
`AuthorizedKeysCommand` must be able to accept a fingerprint. These
instructions will break installations using older versions of OpenSSH, such as
those included with CentOS 6 as of September 2017. If you want to use this
feature for CentOS 6, follow [the instructions on how to build and install a custom OpenSSH package]
(#compiling-a-custom-version-of-openssh-for-centos-6) before continuing.
Create the directory `/opt/gitlab-shell` first:
```bash
sudo mkdir -p /opt/gitlab-shell
```
Create this file at `/opt/gitlab-shell/authorized_keys`:
```
#!/bin/bash
if [[ "$1" == "git" ]]; then
/opt/gitlab/embedded/service/gitlab-shell/bin/authorized_keys $2
fi
```
Set appropriate ownership and permissions:
```
sudo chown root:git /opt/gitlab-shell/authorized_keys
sudo chmod 0650 /opt/gitlab-shell/authorized_keys
```
Add the following to `/etc/ssh/sshd_config` or to `/assets/sshd_config` if you are using Omnibus Docker:
```
AuthorizedKeysCommand /opt/gitlab-shell/authorized_keys %u %k
AuthorizedKeysCommandUser git
```
Reload OpenSSH:
```bash
# Debian or Ubuntu installations
sudo service ssh reload
# CentOS installations
sudo service sshd reload
```
Confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
> **Warning:** Do not disable writes until SSH is confirmed to be working perfectly because the file will quickly become out-of-date.
In the case of lookup failures (which are not uncommon), the `authorized_keys` file will still be scanned. So git SSH performance will still be slow for many users as long as a large file exists.
You can disable any more writes to the `authorized_keys` file by unchecking `Write to "authorized_keys" file` in the Application Settings of your GitLab installation.
![Write to authorized keys setting](img/write_to_authorized_keys_setting.png)
Again, confirm that SSH is working by removing your user's SSH key in the UI, adding a new one, and attempting to pull a repo.
Then you can backup and delete your `authorized_keys` file for best performance.
## How to go back to using the `authorized_keys` file
This is a brief overview. Please refer to the above instructions for more context.
1. [Rebuild the `authorized_keys` file](../raketasks/maintenance.md#rebuild-authorized_keys-file)
1. Enable writes to the `authorized_keys` file in Application Settings
1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config` or from `/assets/sshd_config` if you are using Omnibus Docker.
1. Reload sshd: `sudo service sshd reload`
1. Remove the `/opt/gitlab-shell/authorized_keys` file
## Compiling a custom version of OpenSSH for CentOS 6
Building a custom version of OpenSSH is not necessary for Ubuntu 16.04 users,
since Ubuntu 16.04 ships with OpenSSH 7.2.
It is also unnecessary for CentOS 7.4 users, as that version ships with
OpenSSH 7.4. If you are using CentOS 7.0 - 7.3, we strongly recommend that you
upgrade to CentOS 7.4 instead of following this procedure. This should be as
simple as running `yum update`.
CentOS 6 users must build their own OpenSSH package to enable SSH lookups via
the database. The following instructions can be used to build OpenSSH 7.5:
1. First, download the package and install the required packages:
```
sudo su -
cd /tmp
curl --remote-name https://mirrors.evowise.com/pub/OpenBSD/OpenSSH/portable/openssh-7.5p1.tar.gz
tar xzvf openssh-7.5p1.tar.gz
yum install rpm-build gcc make wget openssl-devel krb5-devel pam-devel libX11-devel xmkmf libXt-devel
```
3. Prepare the build by copying files to the right place:
```
mkdir -p /root/rpmbuild/{SOURCES,SPECS}
cp ./openssh-7.5p1/contrib/redhat/openssh.spec /root/rpmbuild/SPECS/
cp openssh-7.5p1.tar.gz /root/rpmbuild/SOURCES/
cd /root/rpmbuild/SPECS
```
3. Next, set the spec settings properly:
```
sed -i -e "s/%define no_gnome_askpass 0/%define no_gnome_askpass 1/g" openssh.spec
sed -i -e "s/%define no_x11_askpass 0/%define no_x11_askpass 1/g" openssh.spec
sed -i -e "s/BuildPreReq/BuildRequires/g" openssh.spec
```
3. Build the RPMs:
```
rpmbuild -bb openssh.spec
```
4. Ensure the RPMs were built:
```
ls -al /root/rpmbuild/RPMS/x86_64/
```
You should see something as the following:
```
total 1324
drwxr-xr-x. 2 root root 4096 Jun 20 19:37 .
drwxr-xr-x. 3 root root 19 Jun 20 19:37 ..
-rw-r--r--. 1 root root 470828 Jun 20 19:37 openssh-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 490716 Jun 20 19:37 openssh-clients-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 17020 Jun 20 19:37 openssh-debuginfo-7.5p1-1.x86_64.rpm
-rw-r--r--. 1 root root 367516 Jun 20 19:37 openssh-server-7.5p1-1.x86_64.rpm
```
5. Install the packages. OpenSSH packages will replace `/etc/pam.d/sshd`
with its own version, which may prevent users from logging in, so be sure
that the file is backed up and restored after installation:
```
timestamp=$(date +%s)
cp /etc/pam.d/sshd pam-ssh-conf-$timestamp
rpm -Uvh /root/rpmbuild/RPMS/x86_64/*.rpm
yes | cp pam-ssh-conf-$timestamp /etc/pam.d/sshd
```
6. Verify the installed version. In another window, attempt to login to the server:
```
ssh -v <your-centos-machine>
```
You should see a line that reads: "debug1: Remote protocol version 2.0, remote software version OpenSSH_7.5"
If not, you may need to restart sshd (e.g. `systemctl restart sshd.service`).
7. *IMPORTANT!* Open a new SSH session to your server before exiting to make
sure everything is working! If you need to downgrade, simple install the
older package:
```
# Only run this if you run into a problem logging in
yum downgrade openssh-server openssh openssh-clients
```
This document was moved to [another location](fast_ssh_key_lookup.md).
......@@ -366,16 +366,16 @@ POST /groups
Parameters:
- `name` (required) - The name of the group
- `path` (required) - The path of the group
- `description` (optional) - The group's description
- `membership_lock` (optional, boolean) - Prevent adding new members to project membership within this group
- `share_with_group_lock` (optional, boolean) - Prevent sharing a project with another group within this group
- `visibility` (optional) - The group's visibility. Can be `private`, `internal`, or `public`.
- `lfs_enabled` (optional) - Enable/disable Large File Storage (LFS) for the projects in this group
- `request_access_enabled` (optional) - Allow users to request member access.
- `parent_id` (optional) - The parent group id for creating nested group.
- `shared_runners_minutes_limit` (optional) - (admin-only) Pipeline minutes quota for this group
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `name` | string | yes | The name of the group |
| `path` | string | yes | The path of the group |
| `description` | string | no | The group's description |
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group |
| `request_access_enabled` | boolean | no | Allow users to request member access. |
| `parent_id` | integer | no | The parent group id for creating nested group. |
| `shared_runners_minutes_limit` | integer | no | (admin-only) Pipeline minutes quota for this group. |
## Transfer project to group
......@@ -387,8 +387,10 @@ POST /groups/:id/projects/:project_id
Parameters:
- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `project_id` (required) - The ID or path of a project
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
## Update group
......
......@@ -58,6 +58,10 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Analyze code quality with the Code Climate CLI](code_climate.md)
### Static Application Security Testing (SAST)
- [Scan your code for vulnerabilities](sast.md)
### Other
- [Using `dpl` as deployment tool](deployment/README.md)
......
# Static application security testing with GitLab CI/CD
NOTE: **Note:**
In order to use this tool, a [GitLab Enterprise Edition Ultimate][ee] license
is needed.
This example shows how to run
[Static Application Security Testing (SAST)](https://en.wikipedia.org/wiki/Static_program_analysis)
on your project's source code by using GitLab CI/CD.
All you need is a GitLab Runner with the Docker executor (the shared Runners on
GitLab.com will work fine). You can then add a new job to `.gitlab-ci.yml`,
called `sast`:
```yaml
sast:
image: registry.gitlab.com/gitlab-org/gl-sast:latest
script:
- /app/bin/run .
artifacts:
paths: [gl-sast-report.json]
```
Behind the scenes, the [gl-sast Docker image](https://gitlab.com/gitlab-org/gl-sast)
is used to detect the language/framework and in turn runs the matching scan tool.
The above example will create a `sast` job in your CI pipeline and will allow
you to download and analyze the report artifact in JSON format.
The results are sorted by the priority of the vulnerability:
1. High
1. Medium
1. Low
1. Unknown
1. Everything else
TIP: **Tip:**
Starting with GitLab Enterprise Edition Ultimate 10.3, this information will
be automatically extracted and shown right in the merge request widget. To do
so, the CI job must be named `sast` and the artifact path must be
`gl-sast-report.json`.
[Learn more on application security testing results shown in merge requests](../../user/project/merge_requests/sast.md).
## Supported languages and frameworks
The following languages and frameworks are supported.
| Language / framework | Scan tool |
| -------------------- | --------- |
| JavaScript | [Retire.js](https://retirejs.github.io/retire.js)
| Python | [bandit](https://github.com/openstack/bandit) |
| Ruby | [bundler-audit](https://github.com/rubysec/bundler-audit) |
| Ruby on Rails | [brakeman](https://brakemanscanner.org) |
[ee]: https://about.gitlab.com/gitlab-ee/
......@@ -37,6 +37,7 @@ comments: false
- [`Gemfile` guidelines](gemfile.md)
- [Sidekiq debugging](sidekiq_debugging.md)
- [Gotchas](gotchas.md) to avoid
- [Avoid modules with instance variables](module_with_instance_variables.md) if possible
- [Issue and merge requests state models](object_state_models.md)
- [How to dump production data to staging](db_dump.md)
- [Working with the GitHub importer](github_importer.md)
......@@ -81,10 +82,9 @@ comments: false
## Documentation guides
- [Documentation styleguide](doc_styleguide.md): Use this styleguide if you are
contributing to the documentation.
- [Writing documentation](writing_documentation.md)
- [Distinction between general documentation and technical articles](writing_documentation.md#distinction-between-general-documentation-and-technical-articles)
- [Documentation styleguide](doc_styleguide.md)
- [Markdown](../user/markdown.md)
## Internationalization (i18n) guides
......
......@@ -8,7 +8,7 @@ might encounter or should avoid during development of GitLab CE and EE.
Consider the following factory:
```ruby
FactoryGirl.define do
FactoryBot.define do
factory :label do
sequence(:title) { |n| "label#{n}" }
end
......@@ -53,7 +53,7 @@ When run, this spec doesn't do what we might expect:
(compared using ==)
```
That's because FactoryGirl sequences are not reseted for each example.
That's because FactoryBot sequences are not reseted for each example.
Please remember that sequence-generated values exist only to avoid having to
explicitly set attributes that have a uniqueness constraint when using a factory.
......
## Modules with instance variables could be considered harmful
### Background
Rails somehow encourages people using modules and instance variables
everywhere. For example, using instance variables in the controllers,
helpers, and views. They're also encouraging the use of
`ActiveSupport::Concern`, which further strengthens the idea of
saving everything in a giant, single object, and people could access
everything in that one giant object.
### The problems
Of course this is convenient to develop, because we just have everything
within reach. However this has a number of downsides when that chosen object
is growing, it would later become out of control for the same reason.
There are just too many things in the same context, and we don't know if
those things are tightly coupled or not, depending on each others or not.
It's very hard to tell when the complexity grows to a point, and it makes
tracking the code also extremely hard. For example, a class could be using
3 different instance variables, and all of them could be initialized and
manipulated from 3 different modules. It's hard to track when those variables
start giving us troubles. We don't know which module would suddenly change
one of the variables. Everything could touch anything.
### Similar concerns
People are saying multiple inheritance is bad. Mixing multiple modules with
multiple instance variables scattering everywhere suffer from the same issue.
The same applies to `ActiveSupport::Concern`. See:
[Consider replacing concerns with dedicated classes & composition](
https://gitlab.com/gitlab-org/gitlab-ce/issues/23786)
There's also a similar idea:
[Use decorators and interface segregation to solve overgrowing models problem](
https://gitlab.com/gitlab-org/gitlab-ce/issues/13484)
Note that `included` doesn't solve the whole issue. They define the
dependencies, but they still allow each modules to talk implicitly via the
instance variables in the final giant object, and that's where the problem is.
### Solutions
We should split the giant object into multiple objects, and they communicate
with each other with the API, i.e. public methods. In short, composition over
inheritance. This way, each smaller objects would have their own respective
limited states, i.e. instance variables. If one instance variable goes wrong,
we would be very clear that it's from that single small object, because
no one else could be touching it.
With clearly defined API, this would make things less coupled and much easier
to debug and track, and much more extensible for other objects to use, because
they communicate in a clear way, rather than implicit dependencies.
### Acceptable use
However, it's not always bad to use instance variables in a module,
as long as it's contained in the same module; that is, no other modules or
objects are touching them, then it would be an acceptable use.
We especially allow the case where a single instance variable is used with
`||=` to setup the value. This would look like:
``` ruby
module M
def f
@f ||= true
end
end
```
Unfortunately it's not easy to code more complex rules into the cop, so
we rely on people's best judgement. If we could find another good pattern
we could easily add to the cop, we should do it.
### How to rewrite and avoid disabling this cop
Even if we could just disable the cop, we should avoid doing so. Some code
could be easily rewritten in simple form. Consider this acceptable method:
``` ruby
module Gitlab
module Emoji
def emoji_unicode_version(name)
@emoji_unicode_versions_by_name ||=
JSON.parse(File.read(Rails.root.join('fixtures', 'emojis', 'emoji-unicode-version-map.json')))
@emoji_unicode_versions_by_name[name]
end
end
end
```
This method is totally fine because it's already self-contained. No other
methods should be using `@emoji_unicode_versions_by_name` and we're good.
However it's still offending the cop because it's not just `||=`, and the
cop is not smart enough to judge that this is fine.
On the other hand, we could split this method into two:
``` ruby
module Gitlab
module Emoji
def emoji_unicode_version(name)
emoji_unicode_versions_by_name[name]
end
private
def emoji_unicode_versions_by_name
@emoji_unicode_versions_by_name ||=
JSON.parse(File.read(Rails.root.join('fixtures', 'emojis', 'emoji-unicode-version-map.json')))
end
end
end
```
Now the cop won't complain. Here's a bad example which we could rewrite:
``` ruby
module SpamCheckService
def filter_spam_check_params
@request = params.delete(:request)
@api = params.delete(:api)
@recaptcha_verified = params.delete(:recaptcha_verified)
@spam_log_id = params.delete(:spam_log_id)
end
def spam_check(spammable, user)
spam_service = SpamService.new(spammable, @request)
spam_service.when_recaptcha_verified(@recaptcha_verified, @api) do
user.spam_logs.find_by(id: @spam_log_id)&.update!(recaptcha_verified: true)
end
end
end
```
There are several implicit dependencies here. First, `params` should be
defined before use. Second, `filter_spam_check_params` should be called
before `spam_check`. These are all implicit and the includer could be using
those instance variables without awareness.
This should be rewritten like:
``` ruby
class SpamCheckService
def initialize(request:, api:, recaptcha_verified:, spam_log_id:)
@request = request
@api = api
@recaptcha_verified = recaptcha_verified
@spam_log_id = spam_log_id
end
def spam_check(spammable, user)
spam_service = SpamService.new(spammable, @request)
spam_service.when_recaptcha_verified(@recaptcha_verified, @api) do
user.spam_logs.find_by(id: @spam_log_id)&.update!(recaptcha_verified: true)
end
end
end
```
And use it like:
``` ruby
class UpdateSnippetService < BaseService
def execute
# ...
spam = SpamCheckService.new(params.slice!(:request, :api, :recaptcha_verified, :spam_log_id))
spam.check(snippet, current_user)
# ...
end
end
```
This way, all those instance variables are isolated in `SpamCheckService`
rather than whatever includes the module, and those modules which were also
included, making it much easier to track down any issues,
and reducing the chance of having name conflicts.
### How to disable this cop
Put the disabling comment right after your code in the same line:
``` ruby
module M
def violating_method
@f + @g # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
```
If there are multiple lines, you could also enable and disable for a section:
``` ruby
module M
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def violating_method
@f = 0
@g = 1
@h = 2
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
```
Note that you need to enable it at some point, otherwise everything below
won't be checked.
### Things we might need to ignore right now
Because of the way Rails helpers and mailers work, we might not be able to
avoid the use of instance variables there. For those cases, we could ignore
them at the moment. At least we're not going to share those modules with
other random objects, so they're still somewhat isolated.
### Instance variables in views
They're bad because we can't easily tell who's using the instance variables
(from controller's point of view) and where we set them up (from partials'
point of view), making it extremely hard to track data dependency.
We're trying to use something like this instead:
``` haml
= render 'projects/commits/commit', commit: commit, ref: ref, project: project
```
And in the partial:
``` haml
- ref = local_assigns.fetch(:ref)
- commit = local_assigns.fetch(:commit)
- project = local_assigns.fetch(:project)
```
This way it's clearer where those values were coming from, and we gain the
benefit to have typo check over using instance variables. In the future,
we should also forbid the use of instance variables in partials.
......@@ -8,8 +8,8 @@ and effective _as well as_ fast.
Here are some things to keep in mind regarding test performance:
- `double` and `spy` are faster than `FactoryGirl.build(...)`
- `FactoryGirl.build(...)` and `.build_stubbed` are faster than `.create`.
- `double` and `spy` are faster than `FactoryBot.build(...)`
- `FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`.
- Don't `create` an object when `build`, `build_stubbed`, `attributes_for`,
`spy`, or `double` will do. Database persistence is slow!
- Don't mark a feature as requiring JavaScript (through `@javascript` in
......@@ -254,13 +254,13 @@ end
### Factories
GitLab uses [factory_girl] as a test fixture replacement.
GitLab uses [factory_bot] as a test fixture replacement.
- Factory definitions live in `spec/factories/`, named using the pluralization
of their corresponding model (`User` factories are defined in `users.rb`).
- There should be only one top-level factory definition per file.
- FactoryGirl methods are mixed in to all RSpec groups. This means you can (and
should) call `create(...)` instead of `FactoryGirl.create(...)`.
- FactoryBot methods are mixed in to all RSpec groups. This means you can (and
should) call `create(...)` instead of `FactoryBot.create(...)`.
- Make use of [traits] to clean up definitions and usages.
- When defining a factory, don't define attributes that are not required for the
resulting record to pass validation.
......@@ -269,8 +269,8 @@ GitLab uses [factory_girl] as a test fixture replacement.
- Factories don't have to be limited to `ActiveRecord` objects.
[See example](https://gitlab.com/gitlab-org/gitlab-ce/commit/0b8cefd3b2385a21cfed779bd659978c0402766d).
[factory_girl]: https://github.com/thoughtbot/factory_girl
[traits]: http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Traits
[factory_bot]: https://github.com/thoughtbot/factory_bot
[traits]: http://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#Traits
### Fixtures
......
......@@ -33,7 +33,7 @@ changes should be tested.
## [Testing best practices](best_practices.md)
Everything you should know about how to write good tests: RSpec, FactoryGirl,
Everything you should know about how to write good tests: RSpec, FactoryBot,
system tests, parameterized tests etc.
---
......
This diff is collapsed.
......@@ -86,7 +86,7 @@ current version of OpenSSH:
Note that CentOS 6 and 7.0 ship with an old version of OpenSSH that do not
support a feature that Geo requires. See the [documentation on GitLab Geo SSH
access](ssh.md) for more details.
access](../administration/operations/fast_ssh_key_lookup.md) for more details.
### LDAP
......@@ -145,8 +145,8 @@ If you installed GitLab using the Omnibus packages (highly recommended):
Geo node to unlock GitLab Geo.
1. [Setup the database replication](database.md) (`primary (read-write) <->
secondary (read-only)` topology).
1. [Lookup authorized SSH keys in the database](../administration/operations/speed_up_ssh.html),
do this step for both primary AND secondary nodes.
1. [Configure fast lookup of authorized SSH keys in the database](../administration/operations/fast_ssh_key_lookup.md),
this step is required and needs to be done on both the primary AND secondary nodes.
1. [Configure GitLab](configuration.md) to set the primary and secondary nodes.
1. Optional: [Configure a secondary LDAP server](../administration/auth/ldap.md)
for the secondary. See [notes on LDAP](#ldap).
......@@ -165,7 +165,7 @@ If you installed GitLab from source:
Geo node to unlock GitLab Geo.
1. [Setup the database replication](database_source.md) (`primary (read-write)
<-> secondary (read-only)` topology).
1. [Lookup authorized SSH keys in the database](../administration/operations/speed_up_ssh.html),
1. [Configure fast lookup of authorized SSH keys in the database](../administration/operations/fast_ssh_key_lookup.md),
do this step for both primary AND secondary nodes.
1. [Configure GitLab](configuration_source.md) to set the primary and secondary
nodes.
......
This document was moved to [another location](using_a_geo_server.md).
This diff is collapsed.
This diff is collapsed.
# GitLab Geo SSH access
By default, GitLab manages an `authorized_keys` file, which contains all the
public SSH keys for users allowed to access GitLab. However, to maintain a
single source of truth, Geo needs to be configured to perform SSH fingerprint
lookups via database lookup. This approach is also much faster than scanning a
file.
>**Note:**
GitLab 10.0 and higher require database lookups for SSH keys.
Note this feature is only available on operating systems that support OpenSSH
6.9 and above. For CentOS 6, see the [instructions on building custom
version of OpenSSH for your server]
(../administration/operations/speed_up_ssh.html#compiling-a-custom-version-of-openssh-for-centos-6).
For both primary AND secondary nodes, follow the instructions on
[looking up authorized SSH keys in the database](../administration/operations/speed_up_ssh.html).
Note that the 'Write to "authorized keys" file' checkbox only needs
to be unchecked on the primary node since it will be reflected automatically
in the secondary if database replication is working.
This document was moved to [another location](../administration/operations/fast_ssh_key_lookup.md).
......@@ -93,7 +93,7 @@ for existing repositories was added in GitLab 10.1.
## Upgrading to GitLab 10.0
Since GitLab 10.0, we require all **Geo** systems to [use SSH key lookups via
the database](ssh.md) to avoid having to maintain consistency of the
the database](../administration/operations/fast_ssh_key_lookup.md) to avoid having to maintain consistency of the
`authorized_keys` file for SSH access. Failing to do this will prevent users
from being able to clone via SSH.
......
......@@ -14,3 +14,4 @@ comments: false
- [How we manage the CRIME vulnerability](crime_vulnerability.md)
- [Enforce Two-factor authentication](two_factor_authentication.md)
- [Send email confirmation on sign-up](user_email_confirmation.md)
- [Security of running jobs](https://docs.gitlab.com/runner/security/#security-of-running-jobs)
......@@ -19,6 +19,7 @@ project in an easy and automatic way:
1. [Auto Build](#auto-build)
1. [Auto Test](#auto-test)
1. [Auto Code Quality](#auto-code-quality)
1. [Auto SAST (Static Application Security Testing)](#auto-sast)
1. [Auto Review Apps](#auto-review-apps)
1. [Auto Deploy](#auto-deploy)
1. [Auto Monitoring](#auto-monitoring)
......@@ -198,6 +199,18 @@ out. In GitLab Enterprise Edition Starter, differences between the source and
target branches are
[shown in the merge request widget](../../user/project/merge_requests/code_quality_diff.md).
### Auto SAST
> Introduced in [GitLab Enterprise Edition Ultimate][ee] 10.3.
Static Application Security Testing (SAST) uses the
[gl-sast Docker image](https://gitlab.com/gitlab-org/gl-sast) to run static
analysis on the current code and checks for potential security issues. Once the
report is created, it's uploaded as an artifact which you can later download and
check out.
Any security warnings are also [shown in the merge request widget](../../user/project/merge_requests/sast.md).
### Auto Review Apps
NOTE: **Note:**
......@@ -536,3 +549,4 @@ curl --data "value=true" --header "PRIVATE-TOKEN: personal_access_token" https:/
[postgresql]: https://www.postgresql.org/
[Auto DevOps template]: https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Auto-DevOps.gitlab-ci.yml
[GitLab Omnibus Helm Chart]: ../../install/kubernetes/gitlab_omnibus.md
[ee]: https://about.gitlab.com/gitlab-ee/
......@@ -55,6 +55,7 @@ and [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.
- [Lock files](https://docs.gitlab.com/ee/user/project/file_lock.html) to prevent conflicts
- View of the current health and status of each CI environment running on Kubernetes with [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html)
- Leverage your continuous delivery method with [Canary Deployments](https://docs.gitlab.com/ee/user/project/canary_deployments.html)
- Scan your code for vulnerabilities and [display them in merge requests](project/merge_requests/sast.md).
You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, JIRA, and a lot more.
......
......@@ -193,6 +193,17 @@ can show the Code Climate report right in the merge request widget area.
[Read more about Code Quality reports.](code_quality_diff.md)
## Static Application Security Testing
> Introduced in [GitLab Enterprise Edition Ultimate][products] 10.3.
If you are using [GitLab CI/CD][ci], you can analyze your source code for known
vulnerabilities using Static Application Security Testing (SAST).
Going a step further, GitLab can show the vulnerability report right in the
merge request widget area.
[Read more about Static Application Security Testing reports.](sast.md)
## Live preview with Review Apps
If you configured [Review Apps](https://about.gitlab.com/features/review-apps/) for your project,
......
# Static Application Security Testing (SAST)
> [Introduced][ee-3775] in [GitLab Enterprise Edition Ultimate][ee] 10.3.
## Overview
If you are using [GitLab CI/CD][ci], you can analyze your source code for known
vulnerabilities using Static Application Security Testing (SAST).
Going a step further, GitLab can show the vulnerability list right in the merge
request widget area:
![SAST Widget](img/sast.png)
## Use cases
- Your application is using an external (open source) library, locked to a
specific version (e.g., via `Gemfile.lock`) and the version is known to be
vulnerable.
- Your code has a potentially dangerous attribute in a class, or unsafe code
that can lead to unintended code execution.
## How it works
In order for the report to show in the merge request, you need to specify a
`sast` job (exact name) that will analyze the code and upload the resulting
`gl-sast-report.json` file as an artifact. GitLab will then check this file and
show the information inside the merge request.
This JSON file needs to be the only artifact file for the job. If you try
to also include other files, it will break the vulnerability display in the
merge request.
For more information on how the `sast` job should look like, check the
example on [analyzing a project's code for vulnerabilities][cc-docs].
[ee-3775]: https://gitlab.com/gitlab-org/gitlab-ee/issues/3775
[ee]: https://about.gitlab.com/gitlab-ee/
[ci]: ../../../ci/README.md
[cc-docs]: ../../../ci/examples/sast.md
......@@ -43,7 +43,9 @@ Annex to Git LFS.
If you know what you are doing and want to skip the reading, this is what you
need to do (we assume you have [git-annex enabled][annex-gitlab-use] in your
repository). Fire up a terminal, navigate to your Git repository and:
repository and that you have made backups in case something goes wrong).
Fire up a terminal, navigate to your Git repository and:
1. Disable `git-annex`:
......@@ -57,6 +59,7 @@ repository). Fire up a terminal, navigate to your Git repository and:
1. Enable `git-lfs`:
```
git lfs install
git lfs track <files>
git add .
git commit -m "commit message"
......@@ -81,9 +84,22 @@ deprecated in Git Annex version 6, so you may need to upgrade your repository
if the server also has Git Annex 6 installed. Read more in the
[Git Annex troubleshooting tips][annex-tips] section.
1. Backup your repository
```bash
cd repository
git annex sync --content
cd ..
git clone repository repository-backup
cd repository-backup
git annex get
cd ..
```
1. Use `annex direct`:
```bash
cd repository
git annex direct
```
......@@ -198,6 +214,17 @@ branches created by Git Annex: `git-annex`, and all under `synced/`.
![repository branches](images/git-annex-branches.png)
You can also do this on the commandline with:
```bash
git branch -d synced/master
git branch -d synced/git-annex
git push origin :synced/master
git push origin :synced/git-annex
git push origin :git-annex
git remote prune origin
```
If there are still some Annex objects inside your repository (`.git/annex/`)
or references inside `.git/config`, run `annex uninit` again:
......
module EE
module LfsRequest
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
def lfs_forbidden!
if project.above_size_limit? || objects_exceed_repo_limit?
......@@ -13,7 +14,7 @@ module EE
def render_size_error
render(
json: {
message: ::Gitlab::RepositorySizeError.new(project).push_error(@exceeded_limit),
message: ::Gitlab::RepositorySizeError.new(project).push_error(@exceeded_limit), # rubocop:disable Gitlab/ModuleWithInstanceVariables
documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
......@@ -23,13 +24,14 @@ module EE
def objects_exceed_repo_limit?
return false unless project.size_limit_enabled?
return @limit_exceeded if defined?(@limit_exceeded)
lfs_push_size = objects.sum { |o| o[:size] }
size_with_lfs_push = project.repository_and_lfs_size + lfs_push_size
strong_memoize(:limit_exceeded) do
lfs_push_size = objects.sum { |o| o[:size] }
size_with_lfs_push = project.repository_and_lfs_size + lfs_push_size
@exceeded_limit = size_with_lfs_push - project.actual_size_limit
@limit_exceeded = @exceeded_limit > 0
@exceeded_limit = size_with_lfs_push - project.actual_size_limit # rubocop:disable Gitlab/ModuleWithInstanceVariables
@exceeded_limit > 0 # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
end
end
......@@ -14,6 +14,6 @@ module SafeMirrorParams
end
def default_mirror_users
[current_user, @project.mirror_user].compact.uniq
[current_user, project.mirror_user].compact.uniq
end
end
module EE::Admin::LogsController
include ::Gitlab::Utils::StrongMemoize
def loggers
raise NotImplementedError unless defined?(super)
@loggers ||= super + [
Gitlab::GeoLogger
]
strong_memoize(:loggers) do
super + [
Gitlab::GeoLogger
]
end
end
end
......@@ -24,6 +24,7 @@ module EE
end
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
service = ::Boards::UpdateService.new(parent, current_user, board_params)
......@@ -40,10 +41,11 @@ module EE
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def destroy
service = ::Boards::DestroyService.new(parent, current_user)
service.execute(@board)
service.execute(@board) # rubocop:disable Gitlab/ModuleWithInstanceVariables
respond_to do |format|
format.json { head :ok }
......@@ -62,15 +64,15 @@ module EE
end
def find_board
@board = parent.boards.find(params[:id])
@board = parent.boards.find(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def parent
@parent ||= @project || @group
@parent ||= @project || @group # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def boards_path
if @group
if @group # rubocop:disable Gitlab/ModuleWithInstanceVariables
group_boards_path(parent)
else
project_boards_path(parent)
......@@ -78,7 +80,7 @@ module EE
end
def board_path(board)
if @group
if @group # rubocop:disable Gitlab/ModuleWithInstanceVariables
group_board_path(parent, board)
else
project_board_path(parent, board)
......
module EE
module Groups
module GroupMembersController
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def override
@group_member = @group.group_members.find(params[:id])
......@@ -14,6 +15,7 @@ module EE
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
protected
......
......@@ -3,7 +3,7 @@ module EE
protected
def fail_login
log_failed_login(@user.username, oauth['provider'])
log_failed_login(@user.username, oauth['provider']) # rubocop:disable Gitlab/ModuleWithInstanceVariables
super
end
......
......@@ -33,7 +33,7 @@ module EE
payload = ::Gitlab::Geo::JwtRequestDecoder.new(request.headers['Authorization']).decode
if payload
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code])
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
return # grant access
end
......
......@@ -11,8 +11,8 @@ module EE
end
def service_desk
@issues = @issuables
@users.push(::User.support_bot)
@issues = @issuables # rubocop:disable Gitlab/ModuleWithInstanceVariables
@users.push(::User.support_bot) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def export_csv
......
......@@ -7,11 +7,11 @@ module EE
private
def set_suggested_approvers
if @merge_request.requires_approve?
@suggested_approvers = ::Gitlab::AuthorityAnalyzer.new(
@merge_request,
@merge_request.author || current_user
).calculate(@merge_request.approvals_required)
if merge_request.requires_approve?
@suggested_approvers = ::Gitlab::AuthorityAnalyzer.new( # rubocop:disable Gitlab/ModuleWithInstanceVariables
merge_request,
merge_request.author || current_user
).calculate(merge_request.approvals_required)
end
end
......@@ -38,12 +38,12 @@ module EE
# Target the MR target project in priority, else it depends whether the project
# is forked.
target_project = if @merge_request
@merge_request.target_project
elsif @project.forked? && @project.id.to_s != mr_params[:target_project_id]
@project.forked_from_project
target_project = if @merge_request # rubocop:disable Gitlab/ModuleWithInstanceVariables
@merge_request.target_project # rubocop:disable Gitlab/ModuleWithInstanceVariables
elsif project.forked? && project.id.to_s != mr_params[:target_project_id]
project.forked_from_project
else
@project
project
end
if mr_params[:approvals_before_merge].to_i <= target_project.approvals_before_merge
......
......@@ -9,19 +9,19 @@ module EE
end
def rebase
RebaseWorker.perform_async(@merge_request.id, current_user.id)
RebaseWorker.perform_async(merge_request.id, current_user.id)
render nothing: true, status: 200
end
def approve
unless @merge_request.can_approve?(current_user)
unless merge_request.can_approve?(current_user)
return render_404
end
::MergeRequests::ApprovalService
.new(project, current_user)
.execute(@merge_request)
.execute(merge_request)
render_approvals_json
end
......@@ -31,10 +31,10 @@ module EE
end
def unapprove
if @merge_request.has_approved?(current_user)
if merge_request.has_approved?(current_user)
::MergeRequests::RemoveApprovalService
.new(project, current_user)
.execute(@merge_request)
.execute(merge_request)
end
render_approvals_json
......@@ -51,7 +51,7 @@ module EE
def render_approvals_json
respond_to do |format|
format.json do
entity = ::API::Entities::MergeRequestApprovals.new(@merge_request, current_user: current_user)
entity = ::API::Entities::MergeRequestApprovals.new(merge_request, current_user: current_user)
render json: entity
end
end
......@@ -65,11 +65,11 @@ module EE
end
def check_user_can_push_to_source_branch!
return access_denied! unless @merge_request.source_branch_exists?
return access_denied! unless merge_request.source_branch_exists?
access_check = ::Gitlab::UserAccess
.new(current_user, project: @merge_request.source_project)
.can_push_to_branch?(@merge_request.source_branch)
.new(current_user, project: merge_request.source_project)
.can_push_to_branch?(merge_request.source_branch)
access_denied! unless access_check
end
......
......@@ -15,15 +15,16 @@ module EE
return unless project.feature_available?(:push_rules)
project.create_push_rule unless project.push_rule
@push_rule = project.push_rule
@push_rule = project.push_rule # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def remote_mirror
return unless project.feature_available?(:repository_mirrors)
@remote_mirror = @project.remote_mirrors.first_or_initialize
@remote_mirror = project.remote_mirrors.first_or_initialize # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def acces_levels_options
super.merge(
selected_merge_access_levels: @protected_branch.merge_access_levels.map { |access_level| access_level.user_id || access_level.access_level },
......@@ -31,11 +32,12 @@ module EE
selected_create_access_levels: @protected_tag.create_access_levels.map { |access_level| access_level.user_id || access_level.access_level }
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def load_gon_index
super
gon.push(current_project_id: @project.id) if @project
gon.push(current_project_id: project.id) if project
end
end
end
......
......@@ -26,7 +26,7 @@ module EE
return unless ::Gitlab::Geo.secondary?
oauth = ::Gitlab::Geo::OauthSession.new(access_token: session[:access_token])
@geo_logout_state = oauth.generate_logout_state
@geo_logout_state = oauth.generate_logout_state # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def log_failed_login
......
......@@ -10,7 +10,7 @@ module EE
return unless entity_type && entity_id
# Avoiding exception if the record doesn't exist
@entity ||= entity_type.constantize.find_by_id(entity_id)
@entity ||= entity_type.constantize.find_by_id(entity_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def present
......
......@@ -5,6 +5,7 @@ module EE
# and be prepended in the `Namespace` model
module Namespace
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
FREE_PLAN = 'free'.freeze
......@@ -67,19 +68,23 @@ module EE
# for a given Namespace plan. This method should consider ancestor groups
# being licensed.
def feature_available?(feature)
@feature_available ||= Hash.new do |h, feature|
h[feature] = load_feature_available(feature)
available_features = strong_memoize(:feature_available) do
Hash.new do |h, feature|
h[feature] = load_feature_available(feature)
end
end
@feature_available[feature]
available_features[feature]
end
def feature_available_in_plan?(feature)
@features_available_in_plan ||= Hash.new do |h, feature|
h[feature] = (plans.map(&:name) & self.class.plans_with_feature(feature)).any?
available_features = strong_memoize(:features_available_in_plan) do
Hash.new do |h, feature|
h[feature] = (plans.map(&:name) & self.class.plans_with_feature(feature)).any?
end
end
@features_available_in_plan[feature]
available_features[feature]
end
# The main difference between the "plan" column and this method is that "plan"
......@@ -128,9 +133,9 @@ module EE
# These helper methods are required to not break the Namespace API.
def plan=(plan_name)
if plan_name.is_a?(String)
@plan_name = plan_name
@plan_name = plan_name # rubocop:disable Gitlab/ModuleWithInstanceVariables
super(Plan.find_by(name: @plan_name))
super(Plan.find_by(name: @plan_name)) # rubocop:disable Gitlab/ModuleWithInstanceVariables
else
super
end
......@@ -149,7 +154,7 @@ module EE
private
def validate_plan_name
if @plan_name.present? && PLANS.exclude?(@plan_name)
if @plan_name.present? && PLANS.exclude?(@plan_name) # rubocop:disable Gitlab/ModuleWithInstanceVariables
errors.add(:plan, 'is not included in the list')
end
end
......
......@@ -5,6 +5,7 @@ module EE
# and be prepended in the `Project` model
module Project
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
prepended do
include Elastic::ProjectsSearch
......@@ -258,8 +259,9 @@ module EE
def deployment_platform(environment: nil)
return super unless environment && feature_available?(:multiple_clusters)
@deployment_platform ||= clusters.enabled.on_environment(environment.name)
.last&.platform_kubernetes
@deployment_platform ||= # rubocop:disable Gitlab/ModuleWithInstanceVariables
clusters.enabled.on_environment(environment.name)
.last&.platform_kubernetes
super # Wildcard or KubernetesService
end
......@@ -323,8 +325,11 @@ module EE
end
def find_path_lock(path, exact_match: false, downstream: false)
@path_lock_finder ||= ::Gitlab::PathLocksFinder.new(self)
@path_lock_finder.find(path, exact_match: exact_match, downstream: downstream)
path_lock_finder = strong_memoize(:path_lock_finder) do
::Gitlab::PathLocksFinder.new(self)
end
path_lock_finder.find(path, exact_match: exact_match, downstream: downstream)
end
def import_url_updated?
......@@ -450,15 +455,15 @@ module EE
end
def disabled_services
return @disabled_services if defined?(@disabled_services)
strong_memoize(:disabled_services) do
disabled_services = []
@disabled_services = []
unless feature_available?(:jenkins_integration)
disabled_services.push('jenkins', 'jenkins_deprecated')
end
unless feature_available?(:jenkins_integration)
@disabled_services.push('jenkins', 'jenkins_deprecated')
disabled_services
end
@disabled_services
end
def remote_mirror_available?
......@@ -479,11 +484,13 @@ module EE
end
def licensed_feature_available?(feature)
@licensed_feature_available ||= Hash.new do |h, feature|
h[feature] = load_licensed_feature_available(feature)
available_features = strong_memoize(:licensed_feature_available) do
Hash.new do |h, feature|
h[feature] = load_licensed_feature_available(feature)
end
end
@licensed_feature_available[feature]
available_features[feature]
end
def load_licensed_feature_available(feature)
......
module EE
module Applications
# rubocop:disable Gitlab/ModuleWithInstanceVariables
module CreateService
def execute(request)
super.tap do |application|
......
module EE
module AuditEventService
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def for_member(member)
action = @details[:action]
old_access_level = @details[:old_access_level]
......@@ -199,5 +200,6 @@ module EE
}
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
end
......@@ -3,8 +3,8 @@ module EE
module Issues
module ListService
def set_parent
if @parent.is_a?(Group)
params[:group_id] = @parent.id
if parent.is_a?(Group)
params[:group_id] = parent.id
else
super
end
......
......@@ -12,11 +12,11 @@ module EE
end
def audit_event_service
::AuditEventService.new(@user,
@user,
::AuditEventService.new(user,
user,
action: :custom,
custom_message: 'Added SSH key',
ip_address: @ip_address)
ip_address: @ip_address) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
end
......
......@@ -25,8 +25,8 @@ module EE
private
def check_size_limit
if @merge_request.target_project.above_size_limit?
message = ::Gitlab::RepositorySizeError.new(@merge_request.target_project).merge_error
if merge_request.target_project.above_size_limit?
message = ::Gitlab::RepositorySizeError.new(merge_request.target_project).merge_error
raise ::MergeRequests::MergeService::MergeError, message
end
......
......@@ -41,7 +41,7 @@ module EE
create_predefined_push_rule
@project.group&.refresh_members_authorized_projects
project.group&.refresh_members_authorized_projects
end
def create_predefined_push_rule
......
......@@ -8,12 +8,12 @@ module EE
super
EE::Audit::ProjectChangesAuditor.new(@current_user, project).execute
EE::Audit::ProjectChangesAuditor.new(current_user, project).execute
::Geo::RepositoryRenamedEventStore.new(
project,
old_path: project.path,
old_path_with_namespace: @old_path
old_path_with_namespace: @old_path # rubocop:disable Gitlab/ModuleWithInstanceVariables
).create
end
end
......
......@@ -26,15 +26,15 @@ module EE
end
def groups_accessible?
group_ids = @merge_params.group_ids + @push_params.group_ids
allowed_groups = @project.invited_groups.where(id: group_ids)
group_ids = @merge_params.group_ids + @push_params.group_ids # rubocop:disable Gitlab/ModuleWithInstanceVariables
allowed_groups = @project.invited_groups.where(id: group_ids) # rubocop:disable Gitlab/ModuleWithInstanceVariables
group_ids.count == allowed_groups.count
end
def users_accessible?
user_ids = @merge_params.user_ids + @push_params.user_ids
allowed_users = @project.team.users.where(id: user_ids)
user_ids = @merge_params.user_ids + @push_params.user_ids # rubocop:disable Gitlab/ModuleWithInstanceVariables
allowed_users = @project.team.users.where(id: user_ids) # rubocop:disable Gitlab/ModuleWithInstanceVariables
user_ids.count == allowed_users.count
end
......
......@@ -3,7 +3,7 @@ module EE
def execute(blocking: true)
result = super
@user_ids.each do |id|
@user_ids.each do |id| # rubocop:disable Gitlab/ModuleWithInstanceVariables
::Gitlab::Database::LoadBalancing::Sticking.stick(:user, id)
end
......
......@@ -6,7 +6,7 @@ module EE
private
def notify_success(user_exists)
notify_new_user(@user, nil) unless user_exists
notify_new_user(@user, nil) unless user_exists # rubocop:disable Gitlab/ModuleWithInstanceVariables
audit_changes(:email, as: 'email address')
audit_changes(:encrypted_password, as: 'password', skip_changes: true)
......
......@@ -8,7 +8,7 @@
= expanded ? 'Collapse' : 'Expand'
%p
Customize your service desk settings.
= link_to "Learn more about service desk.", help_page_path('user/project/service_desk')
= link_to "Learn more about service desk.", help_page_path('user/project/service_desk'), target: '_blank'
.settings-content
- if EE::Gitlab::ServiceDesk.enabled?(project: @project)
.js-service-desk-setting-root{ data: { endpoint: project_service_desk_path(@project),
......
......@@ -2,14 +2,14 @@ module EE
module API
module Helpers
def current_user
return @current_user if defined?(@current_user)
strong_memoize(:current_user) do
user = super
user = super
::Gitlab::Database::LoadBalancing::RackMiddleware
.stick_or_unstick(env, :user, user.id) if user
::Gitlab::Database::LoadBalancing::RackMiddleware
.stick_or_unstick(env, :user, user.id) if user
user
user
end
end
def check_project_feature_available!(feature)
......
......@@ -6,7 +6,7 @@ module EE
private
def project_or_wiki
@project.wiki
project.wiki
end
end
end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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