Module: Gitlab::WebHooks::RecursionDetection

Defined in:
lib/gitlab/web_hooks/recursion_detection.rb,
lib/gitlab/web_hooks/recursion_detection/uuid.rb

Defined Under Namespace

Classes: UUID

Constant Summary collapse

COUNT_LIMIT =
100
TOUCH_CACHE_TTL =
30.minutes

Class Method Summary collapse

Class Method Details

.block?(hook) ⇒ Boolean

Returns true if the webhook ID is present in the cache, or if the number of IDs in the cache exceeds the limit (see ‘#cache_key_for_hook` for details of the cache).

Returns:

  • (Boolean)


53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 53

def block?(hook)
  # If a request UUID has not been set then we know the request was not
  # made by a webhook, and no recursion is possible.
  return false unless UUID.instance.request_uuid

  cache_key = cache_key_for_hook(hook)

  ::Gitlab::Redis::SharedState.with do |redis|
    redis.sismember(cache_key, hook.id) ||
      redis.scard(cache_key) >= COUNT_LIMIT
  end
end

.header(hook) ⇒ Object



66
67
68
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 66

def header(hook)
  UUID.instance.header(hook)
end

.register!(hook) ⇒ Object

Before a webhook is executed, ‘.register!` should be called. Adds the webhook ID to a cache (see `#cache_key_for_hook` for details of the cache).



39
40
41
42
43
44
45
46
47
48
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 39

def register!(hook)
  cache_key = cache_key_for_hook(hook)

  ::Gitlab::Redis::SharedState.with do |redis|
    redis.multi do |multi|
      multi.sadd?(cache_key, hook.id)
      multi.expire(cache_key, TOUCH_CACHE_TTL)
    end
  end
end

.set_from_headers(headers) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 24

def set_from_headers(headers)
  uuid = headers[UUID::HEADER]

  return unless uuid

  set_request_uuid(uuid)
end

.set_request_uuid(uuid) ⇒ Object



32
33
34
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 32

def set_request_uuid(uuid)
  UUID.instance.request_uuid = uuid
end

.to_log(hook) ⇒ Object



70
71
72
73
74
75
# File 'lib/gitlab/web_hooks/recursion_detection.rb', line 70

def to_log(hook)
  {
    uuid: UUID.instance.uuid_for_hook(hook),
    ids: ::Gitlab::Redis::SharedState.with { |redis| redis.smembers(cache_key_for_hook(hook)).map(&:to_i) }
  }
end