diff options
30 files changed, 408 insertions, 112 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index e9ec8876688..99411641874 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -106,6 +106,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :lets_encrypt_notification_email, :lets_encrypt_terms_of_service_accepted, :domain_blacklist_file, + :raw_blob_request_limit, disabled_oauth_sign_in_sources: [], import_sources: [], repository_storages: [], diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 42ae5b0ef3c..3254229d9cb 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -8,10 +8,30 @@ class Projects::RawController < Projects::ApplicationController before_action :require_non_empty_project before_action :assign_ref_vars before_action :authorize_download_code! + before_action :show_rate_limit, only: [:show] def show @blob = @repository.blob_at(@commit.id, @path) send_blob(@repository, @blob, inline: (params[:inline] != 'false')) end + + private + + def show_rate_limit + limiter = ::Gitlab::ActionRateLimiter.new(action: :show_raw_controller) + + return unless limiter.throttled?([@project, @commit, @path], raw_blob_request_limit) + + limiter.log_request(request, :raw_blob_request_limit, current_user) + + flash[:alert] = _('You cannot access the raw file. Please wait a minute.') + redirect_to project_blob_path(@project, File.join(@ref, @path)) + end + + def raw_blob_request_limit + Gitlab::CurrentSettings + .current_application_settings + .raw_blob_request_limit + end end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index db4f29cd996..2ed016beea4 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -4,11 +4,10 @@ module LabelsHelper extend self include ActionView::Helpers::TagHelper - def show_label_issuables_link?(label, issuables_type, current_user: nil, project: nil) + def show_label_issuables_link?(label, issuables_type, current_user: nil) return true unless label.project_label? - return true unless project - project.feature_available?(issuables_type, current_user) + label.project.feature_available?(issuables_type, current_user) end # Link to a Label diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index 30fc9fd6892..1e612bd0e78 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -98,7 +98,8 @@ module ApplicationSettingImplementation commit_email_hostname: default_commit_email_hostname, protected_ci_variables: false, local_markdown_version: 0, - outbound_local_requests_whitelist: [] + outbound_local_requests_whitelist: [], + raw_blob_request_limit: 300 } end diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb index 39e12ac2b06..facd81dde80 100644 --- a/app/models/container_repository.rb +++ b/app/models/container_repository.rb @@ -86,4 +86,9 @@ class ContainerRepository < ApplicationRecord def self.build_root_repository(project) self.new(project: project, name: '') end + + def self.find_by_path!(path) + self.find_by!(project: path.repository_project, + name: path.repository_name) + end end diff --git a/app/models/label.rb b/app/models/label.rb index b83e0862bab..dd403562bfa 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -33,7 +33,7 @@ class Label < ApplicationRecord default_scope { order(title: :asc) } - scope :templates, -> { where(template: true) } + scope :templates, -> { where(template: true, type: [Label.name, nil]) } scope :with_title, ->(title) { where(title: title) } scope :with_lists_and_board, -> { joins(lists: :board).merge(List.movable) } scope :on_project_boards, ->(project_id) { with_lists_and_board.where(boards: { project_id: project_id }) } diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb index f39f54f0434..e11d0c48b4b 100644 --- a/app/models/project_auto_devops.rb +++ b/app/models/project_auto_devops.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true class ProjectAutoDevops < ApplicationRecord - include IgnorableColumn - - ignore_column :domain - belongs_to :project, inverse_of: :auto_devops enum deploy_strategy: { diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml index 7821a83530f..b52171afc69 100644 --- a/app/views/admin/application_settings/_performance.html.haml +++ b/app/views/admin/application_settings/_performance.html.haml @@ -15,4 +15,10 @@ AuthorizedKeysCommand. Click on the help icon for more details. = link_to icon('question-circle'), help_page_path('administration/operations/fast_ssh_key_lookup') + .form-group + = f.label :raw_blob_request_limit, _('Raw blob request rate limit per minute'), class: 'label-bold' + = f.number_field :raw_blob_request_limit, class: 'form-control' + .form-text.text-muted + = _('Highest number of requests per minute for each raw path, default to 300. To disable throttling set to 0.') + = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index 2ddea0b9f16..8fecdc6e8a6 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -5,7 +5,7 @@ .branch = merge_path_description(@merge_request, 'to') .author - Author #{@merge_request.author_name} + Author: #{@merge_request.author_name} .assignee = assignees_label(@merge_request) .approvers diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml index af11ce94ec5..b05d903fabe 100644 --- a/app/views/shared/_label_row.html.haml +++ b/app/views/shared/_label_row.html.haml @@ -1,7 +1,7 @@ - force_priority = local_assigns.fetch(:force_priority, false) - subject_or_group_defined = defined?(@project) || defined?(@group) -- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues, project: @project) -- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests, project: @project) +- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues) +- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests) .label-name = render_label(label, tooltip: false) diff --git a/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml b/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml new file mode 100644 index 00000000000..38ee95a7553 --- /dev/null +++ b/changelogs/unreleased/48717-rate-limit-raw-controller-show.yml @@ -0,0 +1,5 @@ +--- +title: Add Rate Request Limiter to RawController#show endpoint +merge_request: 30635 +author: +type: added diff --git a/changelogs/unreleased/63730-fix-500-status-labels-pd.yml b/changelogs/unreleased/63730-fix-500-status-labels-pd.yml new file mode 100644 index 00000000000..a1e2ae0e5df --- /dev/null +++ b/changelogs/unreleased/63730-fix-500-status-labels-pd.yml @@ -0,0 +1,5 @@ +--- +title: Fix admin labels page when there are invalid records +merge_request: 30885 +author: +type: fixed diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 0e78980350f..dd53127ac2c 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -400,6 +400,15 @@ production: &base # path: shared/registry # issuer: gitlab-issuer + # Add notification settings if you plan to use Geo Replication for the registry + # notifications: + # - name: geo_event + # url: https://example.com/api/v4/container_registry_event/events + # timeout: 2s + # threshold: 5 + # backoff: 1s + # headers: + # Authorization: secret_phrase ## Error Reporting and Logging with Sentry sentry: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 494c4dd1f93..32fec7c3d22 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -259,6 +259,7 @@ Settings.registry['key'] ||= nil Settings.registry['issuer'] ||= nil Settings.registry['host_port'] ||= [Settings.registry['host'], Settings.registry['port']].compact.join(':') Settings.registry['path'] = Settings.absolute(Settings.registry['path'] || File.join(Settings.shared['path'], 'registry')) +Settings.registry['notifications'] ||= [] # # Error Reporting and Logging with Sentry diff --git a/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb b/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb new file mode 100644 index 00000000000..8963e837e08 --- /dev/null +++ b/db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddGeoContainerRepositoryUpdatedEventsTable < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table :geo_container_repository_updated_events, force: :cascade do |t| + t.integer :container_repository_id, null: false + + t.index :container_repository_id, name: :idx_geo_con_rep_updated_events_on_container_repository_id, using: :btree + end + + add_column :geo_event_log, :container_repository_updated_event_id, :bigint + end +end diff --git a/db/migrate/20190611100202_add_index_to_geo_event_log.rb b/db/migrate/20190611100202_add_index_to_geo_event_log.rb new file mode 100644 index 00000000000..c5c855fed61 --- /dev/null +++ b/db/migrate/20190611100202_add_index_to_geo_event_log.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexToGeoEventLog < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_index :geo_event_log, :container_repository_updated_event_id + end + + def down + remove_concurrent_index(:geo_event_log, :container_repository_updated_event_id) + end +end diff --git a/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb b/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb new file mode 100644 index 00000000000..cf7fd03e9af --- /dev/null +++ b/db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddForeignKeysForContainerRepository < ActiveRecord::Migration[5.1] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key(:geo_container_repository_updated_events, :container_repositories, column: :container_repository_id, on_delete: :cascade) + + add_concurrent_foreign_key(:geo_event_log, :geo_container_repository_updated_events, column: :container_repository_updated_event_id, on_delete: :cascade) + end + + def down + if foreign_key_exists?(:geo_container_repository_updated_events, :container_repositories) + remove_foreign_key(:geo_container_repository_updated_events, :container_repositories) + end + + if foreign_key_exists?(:geo_event_log, :geo_container_repository_updated_events) + remove_foreign_key(:geo_event_log, :geo_container_repository_updated_events) + end + end +end diff --git a/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb b/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb new file mode 100644 index 00000000000..e8198e11ea7 --- /dev/null +++ b/db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddRawBlobRequestLimitToApplicationSettings < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def change + add_column :application_settings, :raw_blob_request_limit, :integer, default: 300, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 7a25d6cf769..2ec8fcce8f8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_15_114644) do +ActiveRecord::Schema.define(version: 2019_07_15_142138) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -229,6 +229,7 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.boolean "time_tracking_limit_to_hours", default: false, null: false t.string "grafana_url", default: "/-/grafana", null: false t.string "outbound_local_requests_whitelist", limit: 255, array: true + t.integer "raw_blob_request_limit", default: 300, null: false t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id" t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id" @@ -1276,6 +1277,11 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.string "key", null: false end + create_table "geo_container_repository_updated_events", force: :cascade do |t| + t.integer "container_repository_id", null: false + t.index ["container_repository_id"], name: "idx_geo_con_rep_updated_events_on_container_repository_id" + end + create_table "geo_event_log", force: :cascade do |t| t.datetime "created_at", null: false t.bigint "repository_updated_event_id" @@ -1290,7 +1296,9 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do t.bigint "job_artifact_deleted_event_id" t.bigint "reset_checksum_event_id" t.bigint "cache_invalidation_event_id" + t.bigint "container_repository_updated_event_id" t.index ["cache_invalidation_event_id"], name: "index_geo_event_log_on_cache_invalidation_event_id", where: "(cache_invalidation_event_id IS NOT NULL)" + t.index ["container_repository_updated_event_id"], name: "index_geo_event_log_on_container_repository_updated_event_id" t.index ["hashed_storage_attachments_event_id"], name: "index_geo_event_log_on_hashed_storage_attachments_event_id", where: "(hashed_storage_attachments_event_id IS NOT NULL)" t.index ["hashed_storage_migrated_event_id"], name: "index_geo_event_log_on_hashed_storage_migrated_event_id", where: "(hashed_storage_migrated_event_id IS NOT NULL)" t.index ["job_artifact_deleted_event_id"], name: "index_geo_event_log_on_job_artifact_deleted_event_id", where: "(job_artifact_deleted_event_id IS NOT NULL)" @@ -3701,7 +3709,9 @@ ActiveRecord::Schema.define(version: 2019_07_15_114644) do add_foreign_key "fork_network_members", "projects", on_delete: :cascade add_foreign_key "fork_networks", "projects", column: "root_project_id", name: "fk_e7b436b2b5", on_delete: :nullify add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade + add_foreign_key "geo_container_repository_updated_events", "container_repositories", name: "fk_212c89c706", on_delete: :cascade add_foreign_key "geo_event_log", "geo_cache_invalidation_events", column: "cache_invalidation_event_id", name: "fk_42c3b54bed", on_delete: :cascade + add_foreign_key "geo_event_log", "geo_container_repository_updated_events", column: "container_repository_updated_event_id", name: "fk_6ada82d42a", on_delete: :cascade add_foreign_key "geo_event_log", "geo_hashed_storage_migrated_events", column: "hashed_storage_migrated_event_id", name: "fk_27548c6db3", on_delete: :cascade add_foreign_key "geo_event_log", "geo_job_artifact_deleted_events", column: "job_artifact_deleted_event_id", name: "fk_176d3fbb5d", on_delete: :cascade add_foreign_key "geo_event_log", "geo_lfs_object_deleted_events", column: "lfs_object_deleted_event_id", name: "fk_d5af95fcd9", on_delete: :cascade diff --git a/lib/gitlab/action_rate_limiter.rb b/lib/gitlab/action_rate_limiter.rb index c442211e073..fdb06d00548 100644 --- a/lib/gitlab/action_rate_limiter.rb +++ b/lib/gitlab/action_rate_limiter.rb @@ -33,16 +33,48 @@ module Gitlab # Increments the given key and returns true if the action should # be throttled. # - # key - An array of ActiveRecord instances - # threshold_value - The maximum number of times this action should occur in the given time interval + # key - An array of ActiveRecord instances or strings + # threshold_value - The maximum number of times this action should occur in the given time interval. If number is zero is considered disabled. def throttled?(key, threshold_value) - self.increment(key) > threshold_value + threshold_value > 0 && + self.increment(key) > threshold_value + end + + # Logs request into auth.log + # + # request - Web request to be logged + # type - A symbol key that represents the request. + # current_user - Current user of the request, it can be nil. + def log_request(request, type, current_user) + request_information = { + message: 'Action_Rate_Limiter_Request', + env: type, + ip: request.ip, + request_method: request.request_method, + fullpath: request.fullpath + } + + if current_user + request_information.merge!({ + user_id: current_user.id, + username: current_user.username + }) + end + + Gitlab::AuthLogger.error(request_information) end private def action_key(key) - serialized = key.map { |obj| "#{obj.class.model_name.to_s.underscore}:#{obj.id}" }.join(":") + serialized = key.map do |obj| + if obj.is_a?(String) + "#{obj}" + else + "#{obj.class.model_name.to_s.underscore}:#{obj.id}" + end + end.join(":") + "action_rate_limiter:#{action}:#{serialized}" end end diff --git a/lib/quality/test_level.rb b/lib/quality/test_level.rb index 24d8eac200c..60d79b52680 100644 --- a/lib/quality/test_level.rb +++ b/lib/quality/test_level.rb @@ -14,6 +14,7 @@ module Quality finders frontend graphql + haml_lint helpers initializers javascripts diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index c881ad4cf12..bf18332a8eb 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -2,8 +2,6 @@ return if Rails.env.production? -Rake::Task["spec"].clear if Rake::Task.task_defined?('spec') - namespace :spec do desc 'GitLab | RSpec | Run unit tests' RSpec::Core::RakeTask.new(:unit, :rspec_opts) do |t, args| @@ -26,63 +24,8 @@ namespace :spec do t.rspec_opts = args[:rspec_opts] end - desc '[Deprecated] Use the "bin/rspec --tag api" instead' - task :api do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @api) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use the "spec:system" task instead' - task :feature do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @feature) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/models" instead' - task :models do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @models) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/services" instead' - task :services do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @services) - ] - run_commands(cmds) - end - - desc '[Deprecated] Use "bin/rspec spec/lib" instead' - task :lib do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec --tag @lib) - ] - run_commands(cmds) - end -end - -desc "GitLab | Run specs" -task :spec do - cmds = [ - %w(rake gitlab:setup), - %w(rspec spec) - ] - run_commands(cmds) -end - -def run_commands(cmds) - cmds.each do |cmd| - system({ 'RAILS_ENV' => 'test', 'force' => 'yes' }, *cmd) || raise("#{cmd} failed!") + desc 'Run the code examples in spec/requests/api' + RSpec::Core::RakeTask.new(:api) do |t| + t.pattern = 'spec/requests/api/**/*_spec.rb' end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 1f622db8bd7..cbab027d4a3 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5298,6 +5298,9 @@ msgstr[1] "" msgid "Hide values" msgstr "" +msgid "Highest number of requests per minute for each raw path, default to 300. To disable throttling set to 0." +msgstr "" + msgid "Highest role:" msgstr "" @@ -8717,6 +8720,9 @@ msgstr "" msgid "Rake Tasks Help" msgstr "" +msgid "Raw blob request rate limit per minute" +msgstr "" + msgid "Read more" msgstr "" @@ -12442,6 +12448,9 @@ msgstr "" msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}." msgstr "" +msgid "You cannot access the raw file. Please wait a minute." +msgstr "" + msgid "You cannot impersonate a blocked user" msgstr "" diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index 97acd47b4da..8ee3168273f 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe Projects::RawController do + include RepoHelpers + let(:project) { create(:project, :public, :repository) } describe 'GET #show' do @@ -46,5 +48,98 @@ describe Projects::RawController do let(:filename) { 'lfs_object.iso' } let(:filepath) { "be93687/files/lfs/#{filename}" } end + + context 'when the endpoint receives requests above the limit', :clean_gitlab_redis_cache do + let(:file_path) { 'master/README.md' } + + before do + stub_application_setting(raw_blob_request_limit: 5) + end + + it 'prevents from accessing the raw file' do + execute_raw_requests(requests: 6, project: project, file_path: file_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, file_path)) + end + + it 'logs the event on auth.log' do + attributes = { + message: 'Action_Rate_Limiter_Request', + env: :raw_blob_request_limit, + ip: '0.0.0.0', + request_method: 'GET', + fullpath: "/#{project.full_path}/raw/#{file_path}" + } + + expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once + + execute_raw_requests(requests: 6, project: project, file_path: file_path) + end + + context 'when the request uses a different version of a commit' do + it 'prevents from accessing the raw file' do + # 3 times with the normal sha + commit_sha = project.repository.commit.sha + file_path = "#{commit_sha}/README.md" + + execute_raw_requests(requests: 3, project: project, file_path: file_path) + + # 3 times with the modified version + modified_sha = commit_sha.gsub(commit_sha[0..5], commit_sha[0..5].upcase) + modified_path = "#{modified_sha}/README.md" + + execute_raw_requests(requests: 3, project: project, file_path: modified_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, modified_path)) + end + end + + context 'when the throttling has been disabled' do + before do + stub_application_setting(raw_blob_request_limit: 0) + end + + it 'does not prevent from accessing the raw file' do + execute_raw_requests(requests: 10, project: project, file_path: file_path) + + expect(response).to have_gitlab_http_status(200) + end + end + + context 'with case-sensitive files' do + it 'prevents from accessing the specific file' do + create_file_in_repo(project, 'master', 'master', 'readme.md', 'Add readme.md') + create_file_in_repo(project, 'master', 'master', 'README.md', 'Add README.md') + + commit_sha = project.repository.commit.sha + file_path = "#{commit_sha}/readme.md" + + # Accessing downcase version of readme + execute_raw_requests(requests: 6, project: project, file_path: file_path) + + expect(flash[:alert]).to eq('You cannot access the raw file. Please wait a minute.') + expect(response).to redirect_to(project_blob_path(project, file_path)) + + # Accessing upcase version of readme + file_path = "#{commit_sha}/README.md" + + execute_raw_requests(requests: 1, project: project, file_path: file_path) + + expect(response).to have_gitlab_http_status(200) + end + end + end + end + + def execute_raw_requests(requests:, project:, file_path:) + requests.times do + get :show, params: { + namespace_id: project.namespace, + project_id: project, + id: file_path + } + end end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 314305d7a8e..4f1cab38f34 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -3,10 +3,8 @@ require 'spec_helper' describe LabelsHelper do describe '#show_label_issuables_link?' do shared_examples 'a valid response to show_label_issuables_link?' do |issuables_type, when_enabled = true, when_disabled = false| - let(:context_project) { project } - context "when asking for a #{issuables_type} link" do - subject { show_label_issuables_link?(label.present(issuable_subject: nil), issuables_type, project: context_project) } + subject { show_label_issuables_link?(label.present(issuable_subject: nil), issuables_type) } context "when #{issuables_type} are enabled for the project" do let(:project) { create(:project, "#{issuables_type}_access_level": ProjectFeature::ENABLED) } @@ -39,27 +37,11 @@ describe LabelsHelper do let(:label) { create(:group_label, group: group, title: 'bug') } context 'when asking for an issue link' do - context 'in the context of a project' do - it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true - end - - context 'in the context of a group' do - let(:context_project) { nil } - - it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true - end + it_behaves_like 'a valid response to show_label_issuables_link?', :issues, true, true end context 'when asking for a merge requests link' do - context 'in the context of a project' do - it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true - end - - context 'in the context of a group' do - let(:context_project) { nil } - - it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true - end + it_behaves_like 'a valid response to show_label_issuables_link?', :merge_requests, true, true end end end diff --git a/spec/lib/gitlab/action_rate_limiter_spec.rb b/spec/lib/gitlab/action_rate_limiter_spec.rb index 542fc03e555..cf266a25819 100644 --- a/spec/lib/gitlab/action_rate_limiter_spec.rb +++ b/spec/lib/gitlab/action_rate_limiter_spec.rb @@ -1,11 +1,9 @@ require 'spec_helper' -describe Gitlab::ActionRateLimiter do +describe Gitlab::ActionRateLimiter, :clean_gitlab_redis_cache do let(:redis) { double('redis') } let(:user) { create(:user) } let(:project) { create(:project) } - let(:key) { [user, project] } - let(:cache_key) { "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" } subject { described_class.new(action: :test_action, expiry_time: 100) } @@ -13,17 +11,98 @@ describe Gitlab::ActionRateLimiter do allow(Gitlab::Redis::Cache).to receive(:with).and_yield(redis) end - it 'increases the throttle count and sets the expire time' do - expect(redis).to receive(:incr).with(cache_key).and_return(1) - expect(redis).to receive(:expire).with(cache_key, 100) + shared_examples 'action rate limiter' do + it 'increases the throttle count and sets the expiration time' do + expect(redis).to receive(:incr).with(cache_key).and_return(1) + expect(redis).to receive(:expire).with(cache_key, 100) - expect(subject.throttled?(key, 1)).to be false + expect(subject.throttled?(key, 1)).to be_falsy + end + + it 'returns true if the key is throttled' do + expect(redis).to receive(:incr).with(cache_key).and_return(2) + expect(redis).not_to receive(:expire) + + expect(subject.throttled?(key, 1)).to be_truthy + end + + context 'when throttling is disabled' do + it 'returns false and does not set expiration time' do + expect(redis).not_to receive(:incr) + expect(redis).not_to receive(:expire) + + expect(subject.throttled?(key, 0)).to be_falsy + end + end + end + + context 'when the key is an array of only ActiveRecord models' do + let(:key) { [user, project] } + + let(:cache_key) do + "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" + end + + it_behaves_like 'action rate limiter' + end + + context 'when they key a combination of ActiveRecord models and strings' do + let(:project) { create(:project, :public, :repository) } + let(:commit) { project.repository.commit } + let(:path) { 'app/controllers/groups_controller.rb' } + let(:key) { [project, commit, path] } + + let(:cache_key) do + "action_rate_limiter:test_action:project:#{project.id}:commit:#{commit.sha}:#{path}" + end + + it_behaves_like 'action rate limiter' end - it 'returns true if the key is throttled' do - expect(redis).to receive(:incr).with(cache_key).and_return(2) - expect(redis).not_to receive(:expire) + describe '#log_request' do + let(:file_path) { 'master/README.md' } + let(:type) { :raw_blob_request_limit } + let(:fullpath) { "/#{project.full_path}/raw/#{file_path}" } + + let(:request) do + double('request', ip: '127.0.0.1', request_method: 'GET', fullpath: fullpath) + end + + let(:base_attributes) do + { + message: 'Action_Rate_Limiter_Request', + env: type, + ip: '127.0.0.1', + request_method: 'GET', + fullpath: fullpath + } + end + + context 'without a current user' do + let(:current_user) { nil } + + it 'logs information to auth.log' do + expect(Gitlab::AuthLogger).to receive(:error).with(base_attributes).once + + subject.log_request(request, type, current_user) + end + end + + context 'with a current_user' do + let(:current_user) { create(:user) } + + let(:attributes) do + base_attributes.merge({ + user_id: current_user.id, + username: current_user.username + }) + end + + it 'logs information to auth.log' do + expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once - expect(subject.throttled?(key, 1)).to be true + subject.log_request(request, type, current_user) + end + end end end diff --git a/spec/lib/quality/test_level_spec.rb b/spec/lib/quality/test_level_spec.rb index 3465c3a050b..59870ce44a7 100644 --- a/spec/lib/quality/test_level_spec.rb +++ b/spec/lib/quality/test_level_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a pattern' do expect(subject.pattern(:unit)) - .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,helpers,initializers,javascripts,lib,migrations,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") + .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,migrations,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") end end @@ -47,7 +47,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a regexp' do expect(subject.regexp(:unit)) - .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|helpers|initializers|javascripts|lib|migrations|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) + .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|migrations|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) end end diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb index 5174c590a10..c2e2298823e 100644 --- a/spec/models/label_spec.rb +++ b/spec/models/label_spec.rb @@ -193,4 +193,17 @@ describe Label do expect(described_class.optionally_subscribed_by(nil)).to match_array([label, label2]) end end + + describe '#templates' do + context 'with invalid template labels' do + it 'returns only valid template labels' do + create(:label) + # Project labels should not have template set to true + create(:label, template: true) + valid_template_label = described_class.create!(title: 'test', template: true, type: nil) + + expect(described_class.templates).to eq([valid_template_label]) + end + end + end end diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 7bdd2367a68..da9e56ef897 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -15,7 +15,7 @@ describe ProjectAutoDevops do it { is_expected.to respond_to(:updated_at) } describe '#predefined_variables' do - let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: domain) } + let(:auto_devops) { build_stubbed(:project_auto_devops, project: project) } context 'when deploy_strategy is manual' do let(:auto_devops) { build_stubbed(:project_auto_devops, :manual_deployment, project: project) } diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb index a641828faa5..33cd1f37ff6 100644 --- a/spec/services/application_settings/update_service_spec.rb +++ b/spec/services/application_settings/update_service_spec.rb @@ -180,4 +180,20 @@ describe ApplicationSettings::UpdateService do described_class.new(application_settings, admin, { home_page_url: 'http://foo.bar' }).execute end end + + context 'when raw_blob_request_limit is passsed' do + let(:params) do + { + raw_blob_request_limit: 600 + } + end + + it 'updates raw_blob_request_limit value' do + subject.execute + + application_settings.reload + + expect(application_settings.raw_blob_request_limit).to eq(600) + end + end end |