lib/pact_broker/webhooks/service.rb in pact_broker-2.79.1 vs lib/pact_broker/webhooks/service.rb in pact_broker-2.80.0

- old
+ new

@@ -1,45 +1,57 @@ -require 'pact_broker/repositories' -require 'pact_broker/services' -require 'pact_broker/logging' -require 'base64' -require 'securerandom' -require 'pact_broker/webhooks/job' -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' -require 'pact_broker/hash_refinements' -require 'pact_broker/webhooks/execution_configuration' -require 'pact_broker/messages' -require 'pact_broker/webhooks/pact_and_verification_parameters' +require "delegate" +require "pact_broker/repositories" +require "pact_broker/services" +require "pact_broker/logging" +require "base64" +require "securerandom" +require "pact_broker/webhooks/job" +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" +require "pact_broker/hash_refinements" +require "pact_broker/webhooks/execution_configuration" +require "pact_broker/messages" +require "pact_broker/webhooks/pact_and_verification_parameters" +require "pact_broker/feature_toggle" module PactBroker module Webhooks - class Service + module Service using PactBroker::HashRefinements - - RESOURCE_CREATION = PactBroker::Webhooks::TriggeredWebhook::TRIGGER_TYPE_RESOURCE_CREATION - USER = PactBroker::Webhooks::TriggeredWebhook::TRIGGER_TYPE_USER - + extend self + extend Forwardable extend Repositories extend Services include Logging extend PactBroker::Messages + delegate [ + :find_by_uuid, + :find_all, + :update_triggered_webhook_status, + :any_webhooks_configured_for_pact?, + :find_by_consumer_and_provider, + :find_latest_triggered_webhooks_for_pact, + :fail_retrying_triggered_webhooks, + :find_triggered_webhooks_for_pact, + :find_triggered_webhooks_for_verification + ] => :webhook_repository + # Not actually a UUID. Ah well. - def self.valid_uuid_format?(uuid) + def valid_uuid_format?(uuid) !!(uuid =~ /^[A-Za-z0-9_\-]{16,}$/) end - def self.next_uuid + def next_uuid SecureRandom.urlsafe_base64 end - def self.errors webhook, uuid = nil + def errors webhook, uuid = nil contract = PactBroker::Api::Contracts::WebhookContract.new(webhook) contract.validate(webhook.attributes) messages = contract.errors.messages if uuid && !valid_uuid_format?(uuid) @@ -47,132 +59,38 @@ end OpenStruct.new(messages: messages, empty?: messages.empty?, any?: messages.any?) end - def self.create uuid, webhook, consumer, provider + def create uuid, webhook, consumer, provider webhook_repository.create uuid, webhook, consumer, provider end - def self.find_by_uuid uuid - webhook_repository.find_by_uuid uuid - end - - def self.update_by_uuid uuid, params + def 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 + def delete_by_uuid uuid webhook_repository.delete_by_uuid uuid end - def self.delete_all_webhhook_related_objects_by_pacticipant pacticipant - webhook_repository.delete_executions_by_pacticipant pacticipant - webhook_repository.delete_triggered_webhooks_by_pacticipant pacticipant - webhook_repository.delete_by_pacticipant pacticipant + def delete_all_webhhook_related_objects_by_pacticipant pacticipant + webhook_repository.delete_by_pacticipant(pacticipant) end - def self.delete_all_webhook_related_objects_by_pact_publication_ids pact_publication_ids + def delete_all_webhook_related_objects_by_pact_publication_ids pact_publication_ids webhook_repository.delete_triggered_webhooks_by_pact_publication_ids pact_publication_ids end - def self.delete_all_webhook_related_objects_by_verification_ids verification_ids + def delete_all_webhook_related_objects_by_verification_ids verification_ids webhook_repository.delete_triggered_webhooks_by_verification_ids verification_ids end - def self.find_all - webhook_repository.find_all - end - - def self.test_execution webhook, event_context, execution_configuration - merged_options = execution_configuration.with_failure_log_message("Webhook execution failed").to_hash - - 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, event_context.merge(event_name: "test"), merged_options) - end - - def self.execute_triggered_webhook_now triggered_webhook, webhook_execution_configuration_hash - webhook_execution_result = triggered_webhook.execute webhook_execution_configuration_hash - webhook_repository.create_execution triggered_webhook, webhook_execution_result - webhook_execution_result - end - - def self.update_triggered_webhook_status triggered_webhook, status - webhook_repository.update_triggered_webhook_status triggered_webhook, status - end - - def self.find_for_pact pact - webhook_repository.find_for_pact(pact) - end - - def self.find_by_consumer_and_or_provider consumer, provider - webhook_repository.find_by_consumer_and_or_provider(consumer, provider) - end - - 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, event_context, options - webhooks = webhook_repository.find_by_consumer_and_or_provider_and_event_name pact.consumer, pact.provider, event_name - - if webhooks.any? - webhook_execution_configuration = options.fetch(:webhook_execution_configuration).with_webhook_context(event_name: event_name) - # bit messy to merge in base_url here, but easier than a big refactor - base_url = options.fetch(:webhook_execution_configuration).webhook_context.fetch(:base_url) - run_later(webhooks, pact, verification, event_name, event_context.merge(event_name: event_name, base_url: base_url), options.merge(webhook_execution_configuration: webhook_execution_configuration)) - else - logger.info "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, event_context, options - trigger_uuid = next_uuid - webhooks.each do | webhook | - begin - triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION, event_name, event_context) - logger.info "Scheduling job for webhook with uuid #{webhook.uuid}" - logger.debug "Schedule webhook with options #{options}" - job_data = { triggered_webhook: triggered_webhook }.deep_merge(options) - # Delay slightly to make sure the request transaction has finished before we execute the webhook - Job.perform_in(5, job_data) - rescue StandardError => e - logger.warn("Error scheduling webhook execution for webhook with uuid #{webhook.uuid}", e) - end - end - 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 - webhook_repository.find_latest_triggered_webhooks consumer, provider - end - - def self.fail_retrying_triggered_webhooks - webhook_repository.fail_retrying_triggered_webhooks - end - - def self.find_triggered_webhooks_for_pact pact - 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 - - def self.parameters + def parameters PactAndVerificationParameters::ALL.collect do | parameter | OpenStruct.new( name: parameter, description: message("messages.webhooks.parameters.#{parameter}") ) @@ -183,26 +101,26 @@ # 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) + def maintain_redacted_params(webhook, params) if webhook.request.password && password_key_does_not_exist_or_is_starred?(params) - params['request']['password'] = webhook.request.password + params["request"]["password"] = webhook.request.password end - new_headers = params['request']['headers'] ||= {} + 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) | + 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["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') =~ /^\**$/ + def password_key_does_not_exist_or_is_starred?(params) + !params["request"].key?("password") || params.dig("request","password") =~ /^\**$/ end end end end