Skip to content

Commit 3d5a538

Browse files
committed
fix: ensure that the templating in the webhook body uses the correct base URL for the broker
1 parent 1315e0b commit 3d5a538

15 files changed

+82
-46
lines changed

lib/pact_broker/app.rb

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
require 'rack/pact_broker/configurable_make_it_later'
1515
require 'rack/pact_broker/no_auth'
1616
require 'rack/pact_broker/convert_404_to_hal'
17+
require 'rack/pact_broker/reset_thread_data'
1718
require 'sucker_punch'
1819

1920
module PactBroker
@@ -122,6 +123,7 @@ def configure_middleware
122123
@app_builder.use Rack::Protection, except: [:path_traversal, :remote_token, :session_hijacking, :http_origin]
123124
end
124125
@app_builder.use Rack::PactBroker::InvalidUriProtection
126+
@app_builder.use Rack::PactBroker::ResetThreadData
125127
@app_builder.use Rack::PactBroker::StoreBaseURL
126128
@app_builder.use Rack::PactBroker::AddPactBrokerVersionHeader
127129
@app_builder.use Rack::Static, :urls => ["/stylesheets", "/css", "/fonts", "/js", "/javascripts", "/images"], :root => PactBroker.project_root.join("public")

lib/pact_broker/domain/webhook.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def request_description
4242

4343
def execute pact, verification, options
4444
logger.info "Executing #{self}"
45-
request.build(pact: pact, verification: verification).execute(options)
45+
request.build(pact: pact, verification: verification, base_url: options[:base_url]).execute(options)
4646
end
4747

4848
def to_s

lib/pact_broker/ui/view_models/index_item.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ def any_webhooks?
6868
end
6969

7070
def pact_versions_url
71-
PactBroker::Api::PactBrokerUrls.pact_versions_url(consumer_name, provider_name, PactBroker.configuration.base_url)
71+
PactBroker::Api::PactBrokerUrls.pact_versions_url(consumer_name, provider_name)
7272
end
7373

7474
def integration_url
75-
PactBroker::Api::PactBrokerUrls.integration_url(consumer_name, provider_name, PactBroker.configuration.base_url)
75+
PactBroker::Api::PactBrokerUrls.integration_url(consumer_name, provider_name)
7676
end
7777

7878
def webhook_label

lib/pact_broker/webhooks/job.rb

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def perform_with_connection(data)
2525
@triggered_webhook = PactBroker::Webhooks::TriggeredWebhook.find(id: data[:triggered_webhook].id)
2626
@error_count = data[:error_count] || 0
2727
begin
28-
webhook_execution_result = PactBroker::Webhooks::Service.execute_triggered_webhook_now triggered_webhook, execution_options
28+
webhook_execution_result = PactBroker::Webhooks::Service.execute_triggered_webhook_now triggered_webhook, execution_options(data)
2929
if webhook_execution_result.success?
3030
handle_success
3131
else
@@ -36,10 +36,11 @@ def perform_with_connection(data)
3636
end
3737
end
3838

39-
def execution_options
39+
def execution_options(data)
4040
{
4141
success_log_message: "Successfully executed webhook",
42-
failure_log_message: failure_log_message
42+
failure_log_message: failure_log_message,
43+
base_url: data.fetch(:base_url)
4344
}
4445
end
4546

lib/pact_broker/webhooks/render.rb

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ class Render
44

55
TEMPLATE_PARAMETER_REGEXP = /\$\{pactbroker\.[^\}]+\}/
66

7-
def self.call(template, pact, trigger_verification = nil, &escaper)
8-
base_url = PactBroker.configuration.base_url
7+
def self.call(template, pact, trigger_verification, base_url, &escaper)
98
verification = trigger_verification || (pact && pact.latest_verification)
109
params = {
1110
'${pactbroker.pactUrl}' => pact ? PactBroker::Api::PactBrokerUrls.pact_url(base_url, pact) : "",
12-
'${pactbroker.verificationResultUrl}' => verification_url(verification),
11+
'${pactbroker.verificationResultUrl}' => verification_url(verification, base_url),
1312
'${pactbroker.consumerVersionNumber}' => pact ? pact.consumer_version_number : "",
1413
'${pactbroker.providerVersionNumber}' => verification ? verification.provider_version_number : "",
1514
'${pactbroker.providerVersionTags}' => provider_version_tags(verification),
@@ -40,9 +39,9 @@ def self.github_verification_status verification
4039
end
4140
end
4241

43-
def self.verification_url verification
42+
def self.verification_url verification, base_url
4443
if verification
45-
PactBroker::Api::PactBrokerUrls.verification_url(verification, PactBroker.configuration.base_url)
44+
PactBroker::Api::PactBrokerUrls.verification_url(verification, base_url)
4645
else
4746
""
4847
end

lib/pact_broker/webhooks/service.rb

+7-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def self.find_all
6464
end
6565

6666
def self.test_execution webhook
67-
options = { failure_log_message: "Webhook execution failed", show_response: PactBroker.configuration.show_webhook_response?}
67+
options = { failure_log_message: "Webhook execution failed", show_response: PactBroker.configuration.show_webhook_response?, base_url: base_url}
6868
verification = nil
6969
if webhook.trigger_on_provider_verification_published?
7070
verification = verification_service.search_for_latest(webhook.consumer_name, webhook.provider_name) || PactBroker::Verifications::PlaceholderVerification.new
@@ -126,7 +126,8 @@ def self.run_later webhooks, pact, verification, event_name
126126
logger.info "Scheduling job for #{webhook.description} with uuid #{webhook.uuid}"
127127
job_data = {
128128
triggered_webhook: triggered_webhook,
129-
database_connector: job_database_connector
129+
database_connector: job_database_connector,
130+
base_url: base_url
130131
}
131132
# Delay slightly to make sure the request transaction has finished before we execute the webhook
132133
Job.perform_in(5, job_data)
@@ -140,6 +141,10 @@ def self.job_database_connector
140141
Thread.current[:pact_broker_thread_data].database_connector
141142
end
142143

144+
def self.base_url
145+
Thread.current[:pact_broker_thread_data].base_url
146+
end
147+
143148
def self.find_latest_triggered_webhooks_for_pact pact
144149
webhook_repository.find_latest_triggered_webhooks_for_pact pact
145150
end

lib/pact_broker/webhooks/webhook_request_template.rb

+7-6
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,23 @@ def initialize attributes = {}
3030
def build(context)
3131
attributes = {
3232
method: http_method,
33-
url: build_url(context[:pact], context[:verification]),
33+
url: build_url(context[:pact], context[:verification], context[:base_url]),
3434
headers: headers,
3535
username: username,
3636
password: password,
3737
uuid: uuid,
38-
body: build_body(context[:pact], context[:verification])
38+
body: build_body(context[:pact], context[:verification], context[:base_url])
3939
}
4040
PactBroker::Domain::WebhookRequest.new(attributes)
4141
end
4242

43-
def build_url(pact, verification)
44-
URI(PactBroker::Webhooks::Render.call(url, pact, verification){ | value | CGI::escape(value) if !value.nil? } ).to_s
43+
def build_url(pact, verification, broker_base_url)
44+
URI(PactBroker::Webhooks::Render.call(url, pact, verification, broker_base_url){ | value | CGI::escape(value) if !value.nil? } ).to_s
4545
end
4646

47-
def build_body(pact, verification)
48-
PactBroker::Webhooks::Render.call(String === body ? body : body.to_json, pact, verification)
47+
def build_body(pact, verification, broker_base_url)
48+
body_string = String === body ? body : body.to_json
49+
PactBroker::Webhooks::Render.call(body_string, pact, verification, broker_base_url)
4950
end
5051

5152
def description
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'ostruct'
2+
3+
module Rack
4+
module PactBroker
5+
class ResetThreadData
6+
def initialize app
7+
@app = app
8+
end
9+
10+
def call env
11+
data = OpenStruct.new
12+
Thread.current[:pact_broker_thread_data] ||= data
13+
response = @app.call(env)
14+
# only delete it if it's the same object that we set
15+
if data.equal?(Thread.current[:pact_broker_thread_data])
16+
Thread.current[:pact_broker_thread_data] = nil
17+
end
18+
response
19+
end
20+
end
21+
end
22+
end

lib/rack/pact_broker/store_base_url.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def initialize app
66
end
77

88
def call(env)
9-
ENV['PACT_BROKER_BASE_URL'] ||= ::Rack::Request.new(env).base_url
9+
Thread.current[:pact_broker_thread_data].base_url ||= (ENV['PACT_BROKER_BASE_URL'] || ::Rack::Request.new(env).base_url)
1010
@app.call(env)
1111
end
1212
end

spec/features/execute_webhook_spec.rb

+2-6
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,19 @@
77
let(:td) { TestDataBuilder.new }
88

99
before do
10-
ENV['PACT_BROKER_BASE_URL'] = 'http://example.org'
10+
Thread.current[:pact_broker_thread_data] = OpenStruct.new(base_url: 'http://broker')
1111
td.create_pact_with_hierarchy("Foo", "1", "Bar")
1212
.create_webhook(method: 'POST', body: '${pactbroker.pactUrl}')
1313
end
1414

15-
after do
16-
ENV.delete('PACT_BROKER_BASE_URL')
17-
end
18-
1915
let(:path) { "/webhooks/#{td.webhook.uuid}/execute" }
2016
let(:response_body) { JSON.parse(last_response.body, symbolize_names: true)}
2117

2218
subject { post path; last_response }
2319

2420
context "when the execution is successful" do
2521
let!(:request) do
26-
stub_request(:post, /http/).with(body: 'http://example.org/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200, body: response_body)
22+
stub_request(:post, /http/).with(body: 'http://broker/pacts/provider/Bar/consumer/Foo/version/1').to_return(:status => 200, body: response_body)
2723
end
2824

2925
let(:response_body) { "webhook-response-body" }

spec/lib/pact_broker/domain/webhook_spec.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ module Domain
88
let(:request_template) { instance_double(PactBroker::Webhooks::WebhookRequestTemplate, build: request)}
99
let(:request) { instance_double(PactBroker::Domain::WebhookRequest, execute: result) }
1010
let(:result) { double('result') }
11-
let(:options) { double('options') }
11+
let(:options) { { base_url: base_url } }
12+
let(:base_url) { "http://broker" }
1213
let(:pact) { double('pact') }
1314
let(:verification) { double('verification') }
1415
let(:logger) { double('logger').as_null_object }
@@ -54,7 +55,7 @@ module Domain
5455
let(:execute) { subject.execute pact, verification, options }
5556

5657
it "builds the request" do
57-
expect(request_template).to receive(:build).with(pact: pact, verification: verification)
58+
expect(request_template).to receive(:build).with(pact: pact, verification: verification, base_url: base_url)
5859
execute
5960
end
6061

spec/lib/pact_broker/webhooks/job_spec.rb

+11-8
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ module Webhooks
1111
allow(Job).to receive(:logger).and_return(logger)
1212
end
1313

14+
let(:base_url) { "http://broker" }
1415
let(:triggered_webhook) { instance_double("PactBroker::Webhooks::TriggeredWebhook", webhook_uuid: '1234', id: 1) }
1516
let(:result) { instance_double("PactBroker::Domain::WebhookExecutionResult", success?: success)}
1617
let(:success) { true }
1718
let(:logger) { double('logger').as_null_object }
1819
let(:database_connector) { ->(&block) { block.call } }
1920

20-
subject { Job.new.perform(triggered_webhook: triggered_webhook, database_connector: database_connector) }
21+
subject { Job.new.perform(triggered_webhook: triggered_webhook, database_connector: database_connector, base_url: base_url) }
2122

2223
it "reloads the TriggeredWebhook object to make sure it has a fresh copy" do
2324
expect(PactBroker::Webhooks::TriggeredWebhook).to receive(:find).with(id: 1)
@@ -44,7 +45,7 @@ module Webhooks
4445
end
4546

4647
it "reschedules the job in 10 seconds" do
47-
expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector})
48+
expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector, base_url: base_url})
4849
subject
4950
end
5051

@@ -59,15 +60,16 @@ module Webhooks
5960
let(:success) { false }
6061

6162
it "reschedules the job in 10 seconds" do
62-
expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector})
63+
expect(Job).to receive(:perform_in).with(10, {triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector, base_url: base_url})
6364
subject
6465
end
6566

6667
it "executes the job with an log message indicating that the webhook will be retried" do
6768
expect(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now)
6869
.with(triggered_webhook, {
6970
failure_log_message: "Retrying webhook in 10 seconds",
70-
success_log_message: "Successfully executed webhook"
71+
success_log_message: "Successfully executed webhook",
72+
base_url: base_url
7173
})
7274
subject
7375
end
@@ -84,10 +86,10 @@ module Webhooks
8486
allow(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now).and_raise("an error")
8587
end
8688

87-
subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector) }
89+
subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 1, database_connector: database_connector, base_url: base_url) }
8890

8991
it "reschedules the job in 60 seconds" do
90-
expect(Job).to receive(:perform_in).with(60, {triggered_webhook: triggered_webhook, error_count: 2, database_connector: database_connector})
92+
expect(Job).to receive(:perform_in).with(60, {triggered_webhook: triggered_webhook, error_count: 2, database_connector: database_connector, base_url: base_url})
9193
subject
9294
end
9395

@@ -101,13 +103,14 @@ module Webhooks
101103
context "when the job is not successful for the last time" do
102104
let(:success) { false }
103105

104-
subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 6, database_connector: database_connector) }
106+
subject { Job.new.perform(triggered_webhook: triggered_webhook, error_count: 6, database_connector: database_connector, base_url: base_url) }
105107

106108
it "executes the job with an log message indicating that the webhook has failed" do
107109
expect(PactBroker::Webhooks::Service).to receive(:execute_triggered_webhook_now)
108110
.with(triggered_webhook, {
109111
failure_log_message: "Webhook execution failed after 7 attempts",
110-
success_log_message: "Successfully executed webhook"
112+
success_log_message: "Successfully executed webhook",
113+
base_url: base_url
111114
})
112115
subject
113116
end

spec/lib/pact_broker/webhooks/render_spec.rb

+8-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ module Webhooks
1515
end
1616
end
1717

18+
let(:base_url) { "http://broker" }
19+
1820
let(:pact) do
1921
double("pact",
2022
consumer_version: consumer_version,
@@ -93,7 +95,7 @@ module Webhooks
9395
let(:nil_pact) { nil }
9496
let(:nil_verification) { nil }
9597

96-
subject { Render.call(template, pact, verification) }
98+
subject { Render.call(template, pact, verification, base_url) }
9799

98100
TEST_CASES = [
99101
["${pactbroker.pactUrl}", "http://foo", :pact, :verification],
@@ -122,15 +124,15 @@ module Webhooks
122124
it "replaces #{template} with #{expected_output.inspect}" do
123125
the_pact = send(pact_var_name)
124126
the_verification = send(verification_var_name)
125-
output = Render.call(template, the_pact, the_verification)
127+
output = Render.call(template, the_pact, the_verification, base_url)
126128
expect(output).to eq expected_output
127129
end
128130
end
129131
end
130132

131133
context "with an escaper" do
132134
subject do
133-
Render.call(template, pact, verification) do | value |
135+
Render.call(template, pact, verification, base_url) do | value |
134136
CGI.escape(value)
135137
end
136138
end
@@ -145,13 +147,14 @@ module Webhooks
145147
describe "#call with placeholder domain objects" do
146148
let(:placeholder_pact) { PactBroker::Pacts::PlaceholderPact.new }
147149
let(:placeholder_verification) { PactBroker::Verifications::PlaceholderVerification.new }
150+
let(:base_url) { "http://broker" }
148151

149152
it "does not blow up with a placeholder pact" do
150-
Render.call("", placeholder_pact)
153+
Render.call("", placeholder_pact, nil, base_url)
151154
end
152155

153156
it "does not blow up with a placeholder verification" do
154-
Render.call("", placeholder_pact, placeholder_verification)
157+
Render.call("", placeholder_pact, placeholder_verification, base_url)
155158
end
156159
end
157160
end

spec/lib/pact_broker/webhooks/service_spec.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,16 @@ module Webhooks
105105
let(:options) do
106106
{
107107
failure_log_message: "Webhook execution failed",
108-
show_response: 'foo'
108+
show_response: 'foo',
109+
base_url: 'http://broker'
109110
}
110111
end
111112

112113
before do
113114
allow(PactBroker::Pacts::Service).to receive(:search_for_latest_pact).and_return(pact)
114115
allow(PactBroker::Verifications::Service).to receive(:search_for_latest).and_return(verification)
115116
allow(PactBroker.configuration).to receive(:show_webhook_response?).and_return('foo')
117+
allow(Service).to receive(:base_url).and_return("http://broker")
116118
end
117119

118120
subject { Service.test_execution(webhook) }

0 commit comments

Comments
 (0)