summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/projects/raw_controller.rb20
-rw-r--r--app/helpers/labels_helper.rb5
-rw-r--r--app/models/application_setting_implementation.rb3
-rw-r--r--app/models/container_repository.rb5
-rw-r--r--app/models/label.rb2
-rw-r--r--app/models/project_auto_devops.rb4
-rw-r--r--app/views/admin/application_settings/_performance.html.haml6
-rw-r--r--app/views/notify/new_merge_request_email.html.haml2
-rw-r--r--app/views/shared/_label_row.html.haml4
-rw-r--r--changelogs/unreleased/48717-rate-limit-raw-controller-show.yml5
-rw-r--r--changelogs/unreleased/63730-fix-500-status-labels-pd.yml5
-rw-r--r--config/gitlab.yml.example9
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--db/migrate/20190611100201_add_geo_container_repository_updated_events_table.rb17
-rw-r--r--db/migrate/20190611100202_add_index_to_geo_event_log.rb17
-rw-r--r--db/migrate/20190627122264_add_foreign_keys_for_container_repository.rb25
-rw-r--r--db/migrate/20190715142138_add_raw_blob_request_limit_to_application_settings.rb9
-rw-r--r--db/schema.rb12
-rw-r--r--lib/gitlab/action_rate_limiter.rb40
-rw-r--r--lib/quality/test_level.rb1
-rw-r--r--lib/tasks/spec.rake63
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb95
-rw-r--r--spec/helpers/labels_helper_spec.rb24
-rw-r--r--spec/lib/gitlab/action_rate_limiter_spec.rb101
-rw-r--r--spec/lib/quality/test_level_spec.rb4
-rw-r--r--spec/models/label_spec.rb13
-rw-r--r--spec/models/project_auto_devops_spec.rb2
-rw-r--r--spec/services/application_settings/update_service_spec.rb16
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