lib/pact_broker/webhooks/service.rb in pact_broker-2.31.0 vs lib/pact_broker/webhooks/service.rb in pact_broker-2.32.0
- old
+ new
@@ -7,10 +7,11 @@
require 'pact_broker/webhooks/triggered_webhook'
require 'pact_broker/webhooks/status'
require 'pact_broker/webhooks/webhook_event'
require 'pact_broker/verifications/placeholder_verification'
require 'pact_broker/pacts/placeholder_pact'
+require 'pact_broker/api/decorators/webhook_decorator'
module PactBroker
module Webhooks
class Service
@@ -38,11 +39,14 @@
def self.find_by_uuid uuid
webhook_repository.find_by_uuid uuid
end
- def self.update_by_uuid uuid, webhook
+ def self.update_by_uuid uuid, params
+ webhook = webhook_repository.find_by_uuid(uuid)
+ maintain_redacted_params(webhook, params)
+ PactBroker::Api::Decorators::WebhookDecorator.new(webhook).from_hash(params)
webhook_repository.update_by_uuid uuid, webhook
end
def self.delete_by_uuid uuid
webhook_repository.delete_triggered_webhooks_by_webhook_uuid uuid
@@ -61,35 +65,39 @@
def self.find_all
webhook_repository.find_all
end
- def self.test_execution webhook
- options = { failure_log_message: "Webhook execution failed", show_response: PactBroker.configuration.show_webhook_response?, base_url: base_url}
+ def self.test_execution webhook, options
+ execution_options = options[:execution_options].merge(
+ failure_log_message: "Webhook execution failed",
+ )
+ merged_options = options.merge(execution_options: execution_options)
verification = nil
if webhook.trigger_on_provider_verification_published?
verification = verification_service.search_for_latest(webhook.consumer_name, webhook.provider_name) || PactBroker::Verifications::PlaceholderVerification.new
end
pact = pact_service.search_for_latest_pact(consumer_name: webhook.consumer_name, provider_name: webhook.provider_name) || PactBroker::Pacts::PlaceholderPact.new
- webhook.execute(pact, verification, options)
+ webhook.execute(pact, verification, merged_options)
end
- def self.execute_webhook_now webhook, pact, verification = nil
- triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, verification, USER)
- options = { failure_log_message: "Webhook execution failed"}
- webhook_execution_result = execute_triggered_webhook_now triggered_webhook, options
- if webhook_execution_result.success?
- webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_SUCCESS
- else
- webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_FAILURE
- end
- webhook_execution_result
- end
+ # # TODO delete?
+ # def self.execute_webhook_now webhook, pact, verification = nil
+ # triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, verification, USER)
+ # execution_options = { failure_log_message: "Webhook execution failed"}
+ # webhook_execution_result = execute_triggered_webhook_now triggered_webhook, execution_options
+ # if webhook_execution_result.success?
+ # webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_SUCCESS
+ # else
+ # webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_FAILURE
+ # end
+ # webhook_execution_result
+ # end
- def self.execute_triggered_webhook_now triggered_webhook, options
- webhook_execution_result = triggered_webhook.execute options.merge(show_response: PactBroker.configuration.show_webhook_response?)
+ def self.execute_triggered_webhook_now triggered_webhook, webhook_options
+ webhook_execution_result = triggered_webhook.execute webhook_options
webhook_repository.create_execution triggered_webhook, webhook_execution_result
webhook_execution_result
end
def self.update_triggered_webhook_status triggered_webhook, status
@@ -106,47 +114,40 @@
def self.find_by_consumer_and_provider consumer, provider
webhook_repository.find_by_consumer_and_provider consumer, provider
end
- def self.trigger_webhooks pact, verification, event_name
+ def self.trigger_webhooks pact, verification, event_name, options
webhooks = webhook_repository.find_by_consumer_and_or_provider_and_event_name pact.consumer, pact.provider, event_name
if webhooks.any?
- run_later(webhooks, pact, verification, event_name)
+ run_later(webhooks, pact, verification, event_name, options)
else
- logger.debug "No webhook found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\""
+ logger.debug "No enabled webhooks found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\" and event #{event_name}"
end
end
- def self.run_later webhooks, pact, verification, event_name
+ def self.run_later webhooks, pact, verification, event_name, options
trigger_uuid = next_uuid
webhooks.each do | webhook |
begin
triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION)
logger.info "Scheduling job for #{webhook.description} with uuid #{webhook.uuid}"
job_data = {
triggered_webhook: triggered_webhook,
- database_connector: job_database_connector,
- base_url: base_url
+ webhook_context: options.fetch(:webhook_context),
+ execution_options: options.fetch(:execution_options),
+ database_connector: options.fetch(:database_connector)
}
# Delay slightly to make sure the request transaction has finished before we execute the webhook
Job.perform_in(5, job_data)
rescue StandardError => e
log_error e
end
end
end
- def self.job_database_connector
- Thread.current[:pact_broker_thread_data].database_connector
- end
-
- def self.base_url
- Thread.current[:pact_broker_thread_data].base_url
- end
-
def self.find_latest_triggered_webhooks_for_pact pact
webhook_repository.find_latest_triggered_webhooks_for_pact pact
end
def self.find_latest_triggered_webhooks consumer, provider
@@ -161,9 +162,34 @@
webhook_repository.find_triggered_webhooks_for_pact(pact)
end
def self.find_triggered_webhooks_for_verification verification
webhook_repository.find_triggered_webhooks_for_verification(verification)
+ end
+
+ private
+
+ # Dirty hack to maintain existing password or Authorization header if it is submitted with value ****
+ # This is required because the password and Authorization header is **** out in the API response
+ # for security purposes, so it would need to be re-entered with every response.
+ # TODO implement proper 'secrets' management.
+ def self.maintain_redacted_params(webhook, params)
+ if webhook.request.password && password_key_does_not_exist_or_is_starred?(params)
+ params['request']['password'] = webhook.request.password
+ end
+
+ new_headers = params['request']['headers'] ||= {}
+ existing_headers = webhook.request.headers
+ starred_new_headers = new_headers.select { |key, value| value =~ /^\**$/ }
+ starred_new_headers.each do | (key, value) |
+ new_headers[key] = existing_headers[key]
+ end
+ params['request']['headers'] = new_headers
+ params
+ end
+
+ def self.password_key_does_not_exist_or_is_starred?(params)
+ !params['request'].key?('password') || params.dig('request','password') =~ /^\**$/
end
end
end
end