pact_broker 2.19.2 → 2.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/example/README.md +7 -1
- data/example/config.ru +2 -3
- data/lib/pact_broker/api/contracts/webhook_contract.rb +73 -6
- data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +9 -13
- data/lib/pact_broker/api/resources/base_resource.rb +3 -3
- data/lib/pact_broker/api/resources/pact_webhooks.rb +1 -1
- data/lib/pact_broker/api/resources/webhook_execution.rb +5 -2
- data/lib/pact_broker/configuration.rb +9 -1
- data/lib/pact_broker/doc/views/webhooks.markdown +23 -0
- data/lib/pact_broker/domain/webhook_request.rb +49 -37
- data/lib/pact_broker/locale/en.yml +2 -0
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/check_host_whitelist.rb +22 -0
- data/lib/pact_broker/webhooks/render.rb +23 -0
- data/lib/pact_broker/webhooks/service.rb +2 -1
- data/lib/pact_broker/webhooks/webhook.rb +0 -5
- data/spec/features/create_webhook_spec.rb +2 -3
- data/spec/features/edit_webhook_spec.rb +2 -2
- data/spec/features/execute_webhook_spec.rb +32 -1
- data/spec/fixtures/webhook_valid.json +1 -1
- data/spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb +64 -1
- data/spec/lib/pact_broker/api/decorators/webhook_execution_result_decorator_spec.rb +17 -9
- data/spec/lib/pact_broker/api/resources/pact_spec.rb +1 -1
- data/spec/lib/pact_broker/api/resources/pact_webhooks_spec.rb +3 -3
- data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +3 -1
- data/spec/lib/pact_broker/domain/webhook_request_spec.rb +73 -68
- data/spec/lib/pact_broker/webhooks/check_host_whitelist_spec.rb +47 -0
- data/spec/lib/pact_broker/webhooks/render_spec.rb +36 -0
- data/spec/lib/pact_broker/webhooks/service_spec.rb +7 -0
- data/spec/support/shared_examples_for_responses.rb +2 -2
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e14b4974d382ad35da338f8b493f4ea721105a7c
|
4
|
+
data.tar.gz: 3d27068e75bea109b5bc3bac0262061ce973f574
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf62aadde7feb83cb578fccb4a853530e1d2c3967f9abfc85d649ff9640c58f410bcfaa5b6a0d347444cf1aab47f7bf5e68d00f67c71d34c9d4fc8ebb3fc8e25
|
7
|
+
data.tar.gz: fb663dbb7503fb6f1d43f53c820257844a2573f9cf1913995e22d04f8cc3e15c53acf59e56fe5bb9e049ef5d9d915e660eeec99f58defcc46b5d22d71df392d4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
<a name="v2.20.0"></a>
|
2
|
+
### v2.20.0 (2018-06-03)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* only log webhook response details when a webhook host whitelist has been configured ([3e1c562](/../../commit/3e1c562))
|
8
|
+
* validate webhook host against configurable list on creation ([077e37f](/../../commit/077e37f))
|
9
|
+
* validate webhook scheme and http method against configurable lists on creation ([d7a2b0a](/../../commit/d7a2b0a))
|
10
|
+
* add ${pactbroker.consumerVersionNumber} to webhook templates ([d525527](/../../commit/d525527))
|
11
|
+
|
12
|
+
|
13
|
+
#### Bug Fixes
|
14
|
+
|
15
|
+
* correct all content types that were application/json to application/hal+json ([690e39b](/../../commit/690e39b))
|
16
|
+
|
17
|
+
|
1
18
|
<a name="v2.19.2"></a>
|
2
19
|
### v2.19.2 (2018-05-29)
|
3
20
|
|
data/example/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Run Pact Broker example
|
2
2
|
|
3
|
+
The configuration for this example should not be used in production. Either use the [Docker Pact Broker image][docker-pact-broker], or copy the [pact_broker directory][pact-broker-dir] from the Docker project as your starting point. Ensure you configure a web server/reverse proxy (such as Passenger/Nginx) in front of it (you can also copy the configuration for these from the Docker image.)
|
4
|
+
|
3
5
|
Clone project
|
4
6
|
|
5
7
|
```bash
|
@@ -40,7 +42,7 @@ Set up postgres database
|
|
40
42
|
|
41
43
|
```bash
|
42
44
|
psql postgres -c "CREATE DATABASE pact_broker;"
|
43
|
-
psql postgres -c "CREATE ROLE pact_broker WITH LOGIN PASSWORD '
|
45
|
+
psql postgres -c "CREATE ROLE pact_broker WITH LOGIN PASSWORD 'CHANGE_ME';"
|
44
46
|
psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker TO pact_broker;"
|
45
47
|
```
|
46
48
|
|
@@ -63,3 +65,7 @@ psql pact_broker < example_data.sql
|
|
63
65
|
```
|
64
66
|
|
65
67
|
Now Pact Broker can be access locally at [http://localhost:9292](http://localhost:9292).
|
68
|
+
|
69
|
+
[docker-pact-broker]: https://github.com/DiUS/pact_broker-docker
|
70
|
+
[pact-broker-dir]: https://github.com/DiUS/pact_broker-docker/tree/master/pact_broker
|
71
|
+
|
data/example/config.ru
CHANGED
@@ -11,10 +11,10 @@ DATABASE_CREDENTIALS = {adapter: "sqlite", database: "pact_broker_database.sqlit
|
|
11
11
|
# For postgres:
|
12
12
|
#
|
13
13
|
# $ psql postgres -c "CREATE DATABASE pact_broker;"
|
14
|
-
# $ psql postgres -c "CREATE ROLE pact_broker WITH LOGIN PASSWORD '
|
14
|
+
# $ psql postgres -c "CREATE ROLE pact_broker WITH LOGIN PASSWORD 'CHANGE_ME';"
|
15
15
|
# $ psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker TO pact_broker;"
|
16
16
|
#
|
17
|
-
# DATABASE_CREDENTIALS = {adapter: "postgres", database: "pact_broker", username: 'pact_broker', password: '
|
17
|
+
# DATABASE_CREDENTIALS = {adapter: "postgres", database: "pact_broker", username: 'pact_broker', password: 'CHANGE_ME', :encoding => 'utf8'}
|
18
18
|
|
19
19
|
# Have a look at the Sequel documentation to make decisions about things like connection pooling
|
20
20
|
# and connection validation.
|
@@ -25,7 +25,6 @@ app = PactBroker::App.new do | config |
|
|
25
25
|
# change these from their default values if desired
|
26
26
|
# config.log_dir = "./log"
|
27
27
|
# config.auto_migrate_db = true
|
28
|
-
# config.use_hal_browser = true
|
29
28
|
config.database_connection = Sequel.connect(DATABASE_CREDENTIALS.merge(:logger => config.logger))
|
30
29
|
end
|
31
30
|
|
@@ -1,11 +1,25 @@
|
|
1
1
|
require 'reform'
|
2
2
|
require 'reform/form'
|
3
|
+
require 'pact_broker/webhooks/check_host_whitelist'
|
3
4
|
|
4
5
|
module PactBroker
|
5
6
|
module Api
|
6
7
|
module Contracts
|
7
8
|
class WebhookContract < Reform::Form
|
8
9
|
|
10
|
+
def validate(*)
|
11
|
+
result = super
|
12
|
+
# I just cannot seem to get the validation to stop on the first error.
|
13
|
+
# If one rule fails, they all come back failed, and it's driving me nuts.
|
14
|
+
# Why on earth would I want that behaviour?
|
15
|
+
new_errors = Reform::Contract::Errors.new
|
16
|
+
errors.messages.each do | key, value |
|
17
|
+
new_errors.add(key, value.first)
|
18
|
+
end
|
19
|
+
@errors = new_errors
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
9
23
|
validation do
|
10
24
|
configure do
|
11
25
|
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
@@ -23,20 +37,73 @@ module PactBroker
|
|
23
37
|
configure do
|
24
38
|
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
25
39
|
|
26
|
-
def
|
27
|
-
|
40
|
+
def self.messages
|
41
|
+
super.merge(
|
42
|
+
en: {
|
43
|
+
errors: {
|
44
|
+
allowed_webhook_method?: http_method_error_message,
|
45
|
+
allowed_webhook_scheme?: scheme_error_message,
|
46
|
+
allowed_webhook_host?: host_error_message
|
47
|
+
}
|
48
|
+
}
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.http_method_error_message
|
53
|
+
if PactBroker.configuration.webhook_http_method_whitelist.size == 1
|
54
|
+
"must be #{PactBroker.configuration.webhook_http_method_whitelist.first}. See /doc/webhooks#whitelist for more information."
|
55
|
+
else
|
56
|
+
"must be one of #{PactBroker.configuration.webhook_http_method_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
57
|
+
end
|
28
58
|
end
|
29
59
|
|
30
|
-
def
|
31
|
-
|
60
|
+
def self.scheme_error_message
|
61
|
+
"scheme must be #{PactBroker.configuration.webhook_scheme_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.host_error_message
|
65
|
+
"host must be in the whitelist #{PactBroker.configuration.webhook_host_whitelist.join(",")}. See /doc/webhooks#whitelist for more information."
|
66
|
+
end
|
67
|
+
|
68
|
+
def valid_method?(http_method)
|
69
|
+
Net::HTTP.const_defined?(http_method.capitalize)
|
70
|
+
end
|
71
|
+
|
72
|
+
def valid_url?(url)
|
73
|
+
uri = URI(url)
|
32
74
|
uri.scheme && uri.host
|
33
75
|
rescue URI::InvalidURIError
|
34
76
|
false
|
35
77
|
end
|
78
|
+
|
79
|
+
def allowed_webhook_method?(http_method)
|
80
|
+
PactBroker.configuration.webhook_http_method_whitelist.any? do | allowed_method |
|
81
|
+
http_method.downcase == allowed_method.downcase
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def allowed_webhook_scheme?(url)
|
86
|
+
scheme = URI(url).scheme
|
87
|
+
PactBroker.configuration.webhook_scheme_whitelist.any? do | allowed_scheme |
|
88
|
+
scheme.downcase == allowed_scheme.downcase
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def allowed_webhook_host?(url)
|
93
|
+
if host_whitelist.any?
|
94
|
+
PactBroker::Webhooks::CheckHostWhitelist.call(URI(url).host, host_whitelist).any?
|
95
|
+
else
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def host_whitelist
|
101
|
+
PactBroker.configuration.webhook_host_whitelist
|
102
|
+
end
|
36
103
|
end
|
37
104
|
|
38
|
-
required(:http_method).filled(:valid_method?)
|
39
|
-
required(:url).filled(:valid_url?)
|
105
|
+
required(:http_method).filled(:valid_method?, :allowed_webhook_method?)
|
106
|
+
required(:url).filled(:valid_url?, :allowed_webhook_scheme?, :allowed_webhook_host?)
|
40
107
|
end
|
41
108
|
end
|
42
109
|
|
@@ -1,21 +1,17 @@
|
|
1
1
|
require_relative 'base_decorator'
|
2
2
|
require 'json'
|
3
|
+
require 'pact_broker/messages'
|
3
4
|
|
4
5
|
module PactBroker
|
5
6
|
module Api
|
6
7
|
module Decorators
|
7
|
-
|
8
8
|
class WebhookExecutionResultDecorator < BaseDecorator
|
9
|
-
|
10
9
|
class ErrorDecorator < BaseDecorator
|
11
|
-
|
12
10
|
property :message
|
13
11
|
property :backtrace
|
14
|
-
|
15
12
|
end
|
16
13
|
|
17
14
|
class HTTPResponseDecorator < BaseDecorator
|
18
|
-
|
19
15
|
property :status, :getter => lambda { |_| code.to_i }
|
20
16
|
property :headers, exec_context: :decorator
|
21
17
|
property :body, exec_context: :decorator
|
@@ -36,13 +32,9 @@ module PactBroker
|
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
39
|
-
property :
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def message
|
44
|
-
"Webhook response has been redacted temporarily for security purposes. Please see the Pact Broker application logs for the response body."
|
45
|
-
end
|
35
|
+
property :error, :extend => ErrorDecorator, if: lambda { |context| context[:options][:user_options][:show_response] }
|
36
|
+
property :response, :extend => HTTPResponseDecorator, if: lambda { |context| context[:options][:user_options][:show_response] }
|
37
|
+
property :response_hidden_message, as: :message, exec_context: :decorator, if: lambda { |context| !context[:options][:user_options][:show_response] }
|
46
38
|
|
47
39
|
link :webhook do | options |
|
48
40
|
{
|
@@ -56,7 +48,11 @@ module PactBroker
|
|
56
48
|
href: webhook_execution_url(options.fetch(:webhook), options.fetch(:base_url))
|
57
49
|
}
|
58
50
|
end
|
51
|
+
|
52
|
+
def response_hidden_message
|
53
|
+
PactBroker::Messages.message('messages.response_body_hidden')
|
54
|
+
end
|
59
55
|
end
|
60
56
|
end
|
61
57
|
end
|
62
|
-
end
|
58
|
+
end
|
@@ -96,12 +96,12 @@ module PactBroker
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def set_json_error_message message
|
99
|
-
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
99
|
+
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
|
100
100
|
response.body = {error: message}.to_json
|
101
101
|
end
|
102
102
|
|
103
103
|
def set_json_validation_error_messages errors
|
104
|
-
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
104
|
+
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
|
105
105
|
response.body = {errors: errors}.to_json
|
106
106
|
end
|
107
107
|
|
@@ -128,7 +128,7 @@ module PactBroker
|
|
128
128
|
rescue StandardError => e
|
129
129
|
logger.error "Error parsing JSON #{e} - #{request_body}"
|
130
130
|
set_json_error_message "Error parsing JSON - #{e.message}"
|
131
|
-
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
131
|
+
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
|
132
132
|
true
|
133
133
|
end
|
134
134
|
end
|
@@ -38,7 +38,7 @@ module PactBroker
|
|
38
38
|
errors = webhook_service.errors(webhook)
|
39
39
|
|
40
40
|
unless errors.empty?
|
41
|
-
response.headers['Content-Type'] = 'application/json;charset=utf-8'
|
41
|
+
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
|
42
42
|
response.body = { errors: errors.messages }.to_json
|
43
43
|
end
|
44
44
|
|
@@ -32,7 +32,7 @@ module PactBroker
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def post_response_body webhook_execution_result
|
35
|
-
Decorators::WebhookExecutionResultDecorator.new(webhook_execution_result).to_json(user_options:
|
35
|
+
Decorators::WebhookExecutionResultDecorator.new(webhook_execution_result).to_json(user_options: user_options)
|
36
36
|
end
|
37
37
|
|
38
38
|
def webhook
|
@@ -46,8 +46,11 @@ module PactBroker
|
|
46
46
|
def uuid
|
47
47
|
identifier_from_path[:uuid]
|
48
48
|
end
|
49
|
+
|
50
|
+
def user_options
|
51
|
+
{ base_url: base_url, webhook: webhook, show_response: PactBroker.configuration.show_webhook_response? }
|
52
|
+
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
52
|
-
|
53
56
|
end
|
@@ -30,9 +30,10 @@ module PactBroker
|
|
30
30
|
attr_accessor :validate_database_connection_config, :enable_diagnostic_endpoints, :version_parser, :sha_generator
|
31
31
|
attr_accessor :use_case_sensitive_resource_names, :order_versions_by_date
|
32
32
|
attr_accessor :check_for_potential_duplicate_pacticipant_names
|
33
|
+
attr_accessor :webhook_http_method_whitelist, :webhook_scheme_whitelist, :webhook_host_whitelist
|
34
|
+
attr_accessor :webhook_retry_schedule
|
33
35
|
attr_accessor :semver_formats
|
34
36
|
attr_accessor :enable_public_badge_access, :shields_io_base_url
|
35
|
-
attr_accessor :webhook_retry_schedule
|
36
37
|
attr_accessor :disable_ssl_verification
|
37
38
|
attr_accessor :base_equality_only_on_content_that_affects_verification_results
|
38
39
|
attr_reader :api_error_reporters
|
@@ -74,6 +75,9 @@ module PactBroker
|
|
74
75
|
config.webhook_retry_schedule = [10, 60, 120, 300, 600, 1200] #10 sec, 1 min, 2 min, 5 min, 10 min, 20 min => 38 minutes
|
75
76
|
config.check_for_potential_duplicate_pacticipant_names = true
|
76
77
|
config.disable_ssl_verification = false
|
78
|
+
config.webhook_http_method_whitelist = ['POST']
|
79
|
+
config.webhook_scheme_whitelist = ['https']
|
80
|
+
config.webhook_host_whitelist = []
|
77
81
|
config
|
78
82
|
end
|
79
83
|
|
@@ -142,6 +146,10 @@ module PactBroker
|
|
142
146
|
end
|
143
147
|
end
|
144
148
|
|
149
|
+
def show_webhook_response?
|
150
|
+
webhook_host_whitelist.any?
|
151
|
+
end
|
152
|
+
|
145
153
|
def enable_badge_resources= enable_badge_resources
|
146
154
|
puts "Pact Broker configuration property `enable_badge_resources` is deprecated. Please use `enable_public_badge_access`"
|
147
155
|
self.enable_public_badge_access = enable_badge_resources
|
@@ -54,6 +54,28 @@ A request body can be specified as well.
|
|
54
54
|
|
55
55
|
**BEWARE** The password can be reverse engineered from the database, so make a separate account for the Pact Broker to use, don't use your personal account!
|
56
56
|
|
57
|
+
<a name="whitelist"></a>
|
58
|
+
#### Webhook Whitelist
|
59
|
+
|
60
|
+
To ensure that webhooks cannot be used maliciously to expose either data about your contracts or your internal network, the following validation rules are applied to webhooks via the Pact Broker configuration settings.
|
61
|
+
|
62
|
+
* **Scheme**: Must be included in the `webhook_scheme_whitelist`, which by default only includes `https`. You can change this to include `http` if absolutely necessary, however, keep in mind that the body of any http traffic is visible to the network. You can load a self signed certificate into the Pact Broker to be used for https connections using [script/insert-self-signed-certificate-from-url.rb](https://github.com/pact-foundation/pact_broker/blob/master/script/insert-self-signed-certificate-from-url.rb) in the
|
63
|
+
Pact Broker Github repository.
|
64
|
+
|
65
|
+
* **HTTP method**: Must be included in the `webhook_http_method_whitelist`, which by default only includes `POST`. It is highly recommended that only `POST` requests are allowed to ensure that webhooks cannot be used to retrieve sensitive information from hosts within the same network.
|
66
|
+
|
67
|
+
* **Host**: If the `webhook_host_whitelist` contains any entries, the host must match one or more of the entries. By default, it is empty. For security purposes, if the host whitelist is empty, the response details will not be logged to the UI (though they can be seen in the application logs at debug level).
|
68
|
+
|
69
|
+
The host whitelist may contain hostnames (eg `"github.com"`), IPs (eg `"192.0.345.4"`), network ranges (eg `"10.0.0.0/8"`) or regular expressions (eg `/.*\.foo\.com$/`). Note that IPs are not resolved, so if you specify an IP range, you need to use the IP in the webhook URL. If you wish to allow webhooks to any host (not recommended!), you can set `webhook_host_whitelist` to `[/.*/]`. Beware of any sensitive endpoints that may be exposed within the same network.
|
70
|
+
|
71
|
+
The recommended set of values to start with are:
|
72
|
+
|
73
|
+
* your CI server's hostname (for triggering builds)
|
74
|
+
* your company chat (eg. Slack, for publishing notifications)
|
75
|
+
* your code repository (eg. Github, for sending commit statuses)
|
76
|
+
|
77
|
+
Alternatively, you could use a regular expression to limit requests to your company's domain. eg `/.*\.foo\.com$/` (don't forget the end of string anchor). You can test Ruby regular expressions at [rubular.com](http://rubular.com).
|
78
|
+
|
57
79
|
#### Event types
|
58
80
|
|
59
81
|
`contract_content_changed:` triggered when the content of the contract has changed since the previous publication. Uses plain string equality, so changes to the ordering of hash keys, or whitespace changes will trigger this webhook.
|
@@ -65,6 +87,7 @@ A request body can be specified as well.
|
|
65
87
|
The following variables may be used in the request parameters or body, and will be replaced with their appropriate values at runtime.
|
66
88
|
|
67
89
|
`${pactbroker.pactUrl}`: the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format.)
|
90
|
+
`${pactbroker.consumerVersionNumber}`: the version number of the most recent consumer version associated with the pact content.
|
68
91
|
|
69
92
|
Example usage:
|
70
93
|
|
@@ -5,8 +5,10 @@ require 'pact_broker/logging'
|
|
5
5
|
require 'pact_broker/messages'
|
6
6
|
require 'net/http'
|
7
7
|
require 'pact_broker/webhooks/redact_logs'
|
8
|
+
require 'pact_broker/webhooks/render'
|
8
9
|
require 'pact_broker/api/pact_broker_urls'
|
9
10
|
require 'pact_broker/build_http_options'
|
11
|
+
require 'cgi'
|
10
12
|
|
11
13
|
module PactBroker
|
12
14
|
|
@@ -66,15 +68,14 @@ module PactBroker
|
|
66
68
|
uri = build_uri(pact)
|
67
69
|
req = build_request(uri, pact, execution_logger)
|
68
70
|
response = do_request(uri, req)
|
69
|
-
log_response(response, execution_logger)
|
71
|
+
log_response(response, execution_logger, options)
|
70
72
|
result = WebhookExecutionResult.new(response, logs.string)
|
71
73
|
log_completion_message(options, execution_logger, result.success?)
|
72
74
|
result
|
73
75
|
end
|
74
76
|
|
75
77
|
def handle_error_and_build_result e, options, logs, execution_logger
|
76
|
-
|
77
|
-
execution_logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message}"
|
78
|
+
log_error(e, execution_logger, options)
|
78
79
|
log_completion_message(options, execution_logger, false)
|
79
80
|
WebhookExecutionResult.new(nil, logs.string, e)
|
80
81
|
end
|
@@ -91,14 +92,10 @@ module PactBroker
|
|
91
92
|
req.basic_auth(username, password) if username
|
92
93
|
|
93
94
|
unless body.nil?
|
94
|
-
|
95
|
-
req.body = gsub_body(pact, body)
|
96
|
-
else
|
97
|
-
req.body = gsub_body(pact, body.to_json)
|
98
|
-
end
|
95
|
+
req.body = PactBroker::Webhooks::Render.call(String === body ? body : body.to_json, pact)
|
99
96
|
end
|
100
97
|
|
101
|
-
execution_logger.info req.body
|
98
|
+
execution_logger.info(req.body) if req.body
|
102
99
|
req
|
103
100
|
end
|
104
101
|
|
@@ -110,23 +107,40 @@ module PactBroker
|
|
110
107
|
end
|
111
108
|
end
|
112
109
|
|
113
|
-
def log_response response, execution_logger
|
114
|
-
|
110
|
+
def log_response response, execution_logger, options
|
111
|
+
log_response_to_application_logger(response)
|
112
|
+
if options[:show_response]
|
113
|
+
log_response_to_execution_logger(response, execution_logger)
|
114
|
+
else
|
115
|
+
execution_logger.info response_body_hidden_message
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def response_body_hidden_message
|
120
|
+
PactBroker::Messages.message('messages.response_body_hidden')
|
121
|
+
end
|
122
|
+
|
123
|
+
def log_response_to_application_logger response
|
115
124
|
logger.info "Received response for webhook #{uuid} status=#{response.code}"
|
116
|
-
|
117
|
-
#response.each_header do | header |
|
118
|
-
# execution_logger.info "#{header.split("-").collect(&:capitalize).join('-')}: #{response[header]}"
|
119
|
-
#end
|
125
|
+
logger.debug "headers=#{response.to_hash}"
|
120
126
|
logger.debug "body=#{response.body}"
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
end
|
128
|
+
|
129
|
+
def log_response_to_execution_logger response, execution_logger
|
130
|
+
execution_logger.info "HTTP/#{response.http_version} #{response.code} #{response.message}"
|
131
|
+
response.each_header do | header |
|
132
|
+
execution_logger.info "#{header.split("-").collect(&:capitalize).join('-')}: #{response[header]}"
|
133
|
+
end
|
134
|
+
|
135
|
+
safe_body = nil
|
136
|
+
|
137
|
+
if response.body
|
138
|
+
safe_body = response.body.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
139
|
+
if response.body != safe_body
|
140
|
+
execution_logger.debug "Note that invalid UTF-8 byte sequences were removed from response body before saving the logs"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
execution_logger.info safe_body
|
130
144
|
end
|
131
145
|
|
132
146
|
def log_completion_message options, execution_logger, success
|
@@ -141,6 +155,16 @@ module PactBroker
|
|
141
155
|
end
|
142
156
|
end
|
143
157
|
|
158
|
+
def log_error e, execution_logger, options
|
159
|
+
logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message} #{e.backtrace.join("\n")}"
|
160
|
+
|
161
|
+
if options[:show_response]
|
162
|
+
execution_logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message}"
|
163
|
+
else
|
164
|
+
execution_logger.error "Error executing webhook #{uuid}. #{response_body_hidden_message}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
144
168
|
def to_s
|
145
169
|
"#{method.upcase} #{url}, username=#{username}, password=#{display_password}, headers=#{headers}, body=#{body}"
|
146
170
|
end
|
@@ -150,7 +174,7 @@ module PactBroker
|
|
150
174
|
end
|
151
175
|
|
152
176
|
def build_uri pact
|
153
|
-
URI(
|
177
|
+
URI(PactBroker::Webhooks::Render.call(url, pact){ | value | CGI::escape(value)} )
|
154
178
|
end
|
155
179
|
|
156
180
|
def url_with_credentials pact
|
@@ -158,18 +182,6 @@ module PactBroker
|
|
158
182
|
u.userinfo = "#{CGI::escape username}:#{display_password}" if username
|
159
183
|
u
|
160
184
|
end
|
161
|
-
|
162
|
-
def gsub_body pact, body
|
163
|
-
base_url = PactBroker.configuration.base_url
|
164
|
-
body.gsub('${pactbroker.pactUrl}', PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact))
|
165
|
-
end
|
166
|
-
|
167
|
-
def gsub_url pact, url
|
168
|
-
base_url = PactBroker.configuration.base_url
|
169
|
-
pact_url = PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact)
|
170
|
-
escaped_pact_url = CGI::escape(pact_url)
|
171
|
-
url.gsub('${pactbroker.pactUrl}', escaped_pact_url)
|
172
|
-
end
|
173
185
|
end
|
174
186
|
end
|
175
187
|
end
|