2021-09-04 01:27:46 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module WebHooks
|
|
|
|
class LogExecutionService
|
2022-05-07 20:08:51 +05:30
|
|
|
include ::Gitlab::ExclusiveLeaseHelpers
|
|
|
|
|
|
|
|
LOCK_TTL = 15.seconds.freeze
|
|
|
|
LOCK_SLEEP = 0.25.seconds.freeze
|
|
|
|
LOCK_RETRY = 65
|
|
|
|
|
2021-09-04 01:27:46 +05:30
|
|
|
attr_reader :hook, :log_data, :response_category
|
|
|
|
|
|
|
|
def initialize(hook:, log_data:, response_category:)
|
|
|
|
@hook = hook
|
2022-05-07 20:08:51 +05:30
|
|
|
@log_data = log_data.transform_keys(&:to_sym)
|
2021-09-04 01:27:46 +05:30
|
|
|
@response_category = response_category
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute
|
2023-03-04 22:38:38 +05:30
|
|
|
update_hook_failure_state
|
2021-09-04 01:27:46 +05:30
|
|
|
log_execution
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def log_execution
|
2023-03-04 22:38:38 +05:30
|
|
|
mask_response_headers
|
|
|
|
|
2023-01-10 11:22:00 +05:30
|
|
|
log_data[:request_headers]['X-Gitlab-Token'] = _('[REDACTED]') if hook.token?
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
WebHookLog.create!(web_hook: hook, **log_data)
|
2021-09-04 01:27:46 +05:30
|
|
|
end
|
|
|
|
|
2023-03-04 22:38:38 +05:30
|
|
|
def mask_response_headers
|
|
|
|
return unless hook.url_variables?
|
|
|
|
return unless log_data.key?(:response_headers)
|
|
|
|
|
|
|
|
variables_map = hook.url_variables.invert.transform_values { "{#{_1}}" }
|
|
|
|
regex = Regexp.union(variables_map.keys)
|
|
|
|
|
|
|
|
log_data[:response_headers].transform_values! do |value|
|
|
|
|
regex === value ? value.gsub(regex, variables_map) : value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
# Perform this operation within an `Gitlab::ExclusiveLease` lock to make it
|
|
|
|
# safe to be called concurrently from different workers.
|
|
|
|
def update_hook_failure_state
|
|
|
|
in_lock(lock_name, ttl: LOCK_TTL, sleep_sec: LOCK_SLEEP, retries: LOCK_RETRY) do |retried|
|
|
|
|
hook.reset # Reload within the lock so properties are guaranteed to be current.
|
|
|
|
|
|
|
|
case response_category
|
|
|
|
when :ok
|
|
|
|
hook.enable!
|
|
|
|
when :error
|
|
|
|
hook.backoff!
|
|
|
|
when :failed
|
|
|
|
hook.failed!
|
|
|
|
end
|
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
hook.update_last_failure
|
2021-09-04 01:27:46 +05:30
|
|
|
end
|
2022-05-07 20:08:51 +05:30
|
|
|
rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
|
|
|
|
raise if raise_lock_error?
|
|
|
|
end
|
|
|
|
|
|
|
|
def lock_name
|
|
|
|
"web_hooks:update_hook_failure_state:#{hook.id}"
|
|
|
|
end
|
|
|
|
|
|
|
|
# Allow an error to be raised after failing to obtain a lease only if the hook
|
|
|
|
# is not already in the correct failure state.
|
|
|
|
def raise_lock_error?
|
|
|
|
hook.reset # Reload so properties are guaranteed to be current.
|
|
|
|
|
|
|
|
hook.executable? != (response_category == :ok)
|
2021-09-04 01:27:46 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|