Add rate limiting to guard against excessive scheduling of pipelines
This commit is contained in:
parent
f8c3a58a54
commit
54f13b1ec8
|
@ -42,6 +42,13 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def play
|
||||
limiter = ::Gitlab::ActionRateLimiter.new(action: 'play_pipeline_schedule')
|
||||
|
||||
if limiter.throttled?(throttle_key, 1)
|
||||
flash[:notice] = 'You cannot play this scheduled pipeline at the moment. Please wait a minute.'
|
||||
return redirect_to pipeline_schedules_path(@project)
|
||||
end
|
||||
|
||||
job_id = RunPipelineScheduleWorker.perform_async(schedule.id, current_user.id)
|
||||
|
||||
flash[:notice] =
|
||||
|
@ -74,6 +81,10 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def throttle_key
|
||||
"user:#{current_user.id}:schedule:#{schedule.id}"
|
||||
end
|
||||
|
||||
def schedule
|
||||
@schedule ||= project.pipeline_schedules.find(params[:id])
|
||||
end
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
module Gitlab
|
||||
# This class implements a simple rate limiter that can be used to throttle
|
||||
# certain actions. Unlike Rack Attack and Rack::Throttle, which operate at
|
||||
# the middleware level, this can be used at the controller level.
|
||||
class ActionRateLimiter
|
||||
TIME_TO_EXPIRE = 60 # 1 min
|
||||
|
||||
attr_accessor :action, :expiry_time
|
||||
|
||||
def initialize(action:, expiry_time: TIME_TO_EXPIRE)
|
||||
@action = action
|
||||
@expiry_time = expiry_time
|
||||
end
|
||||
|
||||
def increment(key)
|
||||
value = 0
|
||||
|
||||
Gitlab::Redis::Cache.with do |redis|
|
||||
cache_key = "action_rate_limiter:#{action}:#{key}"
|
||||
value = redis.incr(cache_key)
|
||||
redis.expire(cache_key, expiry_time) if value == 1
|
||||
end
|
||||
|
||||
value.to_i
|
||||
end
|
||||
|
||||
def throttled?(key, threshold_value)
|
||||
self.increment(key) > threshold_value
|
||||
end
|
||||
end
|
||||
end
|
|
@ -366,7 +366,7 @@ describe Projects::PipelineSchedulesController do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST #play' do
|
||||
describe 'POST #play', :clean_gitlab_redis_cache do
|
||||
set(:user) { create(:user) }
|
||||
let(:ref) { 'master' }
|
||||
|
||||
|
|
Loading…
Reference in New Issue