diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 60a229ef42aec5354cf003d2ab98a0da359266f0..177adb36cd44a341765885eecf19336b5bf44098 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -411,6 +411,9 @@ def visible_attributes :throttle_unauthenticated_files_api_enabled, :throttle_unauthenticated_files_api_period_in_seconds, :throttle_unauthenticated_files_api_requests_per_period, + :throttle_unauthenticated_git_http_enabled, + :throttle_unauthenticated_git_http_period_in_seconds, + :throttle_unauthenticated_git_http_requests_per_period, :throttle_unauthenticated_deprecated_api_enabled, :throttle_unauthenticated_deprecated_api_period_in_seconds, :throttle_unauthenticated_deprecated_api_requests_per_period, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 959000af9ed86f2ba375bc544d83f8ce2cc05f47..415687c18b765d4aa5a9d5bdb0f082b93e6bd36e 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -554,6 +554,8 @@ def self.kroki_formats_attributes :throttle_unauthenticated_deprecated_api_requests_per_period, :throttle_unauthenticated_files_api_period_in_seconds, :throttle_unauthenticated_files_api_requests_per_period, + :throttle_unauthenticated_git_http_period_in_seconds, + :throttle_unauthenticated_git_http_requests_per_period, :throttle_unauthenticated_packages_api_period_in_seconds, :throttle_unauthenticated_packages_api_requests_per_period, :throttle_unauthenticated_period_in_seconds, @@ -613,6 +615,11 @@ def self.kroki_formats_attributes jsonb_accessor :service_ping_settings, gitlab_environment_toolkit_instance: [:boolean, { default: false }] + jsonb_accessor :rate_limits_unauthenticated_git_http, + throttle_unauthenticated_git_http_enabled: [:boolean, { default: false }], + throttle_unauthenticated_git_http_requests_per_period: [:integer, { default: 3600 }], + throttle_unauthenticated_git_http_period_in_seconds: [:integer, { default: 3600 }] + validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" } validates :search_rate_limit_allowlist, diff --git a/app/views/admin/application_settings/_git_http_limits.html.haml b/app/views/admin/application_settings/_git_http_limits.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..fc777a174431013f18ee43824874f4327fc4d10f --- /dev/null +++ b/app/views/admin/application_settings/_git_http_limits.html.haml @@ -0,0 +1,18 @@ += gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-git-http-limits-settings'), html: { class: 'fieldset-form' } do |f| + = form_errors(@application_setting) + + %fieldset + %h5 + = _('Unauthenticated Git HTTP request rate limit') + .form-group + = f.gitlab_ui_checkbox_component :throttle_unauthenticated_git_http_enabled, + _('Enable unauthenticated Git HTTP request rate limit'), + help_text: _('Helps reduce unauthenticated Git HTTP request volume for git paths.') + .form-group + = f.label :throttle_unauthenticated_git_http_requests_per_period, _('Maximum unauthenticated Git HTTP requests per period per IP'), class: 'gl-font-weight-bold' + = f.number_field :throttle_unauthenticated_git_http_requests_per_period, class: 'form-control gl-form-input' + .form-group + = f.label :throttle_unauthenticated_git_http_period_in_seconds, _('Unauthenticated Git HTTP rate limit period in seconds'), class: 'gl-font-weight-bold' + = f.number_field :throttle_unauthenticated_git_http_period_in_seconds, class: 'form-control gl-form-input' + + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml index 86fbbef8dac87e9d5ec5f6cb63ab16a6105b4e9b..b951c97814f7ec88de2afc8dcbf0ecbf1a1d46fa 100644 --- a/app/views/admin/application_settings/network.html.haml +++ b/app/views/admin/application_settings/network.html.haml @@ -72,6 +72,18 @@ .settings-content = render partial: 'network_rate_limits', locals: { anchor: 'js-deprecated-limits-settings', setting_fragment: 'deprecated_api' } +%section.settings.as-git-http-limits.no-animate#js-git-http-limits-settings{ class: ('expanded' if expanded_by_default?) } + .settings-header + %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only + = _('Git HTTP rate limits') + = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do + = expanded_by_default? ? _('Collapse') : _('Expand') + %p.gl-text-secondary + = _('Configure specific limits for Git HTTP requests.') + = link_to _('Learn more.'), help_page_path('administration/settings/git_http_rate_limits'), target: '_blank', rel: 'noopener noreferrer' + .settings-content + = render 'git_http_limits' + %section.settings.as-git-lfs-limits.no-animate#js-git-lfs-limits-settings{ class: ('expanded' if expanded_by_default?) } .settings-header %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only diff --git a/db/migrate/20240405090000_add_throttle_unauthenticated_git_http_to_application_settings.rb b/db/migrate/20240405090000_add_throttle_unauthenticated_git_http_to_application_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..1881b8d630b856a142a65bf9d9a055484ece9cb4 --- /dev/null +++ b/db/migrate/20240405090000_add_throttle_unauthenticated_git_http_to_application_settings.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class AddThrottleUnauthenticatedGitHttpToApplicationSettings < Gitlab::Database::Migration[2.2] + milestone '17.0' + + disable_ddl_transaction! + + def up + add_column :application_settings, :rate_limits_unauthenticated_git_http, :jsonb, default: {}, null: false, + if_not_exists: true + + add_check_constraint( + :application_settings, + "(jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object')", + 'check_application_settings_rate_limits_unauth_git_http_is_hash' + ) + end + + def down + remove_column :application_settings, :rate_limits_unauthenticated_git_http, it_exists: true + end +end diff --git a/db/migrate/20240405090010_update_throttle_unauthenticated_git_http_in_application_settings.rb b/db/migrate/20240405090010_update_throttle_unauthenticated_git_http_in_application_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..d4458912262d09d644c67a477f3805047e66a5d1 --- /dev/null +++ b/db/migrate/20240405090010_update_throttle_unauthenticated_git_http_in_application_settings.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class UpdateThrottleUnauthenticatedGitHttpInApplicationSettings < Gitlab::Database::Migration[2.2] + restrict_gitlab_migration gitlab_schema: :gitlab_main + + milestone '17.0' + + disable_ddl_transaction! + + def up + execute <<~SQL + UPDATE application_settings + SET rate_limits_unauthenticated_git_http = jsonb_build_object( + 'throttle_unauthenticated_git_http_enabled', throttle_unauthenticated_enabled, + 'throttle_unauthenticated_git_http_requests_per_period', throttle_unauthenticated_requests_per_period, + 'throttle_unauthenticated_git_http_period_in_seconds', throttle_unauthenticated_period_in_seconds + ); + SQL + end + + def down + execute "UPDATE application_settings SET rate_limits_unauthenticated_git_http = CAST('{}' AS jsonb)" + end +end diff --git a/db/schema_migrations/20240405090000 b/db/schema_migrations/20240405090000 new file mode 100644 index 0000000000000000000000000000000000000000..42e1ac97298bcc47f6317a723daf23f20c643ab9 --- /dev/null +++ b/db/schema_migrations/20240405090000 @@ -0,0 +1 @@ +1f79208f10eac682970b91dd12159c9c7446fab637409d2f62dc91231af1dd13 \ No newline at end of file diff --git a/db/schema_migrations/20240405090010 b/db/schema_migrations/20240405090010 new file mode 100644 index 0000000000000000000000000000000000000000..3b93267c8f9955c9cd9a9a54544db2c4ab10d6a2 --- /dev/null +++ b/db/schema_migrations/20240405090010 @@ -0,0 +1 @@ +c84be5380fb2c1e90aabd987b8a7c020ec17405a8d0b97f0ca44e4ea724b7c6d \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 4a030710d3bac1723b03594673384024421e1663..53bf60f9e2b159f8350892299dcace955323903e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -4319,6 +4319,7 @@ CREATE TABLE application_settings ( include_optional_metrics_in_service_ping boolean DEFAULT true NOT NULL, zoekt_settings jsonb DEFAULT '{}'::jsonb NOT NULL, service_ping_settings jsonb DEFAULT '{}'::jsonb NOT NULL, + rate_limits_unauthenticated_git_http jsonb DEFAULT '{}'::jsonb NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), @@ -4371,6 +4372,7 @@ CREATE TABLE application_settings ( CONSTRAINT check_app_settings_sentry_clientside_traces_sample_rate_range CHECK (((sentry_clientside_traces_sample_rate >= (0)::double precision) AND (sentry_clientside_traces_sample_rate <= (1)::double precision))), CONSTRAINT check_application_settings_clickhouse_is_hash CHECK ((jsonb_typeof(clickhouse) = 'object'::text)), CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)), + CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)), CONSTRAINT check_application_settings_service_ping_settings_is_hash CHECK ((jsonb_typeof(service_ping_settings) = 'object'::text)), CONSTRAINT check_b8c74ea5b3 CHECK ((char_length(deactivation_email_additional_text) <= 1000)), CONSTRAINT check_cdfbd99405 CHECK ((char_length(security_txt_content) <= 2048)), diff --git a/doc/administration/settings/git_http_rate_limits.md b/doc/administration/settings/git_http_rate_limits.md new file mode 100644 index 0000000000000000000000000000000000000000..751e41eec9b4afd599c21515065dc590966cfa1b --- /dev/null +++ b/doc/administration/settings/git_http_rate_limits.md @@ -0,0 +1,41 @@ +--- +stage: Create +group: Source Code +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# Rate limits on Git HTTP + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** Self-managed, GitLab Dedicated + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147112) in GitLab 17.0. + +If you use Git HTTP in your repository, +common Git operations can generate many Git HTTP requests. +Some of these Git HTTP requests do not contain authentication parameter and +are considered unauthenticated. You can enforce rate limits on Git HTTP requests. +This can improve the security and durability of your web application. +[General user and IP rate limits](../settings/user_and_ip_rate_limits.md) aren't applied +to Git HTTP requests. + +## Configure Git HTTP rate limits + +Git HTTP rate limits are disabled by default. If enabled and configured, these limits +are applied to Git HTTP requests. + +To configure Git HTTP rate limits: + +1. On the left sidebar, at the bottom, select **Admin Area**. +1. Select **Settings > Network**. +1. Expand **Git HTTP rate limits**. +1. Select **Enable unauthenticated Git HTTP request rate limit**. +1. Enter a value for **Max unauthenticated Git HTTP requests per period per user**. +1. Enter a value for **Unauthenticated Git HTTP rate limit period in seconds**. +1. Select **Save changes**. + +## Related topics + +- [Rate limiting](../../security/rate_limits.md) +- [User and IP rate limits](../settings/user_and_ip_rate_limits.md) diff --git a/doc/administration/settings/rate_limits.md b/doc/administration/settings/rate_limits.md index 89e64344e0c3f60fb04383f93308c7bd771b670d..3bcd47ebdc3103189cfaaa4f19353da95b5d30ae 100644 --- a/doc/administration/settings/rate_limits.md +++ b/doc/administration/settings/rate_limits.md @@ -9,6 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w You can change network settings to limit the rate of connections with your instance. - [Deprecated API rate limits](deprecated_api_rate_limits.md) +- [Git HTTP](git_http_rate_limits.md) - [Git LFS](git_lfs_rate_limits.md) - [Git SSH operations](rate_limits_on_git_ssh_operations.md) - [Incident management](incident_management_rate_limits.md) diff --git a/lib/gitlab/rack_attack.rb b/lib/gitlab/rack_attack.rb index 2182f5b56e456150caaff5dd135e143ae1a64e6c..113c6dec6c1b9d0c37783f75c9033c4c153c4486 100644 --- a/lib/gitlab/rack_attack.rb +++ b/lib/gitlab/rack_attack.rb @@ -126,6 +126,16 @@ def self.throttle_definitions 'throttle_authenticated_git_lfs' => ThrottleDefinition.new( Gitlab::Throttle.throttle_authenticated_git_lfs_options, ->(req) { req.throttled_identifer([:api]) if req.throttle_authenticated_git_lfs? } + ), + **throttle_definitions_unauthenticated_git_http + } + end + + def self.throttle_definitions_unauthenticated_git_http + { + 'throttle_unauthenticated_git_http' => ThrottleDefinition.new( + Gitlab::Throttle.throttle_unauthenticated_git_http_options, + ->(req) { req.ip if req.throttle_unauthenticated_git_http? } ) } end diff --git a/lib/gitlab/rack_attack/request.rb b/lib/gitlab/rack_attack/request.rb index e45782b8be0b8b3d2f1857439bd37b1048d25d4a..63c0215c65a2b2828b200dcfb8040643ff515f44 100644 --- a/lib/gitlab/rack_attack/request.rb +++ b/lib/gitlab/rack_attack/request.rb @@ -100,6 +100,7 @@ def throttle_unauthenticated_api? def throttle_unauthenticated_web? (web_request? || frontend_request?) && !should_be_skipped? && + !git_path? && # TODO: Column will be renamed in https://gitlab.com/gitlab-org/gitlab/-/issues/340031 Gitlab::Throttle.settings.throttle_unauthenticated_enabled && unauthenticated? @@ -175,6 +176,12 @@ def throttle_authenticated_packages_api? Gitlab::Throttle.settings.throttle_authenticated_packages_api_enabled end + def throttle_unauthenticated_git_http? + git_path? && + Gitlab::Throttle.settings.throttle_unauthenticated_git_http_enabled && + unauthenticated? + end + def throttle_authenticated_git_lfs? git_lfs_path? && Gitlab::Throttle.settings.throttle_authenticated_git_lfs_enabled @@ -242,6 +249,10 @@ def packages_api_path? matches?(::Gitlab::Regex::Packages::API_PATH_REGEX) end + def git_path? + matches?(::Gitlab::PathRegex.repository_git_route_regex) + end + def git_lfs_path? matches?(::Gitlab::PathRegex.repository_git_lfs_route_regex) end diff --git a/lib/gitlab/throttle.rb b/lib/gitlab/throttle.rb index 384953533b5e9becdd686f42274eb3bb9fdf3025..1aef19f1e6a453699096f075f5953c17e225898f 100644 --- a/lib/gitlab/throttle.rb +++ b/lib/gitlab/throttle.rb @@ -71,6 +71,13 @@ def self.protected_paths_options { limit: limit_proc, period: period_proc } end + def self.throttle_unauthenticated_git_http_options + limit_proc = proc { |req| settings.throttle_unauthenticated_git_http_requests_per_period } + period_proc = proc { |req| settings.throttle_unauthenticated_git_http_period_in_seconds.seconds } + + { limit: limit_proc, period: period_proc } + end + def self.throttle_authenticated_git_lfs_options limit_proc = proc { |req| settings.throttle_authenticated_git_lfs_requests_per_period } period_proc = proc { |req| settings.throttle_authenticated_git_lfs_period_in_seconds.seconds } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index acbed3ec35ee27f05ae2f7a9f021a4812a981c2d..d2872dc7f442824f5e47d6244bce946c804611af 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -13681,6 +13681,9 @@ msgstr "" msgid "Configure specific limits for Files API requests that supersede the general user and IP rate limits." msgstr "" +msgid "Configure specific limits for Git HTTP requests." +msgstr "" + msgid "Configure specific limits for Git LFS requests that supersede the general user and IP rate limits." msgstr "" @@ -19707,6 +19710,9 @@ msgstr "" msgid "Enable unauthenticated API request rate limit" msgstr "" +msgid "Enable unauthenticated Git HTTP request rate limit" +msgstr "" + msgid "Enable unauthenticated web request rate limit" msgstr "" @@ -23076,6 +23082,9 @@ msgstr "" msgid "Git" msgstr "" +msgid "Git HTTP rate limits" +msgstr "" + msgid "Git LFS is not enabled on this GitLab server, contact your admin." msgstr "" @@ -25671,6 +25680,9 @@ msgstr "" msgid "Helps reduce request volume for protected paths." msgstr "" +msgid "Helps reduce unauthenticated Git HTTP request volume for git paths." +msgstr "" + msgid "Hi %{recipient_name}," msgstr "" @@ -31379,6 +31391,9 @@ msgstr "" msgid "Maximum unauthenticated API requests per rate limit period per IP" msgstr "" +msgid "Maximum unauthenticated Git HTTP requests per period per IP" +msgstr "" + msgid "Maximum unauthenticated web requests per rate limit period per IP" msgstr "" @@ -54784,6 +54799,12 @@ msgstr "" msgid "Unauthenticated API rate limit period in seconds" msgstr "" +msgid "Unauthenticated Git HTTP rate limit period in seconds" +msgstr "" + +msgid "Unauthenticated Git HTTP request rate limit" +msgstr "" + msgid "Unauthenticated requests" msgstr "" diff --git a/spec/lib/gitlab/rack_attack/request_spec.rb b/spec/lib/gitlab/rack_attack/request_spec.rb index 92c9acb83cf67f7bd92480d4d7b397774cf96bb1..a076cb557a061d7c74d4d1e48d9278786327123a 100644 --- a/spec/lib/gitlab/rack_attack/request_spec.rb +++ b/spec/lib/gitlab/rack_attack/request_spec.rb @@ -248,6 +248,38 @@ end end + describe '#throttle_unauthenticated_git_http?' do + let_it_be(:project) { create(:project) } + + let(:git_clone_project_path_get_info_refs) { "/#{project.full_path}.git/info/refs?service=git-upload-pack" } + let(:git_clone_path_post_git_upload_pack) { "/#{project.full_path}.git/git-upload-pack" } + + subject { request.throttle_unauthenticated_git_http? } + + where(:path, :request_unauthenticated?, :application_setting_throttle_unauthenticated_git_http_enabled, :expected) do + ref(:git_clone_project_path_get_info_refs) | true | true | true + ref(:git_clone_project_path_get_info_refs) | false | true | false + ref(:git_clone_project_path_get_info_refs) | true | false | false + ref(:git_clone_project_path_get_info_refs) | false | false | false + + ref(:git_clone_path_post_git_upload_pack) | true | true | true + ref(:git_clone_path_post_git_upload_pack) | false | false | false + + '/users/sign_in' | true | true | false + '/users/sign_in' | false | false | false + end + + with_them do + before do + stub_application_setting(throttle_unauthenticated_git_http_enabled: application_setting_throttle_unauthenticated_git_http_enabled) + + allow(request).to receive(:unauthenticated?).and_return(request_unauthenticated?) + end + + it { is_expected.to eq expected } + end + end + describe '#protected_path?' do subject { request.protected_path? } diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb index 28cb295d3edd1c8ba0d70171a260ed3b6849794f..56473dbc7d7faa1293c5920abedc051d2534867a 100644 --- a/spec/requests/rack_attack_global_spec.rb +++ b/spec/requests/rack_attack_global_spec.rb @@ -5,6 +5,7 @@ RSpec.describe 'Rack Attack global throttles', :use_clean_rails_memory_store_caching, feature_category: :system_access do include RackAttackSpecHelpers + include WorkhorseHelpers include SessionHelpers let(:settings) { Gitlab::CurrentSettings.current_application_settings } @@ -27,6 +28,8 @@ throttle_unauthenticated_packages_api_period_in_seconds: 1, throttle_authenticated_packages_api_requests_per_period: 100, throttle_authenticated_packages_api_period_in_seconds: 1, + throttle_unauthenticated_git_http_requests_per_period: 100, + throttle_unauthenticated_git_http_period_in_seconds: 1, throttle_authenticated_git_lfs_requests_per_period: 100, throttle_authenticated_git_lfs_period_in_seconds: 1, throttle_unauthenticated_files_api_requests_per_period: 100, @@ -697,6 +700,45 @@ def do_request end end + describe 'unauthenticated git http requests' do + let_it_be(:project) { create(:project, :repository, :public) } + + let(:git_http_clone_path) { "/#{project.full_path}.git/info/refs?service=git-upload-pack" } + + it_behaves_like 'rate-limited unauthenticated requests' do + let(:throttle_name) { 'throttle_unauthenticated_git_http' } + let(:throttle_setting_prefix) { 'throttle_unauthenticated_git_http' } + let(:url_that_does_not_require_authentication) { "/#{project.full_path}.git/info/refs?service=git-upload-pack" } + let(:url_that_is_not_matched) { '/users/sign_in' } + let(:headers) { WorkhorseHelpers.workhorse_internal_api_request_header } + end + + context 'when authenticated' do + let_it_be(:user) { create(:user) } + let_it_be(:token) { create(:personal_access_token, user: user) } + + let(:headers) { WorkhorseHelpers.workhorse_internal_api_request_header.merge(basic_auth_headers(user, token)) } + + def do_request + get git_http_clone_path, headers: headers + end + + before do + settings_to_set[:throttle_unauthenticated_git_http_requests_per_period] = requests_per_period + settings_to_set[:throttle_unauthenticated_git_http_period_in_seconds] = period_in_seconds + settings_to_set[:throttle_unauthenticated_git_http_enabled] = true + stub_application_setting(settings_to_set) + end + + it 'rejects requests over the rate limit' do + (requests_per_period + 1).times do + do_request + expect(response).to have_gitlab_http_status(:ok) + end + end + end + end + describe 'authenticated git lfs requests', :api do let_it_be(:project) { create(:project, :internal) } let_it_be(:user) { create(:user) } diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb index 89ae165f3fab6bf709fa9750f5a063df9ad5264e..d15c88244f84b72620c1540b0b26865b11f40ac0 100644 --- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb +++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb @@ -459,7 +459,10 @@ def reset_rack_attack # * requests_per_period # * period_in_seconds # * period +# * headers RSpec.shared_examples 'rate-limited unauthenticated requests' do + let(:headers) { {} } + before do # Set low limits settings_to_set[:"#{throttle_setting_prefix}_requests_per_period"] = requests_per_period @@ -467,6 +470,10 @@ def reset_rack_attack travel_back end + def do_request + get url_that_does_not_require_authentication, headers: headers + end + context 'when the throttle is enabled' do before do settings_to_set[:"#{throttle_setting_prefix}_enabled"] = true @@ -476,12 +483,12 @@ def reset_rack_attack it 'rejects requests over the rate limit' do # At first, allow requests under the rate limit. requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end # the last straw - expect_rejection { get url_that_does_not_require_authentication } + expect_rejection { do_request } end context 'with custom response text' do @@ -492,37 +499,37 @@ def reset_rack_attack it 'rejects requests over the rate limit' do # At first, allow requests under the rate limit. requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end # the last straw - expect_rejection { get url_that_does_not_require_authentication } + expect_rejection { do_request } expect(response.body).to eq("Custom response\n") end end it 'allows requests after throttling and then waiting for the next period' do requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end - expect_rejection { get url_that_does_not_require_authentication } + expect_rejection { do_request } travel_to(period.from_now) do requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end - expect_rejection { get url_that_does_not_require_authentication } + expect_rejection { do_request } end end it 'counts requests from different IPs separately' do requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end @@ -531,7 +538,7 @@ def reset_rack_attack end # would be over limit for the same IP - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end @@ -603,7 +610,7 @@ def reset_rack_attack it 'logs RackAttack info into structured logs' do requests_per_period.times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end @@ -619,12 +626,12 @@ def reset_rack_attack expect(Gitlab::AuthLogger).to receive(:error).with(arguments) - get url_that_does_not_require_authentication + do_request end it_behaves_like 'tracking when dry-run mode is set' do def do_request - get url_that_does_not_require_authentication + get url_that_does_not_require_authentication, headers: headers end end end @@ -637,7 +644,7 @@ def do_request it 'allows requests over the rate limit' do (1 + requests_per_period).times do - get url_that_does_not_require_authentication + do_request expect(response).to have_gitlab_http_status(:ok) end end diff --git a/spec/views/admin/application_settings/network.html.haml_spec.rb b/spec/views/admin/application_settings/network.html.haml_spec.rb index 193ee8a32d5adee5d94c6e86264bdf224b1a1211..defaa97f82ab616c84455421f42ef2fe02d7865a 100644 --- a/spec/views/admin/application_settings/network.html.haml_spec.rb +++ b/spec/views/admin/application_settings/network.html.haml_spec.rb @@ -11,6 +11,16 @@ allow(view).to receive(:current_user) { admin } end + context 'for Git HTTP rate limit' do + it 'renders the `git_http_rate_limit_unauthenticated` field' do + render + + expect(rendered).to have_field('application_setting_throttle_unauthenticated_git_http_enabled') + expect(rendered).to have_field('application_setting_throttle_unauthenticated_git_http_requests_per_period') + expect(rendered).to have_field('application_setting_throttle_unauthenticated_git_http_period_in_seconds') + end + end + context 'for Projects API rate limit' do it 'renders the `projects_api_rate_limit_unauthenticated` field' do render