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
@@ -9,6 +9,8 @@ en:
|
|
9
9
|
valid_consumer_version_number?: "Consumer version number '%{value}' cannot be parsed to a version number. The expected format (unless this configuration has been overridden) is a semantic version. eg. 1.3.0 or 2.0.4.rc1"
|
10
10
|
|
11
11
|
pact_broker:
|
12
|
+
messages:
|
13
|
+
response_body_hidden: For security purposes, the response details are not logged. To enable response logging, configure the webhook_host_whitelist property. See /doc/webhooks#whitelist for more information.
|
12
14
|
errors:
|
13
15
|
validation:
|
14
16
|
blank: "cannot be blank."
|
data/lib/pact_broker/version.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
module PactBroker
|
2
|
+
module Webhooks
|
3
|
+
class CheckHostWhitelist
|
4
|
+
|
5
|
+
def self.call(host, whitelist = PactBroker.configuration.webhook_host_whitelist)
|
6
|
+
whitelist.select{ | whitelist_host | match?(host, whitelist_host) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.match?(host, whitelist_host)
|
10
|
+
if whitelist_host.is_a?(Regexp)
|
11
|
+
host =~ whitelist_host
|
12
|
+
else
|
13
|
+
begin
|
14
|
+
IPAddr.new(whitelist_host) === IPAddr.new(host)
|
15
|
+
rescue IPAddr::Error
|
16
|
+
host == whitelist_host
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module PactBroker
|
2
|
+
module Webhooks
|
3
|
+
class Render
|
4
|
+
def self.call(body, pact, verification = nil, &escaper)
|
5
|
+
base_url = PactBroker.configuration.base_url
|
6
|
+
params = {
|
7
|
+
'${pactbroker.pactUrl}' => PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact),
|
8
|
+
'${pactbroker.consumerVersionNumber}' => pact.consumer_version_number
|
9
|
+
}
|
10
|
+
|
11
|
+
if escaper
|
12
|
+
params.keys.each do | key |
|
13
|
+
params[key] = escaper.call(params[key])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
params.inject(body) do | body, (key, value) |
|
18
|
+
body.gsub(key, value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -61,7 +61,8 @@ module PactBroker
|
|
61
61
|
|
62
62
|
def self.execute_webhook_now webhook, pact
|
63
63
|
triggered_webhook = webhook_repository.create_triggered_webhook(next_uuid, webhook, pact, USER)
|
64
|
-
|
64
|
+
options = { failure_log_message: "Webhook execution failed", show_response: PactBroker.configuration.show_webhook_response?}
|
65
|
+
webhook_execution_result = execute_triggered_webhook_now triggered_webhook, options
|
65
66
|
if webhook_execution_result.success?
|
66
67
|
webhook_repository.update_triggered_webhook_status triggered_webhook, TriggeredWebhook::STATUS_SUCCESS
|
67
68
|
else
|
@@ -5,7 +5,6 @@ require 'pact_broker/domain/pacticipant'
|
|
5
5
|
module PactBroker
|
6
6
|
module Webhooks
|
7
7
|
class Webhook < Sequel::Model
|
8
|
-
|
9
8
|
set_primary_key :id
|
10
9
|
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
|
11
10
|
associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
|
@@ -84,13 +83,11 @@ module PactBroker
|
|
84
83
|
is_json_request_body: is_json_request_body
|
85
84
|
}
|
86
85
|
end
|
87
|
-
|
88
86
|
end
|
89
87
|
|
90
88
|
Webhook.plugin :timestamps, :update_on_create=>true
|
91
89
|
|
92
90
|
class WebhookHeader < Sequel::Model
|
93
|
-
|
94
91
|
associate(:many_to_one, :webhook, :class => "PactBroker::Repositories::Webhook", :key => :webhook_id, :primary_key => :id)
|
95
92
|
|
96
93
|
def self.from_domain name, value, webhook_id
|
@@ -100,8 +97,6 @@ module PactBroker
|
|
100
97
|
db_header.webhook_id = webhook_id
|
101
98
|
db_header
|
102
99
|
end
|
103
|
-
|
104
100
|
end
|
105
101
|
end
|
106
|
-
|
107
102
|
end
|
@@ -24,7 +24,7 @@ describe "Creating a webhook" do
|
|
24
24
|
|
25
25
|
it "returns a JSON content type" do
|
26
26
|
subject
|
27
|
-
expect(last_response.headers['Content-Type']).to eq 'application/json;charset=utf-8'
|
27
|
+
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
28
28
|
end
|
29
29
|
|
30
30
|
it "returns the validation errors" do
|
@@ -43,7 +43,7 @@ describe "Creating a webhook" do
|
|
43
43
|
}],
|
44
44
|
request: {
|
45
45
|
method: 'POST',
|
46
|
-
url: '
|
46
|
+
url: 'https://example.org',
|
47
47
|
headers: {
|
48
48
|
:"Content-Type" => "application/json"
|
49
49
|
},
|
@@ -76,5 +76,4 @@ describe "Creating a webhook" do
|
|
76
76
|
expect(response_body).to include webhook_hash
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
80
79
|
end
|
@@ -14,7 +14,7 @@ describe "Creating a webhook" do
|
|
14
14
|
let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
|
15
15
|
let(:webhook_json) do
|
16
16
|
h = load_json_fixture('webhook_valid.json')
|
17
|
-
h['request']['
|
17
|
+
h['request']['url'] = 'https://bar.com'
|
18
18
|
h.to_json
|
19
19
|
end
|
20
20
|
|
@@ -55,7 +55,7 @@ describe "Creating a webhook" do
|
|
55
55
|
|
56
56
|
it "updates the webhook" do
|
57
57
|
subject
|
58
|
-
expect(reloaded_webhook.request.
|
58
|
+
expect(reloaded_webhook.request.url).to eq 'https://bar.com'
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -23,8 +23,9 @@ describe "Execute a webhook" do
|
|
23
23
|
|
24
24
|
context "when the execution is successful" do
|
25
25
|
let!(:request) do
|
26
|
-
stub_request(:post, /http/).with(body: 'http://example.org/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200)
|
26
|
+
stub_request(:post, /http/).with(body: 'http://example.org/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200, body: response_body)
|
27
27
|
end
|
28
|
+
let(:response_body) { "webhook-response-body" }
|
28
29
|
|
29
30
|
it "performs the HTTP request" do
|
30
31
|
subject
|
@@ -42,6 +43,36 @@ describe "Execute a webhook" do
|
|
42
43
|
it "saves a WebhookExecution" do
|
43
44
|
expect { subject }.to change { PactBroker::Webhooks::Execution.count }.by(1)
|
44
45
|
end
|
46
|
+
|
47
|
+
context "when a webhook host whitelist is not configured" do
|
48
|
+
before do
|
49
|
+
allow(PactBroker.configuration).to receive(:show_webhook_response?).and_return(false)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "does not show any response details" do
|
53
|
+
expect(subject.body).to_not include response_body
|
54
|
+
end
|
55
|
+
|
56
|
+
it "does not log any response details" do
|
57
|
+
subject
|
58
|
+
expect(PactBroker::Webhooks::Execution.order(:id).last.logs).to_not include response_body
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when a webhook host whitelist is configured" do
|
63
|
+
before do
|
64
|
+
allow(PactBroker.configuration).to receive(:show_webhook_response?).and_return(true)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "includes response details" do
|
68
|
+
expect(subject.body).to include response_body
|
69
|
+
end
|
70
|
+
|
71
|
+
it "logs the response details" do
|
72
|
+
subject
|
73
|
+
expect(PactBroker::Webhooks::Execution.order(:id).last.logs).to include response_body
|
74
|
+
end
|
75
|
+
end
|
45
76
|
end
|
46
77
|
|
47
78
|
context "when an error occurs", no_db_clean: true do
|
@@ -10,6 +10,7 @@ module PactBroker
|
|
10
10
|
let(:hash) { JSON.parse(json) }
|
11
11
|
let(:webhook) { PactBroker::Api::Decorators::WebhookDecorator.new(Domain::Webhook.new).from_json(json) }
|
12
12
|
let(:subject) { WebhookContract.new(webhook) }
|
13
|
+
let(:matching_hosts) { ['foo'] }
|
13
14
|
|
14
15
|
def valid_webhook_with
|
15
16
|
hash = load_json_fixture 'webhook_valid.json'
|
@@ -18,11 +19,17 @@ module PactBroker
|
|
18
19
|
end
|
19
20
|
|
20
21
|
describe "errors" do
|
21
|
-
|
22
22
|
before do
|
23
|
+
PactBroker.configuration.webhook_http_method_whitelist = webhook_http_method_whitelist
|
24
|
+
PactBroker.configuration.webhook_host_whitelist = webhook_host_whitelist
|
25
|
+
allow(PactBroker::Webhooks::CheckHostWhitelist).to receive(:call).and_return(whitelist_matches)
|
23
26
|
subject.validate(hash)
|
24
27
|
end
|
25
28
|
|
29
|
+
let(:webhook_http_method_whitelist) { ['POST'] }
|
30
|
+
let(:whitelist_matches) { ['foo'] }
|
31
|
+
let(:webhook_host_whitelist) { [] }
|
32
|
+
|
26
33
|
context "with valid fields" do
|
27
34
|
it "is empty" do
|
28
35
|
expect(subject.errors).to be_empty
|
@@ -81,6 +88,62 @@ module PactBroker
|
|
81
88
|
end
|
82
89
|
end
|
83
90
|
|
91
|
+
context "with an invalid scheme" do
|
92
|
+
let(:json) do
|
93
|
+
valid_webhook_with do |hash|
|
94
|
+
hash['request']['url'] = 'ftp://foo'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it "contains an error for the URL" do
|
99
|
+
expect(subject.errors[:"request.url"]).to include "scheme must be https. See /doc/webhooks#whitelist for more information."
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "with an HTTP method that is not whitelisted" do
|
104
|
+
let(:json) do
|
105
|
+
valid_webhook_with do |hash|
|
106
|
+
hash['request']['method'] = 'DELETE'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when there is only one allowed HTTP method" do
|
111
|
+
it "contains an error for invalid method" do
|
112
|
+
expect(subject.errors[:"request.http_method"]).to include "must be POST. See /doc/webhooks#whitelist for more information."
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "when there is more than one allowed HTTP method", pending: "need to work out how to dynamically create this message" do
|
117
|
+
let(:webhook_http_method_whitelist) { ['POST', 'GET'] }
|
118
|
+
|
119
|
+
it "contains an error for invalid method" do
|
120
|
+
expect(subject.errors[:"request.http_method"]).to include "must be one of POST, GET"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when the host whitelist is empty" do
|
126
|
+
it "does not attempt to validate the host" do
|
127
|
+
expect(PactBroker::Webhooks::CheckHostWhitelist).to_not have_received(:call)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when the host whitelist is populated" do
|
132
|
+
let(:webhook_host_whitelist) { [/foo/, "bar"] }
|
133
|
+
|
134
|
+
it "validates the host" do
|
135
|
+
expect(PactBroker::Webhooks::CheckHostWhitelist).to have_received(:call).with("some.url", webhook_host_whitelist)
|
136
|
+
end
|
137
|
+
|
138
|
+
context "when the host does not match the whitelist" do
|
139
|
+
let(:whitelist_matches) { [] }
|
140
|
+
|
141
|
+
it "contains an error", pending: "need to work out how to do dynamic messages" do
|
142
|
+
expect(subject.errors[:"request.url"]).to include "host must be in the whitelist /foo/, \"bar\" . See /doc/webhooks#whitelist for more information."
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
84
147
|
context "with no URL" do
|
85
148
|
let(:json) do
|
86
149
|
valid_webhook_with do |hash|
|
@@ -14,10 +14,11 @@ module PactBroker
|
|
14
14
|
let(:response) { double('http_response', code: '200', body: response_body, to_hash: headers) }
|
15
15
|
let(:response_body) { 'body' }
|
16
16
|
let(:error) { nil }
|
17
|
-
let(:webhook) { instance_double(PactBroker::Domain::Webhook, uuid: 'some-uuid')}
|
17
|
+
let(:webhook) { instance_double(PactBroker::Domain::Webhook, uuid: 'some-uuid') }
|
18
|
+
let(:show_response) { true }
|
18
19
|
let(:json) {
|
19
20
|
WebhookExecutionResultDecorator.new(webhook_execution_result)
|
20
|
-
.to_json(user_options: { base_url: 'http://example.org', webhook: webhook })
|
21
|
+
.to_json(user_options: { base_url: 'http://example.org', webhook: webhook, show_response: show_response })
|
21
22
|
}
|
22
23
|
|
23
24
|
let(:subject) { JSON.parse(json, symbolize_names: true)}
|
@@ -30,11 +31,7 @@ module PactBroker
|
|
30
31
|
expect(subject[:_links][:webhook][:href]).to eq 'http://example.org/webhooks/some-uuid'
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
expect(subject[:message]).to match /redacted/
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when there is an error", pending: "temporarily disabled" do
|
34
|
+
context "when there is an error" do
|
38
35
|
let(:error) { double('error', message: 'message', backtrace: ['blah','blah']) }
|
39
36
|
|
40
37
|
it "includes the message" do
|
@@ -46,7 +43,7 @@ module PactBroker
|
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
49
|
-
context "when there is a response"
|
46
|
+
context "when there is a response" do
|
50
47
|
it "includes the response code" do
|
51
48
|
expect(subject[:response][:status]).to eq 200
|
52
49
|
end
|
@@ -66,8 +63,19 @@ module PactBroker
|
|
66
63
|
end
|
67
64
|
end
|
68
65
|
end
|
69
|
-
end
|
70
66
|
|
67
|
+
context "when show_response is false" do
|
68
|
+
let(:show_response) { false }
|
69
|
+
|
70
|
+
it "does not include the response" do
|
71
|
+
expect(subject).to_not have_key(:response)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "includes a message about why the response is hidden" do
|
75
|
+
expect(subject[:message]).to match /security purposes/
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
71
79
|
end
|
72
80
|
end
|
73
81
|
end
|
@@ -76,7 +76,7 @@ module PactBroker::Api
|
|
76
76
|
end
|
77
77
|
|
78
78
|
it "returns a JSON content type" do
|
79
|
-
expect(response.headers['Content-Type']).to eq "application/json;charset=utf-8"
|
79
|
+
expect(response.headers['Content-Type']).to eq "application/hal+json;charset=utf-8"
|
80
80
|
end
|
81
81
|
|
82
82
|
it "returns an error message" do
|
@@ -93,7 +93,7 @@ module PactBroker::Api
|
|
93
93
|
|
94
94
|
it "returns a JSON content type" do
|
95
95
|
subject
|
96
|
-
expect(last_response.headers['Content-Type']).to eq 'application/json;charset=utf-8'
|
96
|
+
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
97
97
|
end
|
98
98
|
|
99
99
|
it "returns an error message" do
|
@@ -111,7 +111,7 @@ module PactBroker::Api
|
|
111
111
|
|
112
112
|
it "returns a JSON content type" do
|
113
113
|
subject
|
114
|
-
expect(last_response.headers['Content-Type']).to eq 'application/json;charset=utf-8'
|
114
|
+
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
115
115
|
end
|
116
116
|
|
117
117
|
it "returns an error message" do
|
@@ -132,7 +132,7 @@ module PactBroker::Api
|
|
132
132
|
|
133
133
|
it "returns a JSON content type" do
|
134
134
|
subject
|
135
|
-
expect(last_response.headers['Content-Type']).to eq 'application/json;charset=utf-8'
|
135
|
+
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
|
136
136
|
end
|
137
137
|
|
138
138
|
it "returns the validation errors" do
|
@@ -57,7 +57,8 @@ module PactBroker
|
|
57
57
|
end
|
58
58
|
|
59
59
|
it "generates a JSON response body for the execution result" do
|
60
|
-
|
60
|
+
allow(PactBroker.configuration).to receive(:show_webhook_response?).and_return('foo')
|
61
|
+
expect(decorator).to receive(:to_json).with(user_options: { base_url: 'http://example.org', webhook: webhook, show_response: 'foo' })
|
61
62
|
subject
|
62
63
|
end
|
63
64
|
|
@@ -69,6 +70,7 @@ module PactBroker
|
|
69
70
|
|
70
71
|
context "when execution is not successful" do
|
71
72
|
let(:success) { false }
|
73
|
+
|
72
74
|
it "returns a 500 JSON response" do
|
73
75
|
subject
|
74
76
|
expect(last_response.status).to eq 500
|
@@ -8,9 +8,9 @@ module PactBroker
|
|
8
8
|
before do
|
9
9
|
allow(PactBroker::Api::PactBrokerUrls).to receive(:pact_url).and_return('http://example.org/pact-url')
|
10
10
|
allow(PactBroker.configuration).to receive(:base_url).and_return('http://example.org')
|
11
|
-
allow(PactBroker
|
12
|
-
|
13
|
-
|
11
|
+
allow(PactBroker::Webhooks::Render).to receive(:call) do | content, pact, verification, &block |
|
12
|
+
content
|
13
|
+
end
|
14
14
|
end
|
15
15
|
|
16
16
|
let(:username) { nil }
|
@@ -19,7 +19,8 @@ module PactBroker
|
|
19
19
|
let(:body) { 'body' }
|
20
20
|
let(:logs) { StringIO.new }
|
21
21
|
let(:execution_logger) { Logger.new(logs) }
|
22
|
-
let(:options) { {failure_log_message: 'oops'}}
|
22
|
+
let(:options) { {failure_log_message: 'oops', show_response: show_response} }
|
23
|
+
let(:show_response) { true }
|
23
24
|
let(:pact) { instance_double('PactBroker::Domain::Pact') }
|
24
25
|
|
25
26
|
subject do
|
@@ -57,51 +58,37 @@ module PactBroker
|
|
57
58
|
describe "execute" do
|
58
59
|
let!(:http_request) do
|
59
60
|
stub_request(:post, "http://example.org/hook").
|
60
|
-
with(:headers => {'Content-Type'=>'text/plain'}, :body =>
|
61
|
+
with(:headers => {'Content-Type'=>'text/plain'}, :body => request_body).
|
61
62
|
to_return(:status => 200, :body => "respbod", :headers => {'Content-Type' => 'text/foo, blah'})
|
62
63
|
end
|
63
64
|
|
64
|
-
|
65
|
-
let!(:http_request) do
|
66
|
-
stub_request(:post, "http://example.org/hook").
|
67
|
-
with(:headers => {'Content-Type'=>'text/plain'}, :body => "<xml><url>http://example.org/pact-url</url></xml>").
|
68
|
-
to_return(:status => 200)
|
69
|
-
end
|
70
|
-
|
71
|
-
let(:body) { "<xml><url>${pactbroker.pactUrl}</url></xml>" }
|
65
|
+
let(:request_body) { 'body' }
|
72
66
|
|
73
|
-
|
74
|
-
|
75
|
-
expect(
|
67
|
+
it "renders the url template" do
|
68
|
+
expect(PactBroker::Webhooks::Render).to receive(:call).with("http://example.org/hook", pact) do | content, pact, verification, &block |
|
69
|
+
expect(content).to eq "http://example.org/hook"
|
70
|
+
expect(pact).to be pact
|
71
|
+
expect(verification).to be nil
|
72
|
+
expect(block.call("foo bar")).to eq "foo+bar"
|
73
|
+
"http://example.org/hook"
|
76
74
|
end
|
75
|
+
subject.execute(pact, options)
|
77
76
|
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
with(:headers => {'Content-Type'=>'text/plain'}, :body => '{"url":"http://example.org/pact-url"}').
|
83
|
-
to_return(:status => 200)
|
84
|
-
end
|
85
|
-
|
86
|
-
let(:body) { { url: '${pactbroker.pactUrl}' } }
|
87
|
-
|
88
|
-
it "replaces the token with the live value" do
|
78
|
+
context "when the body is a string" do
|
79
|
+
it "renders the body template with the String" do
|
80
|
+
expect(PactBroker::Webhooks::Render).to receive(:call).with('body', pact)
|
89
81
|
subject.execute(pact, options)
|
90
|
-
expect(http_request).to have_been_made
|
91
82
|
end
|
92
83
|
end
|
93
84
|
|
94
|
-
|
95
|
-
let
|
96
|
-
|
97
|
-
to_return(:status => 200)
|
98
|
-
end
|
99
|
-
|
100
|
-
let(:url) { 'http://example.org/hook?url=${pactbroker.pactUrl}' }
|
85
|
+
context "when the body is an object" do
|
86
|
+
let(:body) { {"foo" => "bar"} }
|
87
|
+
let(:request_body) { '{"foo":"bar"}' }
|
101
88
|
|
102
|
-
it "
|
89
|
+
it "renders the body template with JSON" do
|
90
|
+
expect(PactBroker::Webhooks::Render).to receive(:call).with(request_body, pact)
|
103
91
|
subject.execute(pact, options)
|
104
|
-
expect(http_request).to have_been_made
|
105
92
|
end
|
106
93
|
end
|
107
94
|
|
@@ -120,18 +107,11 @@ module PactBroker
|
|
120
107
|
allow(PactBroker.logger).to receive(:info)
|
121
108
|
allow(PactBroker.logger).to receive(:debug)
|
122
109
|
expect(PactBroker.logger).to receive(:info).with(/response.*200/)
|
110
|
+
expect(PactBroker.logger).to receive(:debug).with(/content-type/)
|
123
111
|
expect(PactBroker.logger).to receive(:debug).with(/respbod/)
|
124
112
|
subject.execute(pact, options)
|
125
113
|
end
|
126
114
|
|
127
|
-
it "does not write the response body to the exeuction log for security purposes" do
|
128
|
-
expect(logs).to_not include "An error"
|
129
|
-
end
|
130
|
-
|
131
|
-
it "logs a message about why there is no response information" do
|
132
|
-
expect(logs).to include "Webhook response has been redacted temporarily for security purposes"
|
133
|
-
end
|
134
|
-
|
135
115
|
describe "execution logs" do
|
136
116
|
|
137
117
|
it "logs the request method and path" do
|
@@ -150,16 +130,38 @@ module PactBroker
|
|
150
130
|
expect(logs).to include body
|
151
131
|
end
|
152
132
|
|
153
|
-
|
154
|
-
|
155
|
-
|
133
|
+
context "when show_response is true" do
|
134
|
+
it "logs the response status" do
|
135
|
+
expect(logs).to include "HTTP/1.0 200"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "logs the response headers" do
|
139
|
+
expect(logs).to include "Content-Type: text/foo, blah"
|
140
|
+
end
|
156
141
|
|
157
|
-
|
158
|
-
|
142
|
+
it "logs the response body" do
|
143
|
+
expect(logs).to include "respbod"
|
144
|
+
end
|
159
145
|
end
|
160
146
|
|
161
|
-
|
162
|
-
|
147
|
+
context "when show_response is false" do
|
148
|
+
let(:show_response) { false }
|
149
|
+
|
150
|
+
it "does not log the response status" do
|
151
|
+
expect(logs).to_not include "HTTP/1.0 200"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "does not log the response headers" do
|
155
|
+
expect(logs).to_not include "Content-Type: text/foo, blah"
|
156
|
+
end
|
157
|
+
|
158
|
+
it "does not log the response body" do
|
159
|
+
expect(logs).to_not include "respbod"
|
160
|
+
end
|
161
|
+
|
162
|
+
it "logs a message about why the response is hidden" do
|
163
|
+
expect(logs).to include "security purposes"
|
164
|
+
end
|
163
165
|
end
|
164
166
|
|
165
167
|
context "when the response code is a success" do
|
@@ -234,21 +236,6 @@ module PactBroker
|
|
234
236
|
end
|
235
237
|
end
|
236
238
|
|
237
|
-
context "when the request has a JSONable body" do
|
238
|
-
let(:body) { [{"some": "json"}] }
|
239
|
-
|
240
|
-
let!(:http_request) do
|
241
|
-
stub_request(:post, "http://example.org/hook").
|
242
|
-
with(:headers => {'Content-Type'=>'text/plain'}, :body => body.to_json).
|
243
|
-
to_return(:status => 200, :body => "respbod", :headers => {'Content-Type' => 'text/foo, blah'})
|
244
|
-
end
|
245
|
-
|
246
|
-
it "converts the body to JSON before submitting the request" do
|
247
|
-
subject.execute(pact, options)
|
248
|
-
expect(http_request).to have_been_made
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
239
|
context "when the request has a nil body" do
|
253
240
|
let(:body) { nil }
|
254
241
|
|
@@ -291,7 +278,7 @@ module PactBroker
|
|
291
278
|
end
|
292
279
|
end
|
293
280
|
|
294
|
-
context "when the response body contains a non UTF-8 character"
|
281
|
+
context "when the response body contains a non UTF-8 character" do
|
295
282
|
let!(:http_request) do
|
296
283
|
stub_request(:post, "http://example.org/hook").
|
297
284
|
to_return(:status => 200, :body => "This has some \xC2 invalid chars")
|
@@ -316,10 +303,10 @@ module PactBroker
|
|
316
303
|
|
317
304
|
before do
|
318
305
|
allow(subject).to receive(:http_request).and_raise(WebhookTestError.new("blah"))
|
306
|
+
allow(PactBroker.logger).to receive(:error)
|
319
307
|
end
|
320
308
|
|
321
309
|
it "logs the error" do
|
322
|
-
allow(PactBroker.logger).to receive(:error)
|
323
310
|
expect(PactBroker.logger).to receive(:error).with(/Error.*WebhookTestError.*blah/)
|
324
311
|
subject.execute(pact, options)
|
325
312
|
end
|
@@ -335,6 +322,24 @@ module PactBroker
|
|
335
322
|
it "logs the failure_log_message" do
|
336
323
|
expect(logs).to include "oops"
|
337
324
|
end
|
325
|
+
|
326
|
+
context "when show_response is true" do
|
327
|
+
it "logs the exception information" do
|
328
|
+
expect(logs).to include "blah"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context "when show_response is false" do
|
333
|
+
let(:show_response) { false }
|
334
|
+
|
335
|
+
it "does not logs the exception information" do
|
336
|
+
expect(logs).to_not include "blah"
|
337
|
+
end
|
338
|
+
|
339
|
+
it "logs a message about why the response is hidden" do
|
340
|
+
expect(logs).to include "security purposes"
|
341
|
+
end
|
342
|
+
end
|
338
343
|
end
|
339
344
|
end
|
340
345
|
end
|