Commit 5f21e69a authored by Thong Kuah's avatar Thong Kuah

Merge branch 'rate-limit-imports' into 'master'

Rate limit project imports

See merge request gitlab-org/gitlab!22644
parents a1e25532 ba72aa4c
# frozen_string_literal: true
class Import::BaseController < ApplicationController
before_action :import_rate_limit, only: [:create]
private
# rubocop: disable CodeReuse/ActiveRecord
......@@ -37,4 +39,18 @@ class Import::BaseController < ApplicationController
def project_save_error(project)
project.errors.full_messages.join(', ')
end
def import_rate_limit
key = "project_import".to_sym
if rate_limiter.throttled?(key, scope: [current_user, key])
rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
redirect_back_or_default(options: { alert: _('This endpoint has been requested too many times. Try again later.') })
end
end
def rate_limiter
::Gitlab::ApplicationRateLimiter
end
end
---
title: Add rate limiter to Project Imports
merge_request: 22644
author:
type: other
......@@ -123,3 +123,13 @@ NOTE: **Note:**
If use of the `Internal` visibility level
[is restricted](../../../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects),
all imported projects are given the visibility of `Private`.
## Rate limits
To help avoid abuse, users are rate limited to:
| Request Type | Limit |
| ---------------- | --------------------------- |
| Export | 1 project per 5 minutes |
| Download export | 10 projects per 10 minutes |
| Import | 30 projects per 10 minutes |
......@@ -22,6 +22,7 @@ module Gitlab
project_export: { threshold: 1, interval: 5.minutes },
project_download_export: { threshold: 10, interval: 10.minutes },
project_generate_new_export: { threshold: 1, interval: 5.minutes },
project_import: { threshold: 30, interval: 10.minutes },
play_pipeline_schedule: { threshold: 1, interval: 1.minute },
show_raw_controller: { threshold: -> { Gitlab::CurrentSettings.current_application_settings.raw_blob_request_limit }, interval: 1.minute }
}.freeze
......
......@@ -136,6 +136,8 @@ describe Import::BitbucketController do
expect(response).to have_gitlab_http_status(422)
end
it_behaves_like 'project import rate limiter'
context "when the repository owner is the Bitbucket user" do
context "when the Bitbucket user and GitLab user's usernames match" do
it "takes the current user's namespace" do
......
......@@ -102,6 +102,8 @@ describe Import::BitbucketServerController do
expect(response).to have_gitlab_http_status(422)
end
it_behaves_like 'project import rate limiter'
end
describe 'POST configure' do
......
......@@ -75,4 +75,8 @@ describe Import::FogbugzController do
expect(assigns(:repos)).to eq([])
end
end
describe 'POST create' do
it_behaves_like 'project import rate limiter'
end
end
......@@ -41,6 +41,8 @@ describe Import::GiteaController do
assign_host_url
end
end
it_behaves_like 'project import rate limiter'
end
describe "GET realtime_changes" do
......
......@@ -71,6 +71,8 @@ describe Import::GithubController do
describe "POST create" do
it_behaves_like 'a GitHub-ish import controller: POST create'
it_behaves_like 'project import rate limiter'
end
describe "GET realtime_changes" do
......
......@@ -282,6 +282,8 @@ describe Import::GitlabController do
expect(response).to have_gitlab_http_status(422)
end
end
it_behaves_like 'project import rate limiter'
end
end
end
......@@ -36,5 +36,7 @@ describe Import::GitlabProjectsController do
expect(response).to have_gitlab_http_status(302)
end
end
it_behaves_like 'project import rate limiter'
end
end
......@@ -58,4 +58,8 @@ describe Import::GoogleCodeController do
expect(assigns(:incompatible_repos)).to eq([@repo])
end
end
describe "POST create" do
it_behaves_like 'project import rate limiter'
end
end
......@@ -88,5 +88,7 @@ describe Import::PhabricatorController do
expect { post_create }.not_to change { current_user.namespace.projects.reload.size }
end
end
it_behaves_like 'project import rate limiter'
end
end
# frozen_string_literal: true
shared_examples 'project import rate limiter' do
let(:user) { create(:user) }
before do
sign_in(user)
end
context 'when limit exceeds' do
before do
allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
end
it 'notifies and redirects user' do
post :create, params: {}
expect(flash[:alert]).to eq('This endpoint has been requested too many times. Try again later.')
expect(response).to have_gitlab_http_status(302)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment