pact_broker 2.27.0 → 2.27.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +1 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +4 -0
- data/lib/pact_broker/app.rb +2 -0
- data/lib/pact_broker/doc/views/webhooks.markdown +4 -2
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/check_host_whitelist.rb +27 -7
- data/lib/rack/pact_broker/convert_404_to_hal.rb +20 -0
- data/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb +7 -5
- data/pact_broker.gemspec +0 -1
- data/spec/lib/pact_broker/app_spec.rb +17 -1
- data/spec/lib/pact_broker/webhooks/check_host_whitelist_spec.rb +38 -0
- metadata +4 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e67bad7e9a3ecb1e2ecd911350a937615bf9b2f90ac811ad48acf16185ffee41
|
4
|
+
data.tar.gz: e55c77c181b1d2e37e20a6b0a4f6b500ebdba7b0c861597c8f80b580915d9a3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fcd28aeb22cee45696bee504bb1c6b49cec7faa83185df24c5854e9a22fd2023bee57f62fbea2fad54f5c4f590e1de91febab56f3baa1a15a7656d692a0d816
|
7
|
+
data.tar.gz: 18a6fe1f7dd9c61143ea1fe7bf031576c8d1d615d0a212dc2b8e833ad5fd14de39c606e92ea021f82f8b64015ba3e12a7f8cccc317fd5979c30a965b153cb773
|
data/.travis.yml
CHANGED
@@ -11,6 +11,7 @@ env:
|
|
11
11
|
global:
|
12
12
|
- CC_TEST_REPORTER_ID=dc2c30b67c9e2a5309e1aef699c30fdab55ba4f0e4f1beac029ba93e293835db
|
13
13
|
- GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi)
|
14
|
+
- INSTALL_MYSQL=true
|
14
15
|
matrix:
|
15
16
|
- DATABASE_ADAPTER=default RUBYOPT="-W0"
|
16
17
|
- DATABASE_ADAPTER=postgres RUBYOPT="-W0"
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
<a name="v2.27.2"></a>
|
2
|
+
### v2.27.2 (2018-09-14)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* use application/yaml instead of application/x-yaml to match Swaggerhub ([067d6ac7](/../../commit/067d6ac7))
|
8
|
+
* treat .yaml requests as having header Accept: application/x-yaml ([1c8e199f](/../../commit/1c8e199f))
|
9
|
+
|
10
|
+
* **webhook whitelist**
|
11
|
+
* allow hosts to be whitelisted using * domains ([150858a1](/../../commit/150858a1))
|
12
|
+
|
13
|
+
|
14
|
+
#### Bug Fixes
|
15
|
+
|
16
|
+
* **content-type**
|
17
|
+
* convert 404 content-type to application/hal+json #235 ([83958db7](/../../commit/83958db7))
|
18
|
+
|
19
|
+
|
1
20
|
<a name="v2.27.0"></a>
|
2
21
|
### v2.27.0 (2018-09-07)
|
3
22
|
|
data/Gemfile
CHANGED
data/lib/pact_broker/app.rb
CHANGED
@@ -12,6 +12,7 @@ require 'rack/pact_broker/accepts_html_filter'
|
|
12
12
|
require 'rack/pact_broker/ui_authentication'
|
13
13
|
require 'rack/pact_broker/configurable_make_it_later'
|
14
14
|
require 'rack/pact_broker/no_auth'
|
15
|
+
require 'rack/pact_broker/convert_404_to_hal'
|
15
16
|
require 'sucker_punch'
|
16
17
|
|
17
18
|
module PactBroker
|
@@ -145,6 +146,7 @@ module PactBroker
|
|
145
146
|
require 'pact_broker/api'
|
146
147
|
builder = ::Rack::Builder.new
|
147
148
|
builder.use @make_it_later_api_auth
|
149
|
+
builder.use Rack::PactBroker::Convert404ToHal
|
148
150
|
builder.use Rack::PactBroker::DatabaseTransaction, configuration.database_connection
|
149
151
|
builder.run PactBroker::API
|
150
152
|
builder
|
@@ -123,7 +123,7 @@ Pact Broker Github repository.
|
|
123
123
|
|
124
124
|
* **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).
|
125
125
|
|
126
|
-
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.
|
126
|
+
The host whitelist may contain hostnames (eg `"github.com"`), domains beginning with `*` (eg. `"*.foo.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.
|
127
127
|
|
128
128
|
The recommended set of values to start with are:
|
129
129
|
|
@@ -131,7 +131,9 @@ Pact Broker Github repository.
|
|
131
131
|
* your company chat (eg. Slack, for publishing notifications)
|
132
132
|
* your code repository (eg. Github, for sending commit statuses)
|
133
133
|
|
134
|
-
Alternatively, you could use a
|
134
|
+
Alternatively, you could use a domain beginning with a `*` to limit requests to your company's domain.
|
135
|
+
|
136
|
+
Note that the hostname/domain matching follows that used for SSL certificate hostnames, so `*.foo.com` will match `a.foo.com` but not `a.b.foo.com`. If you need more flexible matching because you have domains with variable "parts" (eg `a.b.foo.com`), you can use a regular expression (eg `/.*\.foo\.com$/` - don't forget the end of string anchor). You can test Ruby regular expressions at [rubular.com](http://rubular.com).
|
135
137
|
|
136
138
|
### Testing
|
137
139
|
|
data/lib/pact_broker/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
1
3
|
module PactBroker
|
2
4
|
module Webhooks
|
3
5
|
class CheckHostWhitelist
|
@@ -7,16 +9,34 @@ module PactBroker
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def self.match?(host, whitelist_host)
|
10
|
-
if
|
11
|
-
host
|
12
|
+
if parse_ip_address(host)
|
13
|
+
ip_address_matches_range(host, whitelist_host)
|
14
|
+
elsif whitelist_host.is_a?(Regexp)
|
15
|
+
host_matches_regexp(host, whitelist_host)
|
16
|
+
elsif whitelist_host.start_with?("*")
|
17
|
+
OpenSSL::SSL.verify_hostname(host, whitelist_host)
|
12
18
|
else
|
13
|
-
|
14
|
-
IPAddr.new(whitelist_host) === IPAddr.new(host)
|
15
|
-
rescue IPAddr::Error
|
16
|
-
host == whitelist_host
|
17
|
-
end
|
19
|
+
host == whitelist_host
|
18
20
|
end
|
19
21
|
end
|
22
|
+
|
23
|
+
def self.parse_ip_address(addr)
|
24
|
+
IPAddr.new(addr)
|
25
|
+
rescue IPAddr::Error
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.ip_address_matches_range(host, maybe_whitelist_range)
|
30
|
+
parse_ip_address(maybe_whitelist_range) === parse_ip_address(host)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.host_matches_regexp(host, whitelist_regexp)
|
34
|
+
host =~ whitelist_regexp
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.host_matches_domain_with_wildcard(host, whitelist_domain)
|
38
|
+
OpenSSL::SSL.verify_hostname(host, whitelist_domain)
|
39
|
+
end
|
20
40
|
end
|
21
41
|
end
|
22
42
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rack
|
2
|
+
module PactBroker
|
3
|
+
class Convert404ToHal
|
4
|
+
|
5
|
+
def initialize app
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call env
|
10
|
+
response = @app.call(env)
|
11
|
+
|
12
|
+
if response.first == 404 && response[1]['Content-Type'] == 'text/html' && !(env['HTTP_ACCEPT'] =~ /html/)
|
13
|
+
[404, { 'Content-Type' => 'application/hal+json'},[]]
|
14
|
+
else
|
15
|
+
response
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,14 +1,18 @@
|
|
1
1
|
module Rack
|
2
2
|
module PactBroker
|
3
|
-
|
4
3
|
# If the HTML and the CSV group resources are both requested by the browser,
|
5
4
|
# Chrome gets confused by the content types, and when you click back, it tries to load the CSV
|
6
5
|
# instead of the HTML page. So we have to give the CSV resource a different URL (.csv)
|
7
6
|
|
8
7
|
class ConvertFileExtensionToAcceptHeader
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
EXTENSION_REGEXP = /\.\w+$/.freeze
|
10
|
+
EXTENSIONS = {
|
11
|
+
".csv" => "text/csv",
|
12
|
+
".svg" => "image/svg+xml",
|
13
|
+
".json" => "application/hal+json",
|
14
|
+
".yaml" => "application/yaml"
|
15
|
+
}
|
12
16
|
|
13
17
|
def initialize app
|
14
18
|
@app = app
|
@@ -37,8 +41,6 @@ module Rack
|
|
37
41
|
"HTTP_ACCEPT" => EXTENSIONS[file_extension]
|
38
42
|
)
|
39
43
|
end
|
40
|
-
|
41
44
|
end
|
42
|
-
|
43
45
|
end
|
44
46
|
end
|
data/pact_broker.gemspec
CHANGED
@@ -47,7 +47,6 @@ Gem::Specification.new do |gem|
|
|
47
47
|
gem.add_development_dependency 'pry-byebug'
|
48
48
|
gem.add_development_dependency 'rake', '~>10.0'
|
49
49
|
gem.add_development_dependency 'fakefs', '~>0.4'
|
50
|
-
gem.add_development_dependency 'mysql2', '~>0.3.15'
|
51
50
|
gem.add_development_dependency 'webmock', '~>2.3'
|
52
51
|
gem.add_development_dependency 'rspec', '~>3.0'
|
53
52
|
gem.add_development_dependency 'rspec-its', '~>1.2'
|
@@ -276,11 +276,27 @@ module PactBroker
|
|
276
276
|
PactBroker::Database.truncate
|
277
277
|
end
|
278
278
|
|
279
|
-
subject { put path, pact_content, {'CONTENT_TYPE' => 'application/json' }; last_response }
|
279
|
+
subject { put path, pact_content, { 'CONTENT_TYPE' => 'application/json' }; last_response }
|
280
280
|
|
281
281
|
it "wraps the API with a database transaction" do
|
282
282
|
expect { subject }.to_not change { PactBroker::Domain::Pacticipant.count }
|
283
283
|
end
|
284
284
|
end
|
285
|
+
|
286
|
+
describe "when resource is not found" do
|
287
|
+
subject { get("/does/not/exist", nil, { 'CONTENT_TYPE' => 'application/hal+json' }) }
|
288
|
+
|
289
|
+
it "returns a Content-Type of application/hal+json" do
|
290
|
+
expect(subject.headers['Content-Type']).to eq 'application/hal+json'
|
291
|
+
end
|
292
|
+
|
293
|
+
it "returns a JSON body" do
|
294
|
+
expect(subject.body).to eq ""
|
295
|
+
end
|
296
|
+
|
297
|
+
it "returns a 404" do
|
298
|
+
expect(subject.status).to eq 404
|
299
|
+
end
|
300
|
+
end
|
285
301
|
end
|
286
302
|
end
|
@@ -23,6 +23,44 @@ module PactBroker
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
context "when the whitelist includes *.foo.bar" do
|
27
|
+
let(:whitelist) { ["*.foo.bar"] }
|
28
|
+
|
29
|
+
it "matches host a.foo.bar" do
|
30
|
+
expect(CheckHostWhitelist.call("a.foo.bar", whitelist)).to eq whitelist
|
31
|
+
end
|
32
|
+
|
33
|
+
it "does not matche host a.b.foo.bar" do
|
34
|
+
expect(CheckHostWhitelist.call("a.b.foo.bar", whitelist)).to eq []
|
35
|
+
end
|
36
|
+
|
37
|
+
it "does not match a.foo.bar.b" do
|
38
|
+
expect(CheckHostWhitelist.call("a.foo.bar.b", whitelist)).to eq []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "does not match foo.bar" do
|
42
|
+
expect(CheckHostWhitelist.call("foo.bar", whitelist)).to eq []
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not match 10.0.0.2" do
|
46
|
+
expect(CheckHostWhitelist.call("10.0.0.2", whitelist)).to eq []
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the whitelist includes *.2" do
|
51
|
+
it "does not match 10.0.0.2 as that's the wrong way to declare an IP range" do
|
52
|
+
expect(CheckHostWhitelist.call("10.0.0.2", ["*.0.0.2"])).to eq []
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when the whitelist includes *.foo.*.bar" do
|
57
|
+
let(:whitelist) { ["*.foo.*.bar"] }
|
58
|
+
|
59
|
+
it "does not match host a.foo.b.bar, according to RFC 6125, section 6.4.3, subitem 1" do
|
60
|
+
expect(CheckHostWhitelist.call("a.foo.b.bar", whitelist)).to eq []
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
26
64
|
context "when the host is localhost" do
|
27
65
|
let(:host) { "localhost" }
|
28
66
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pact_broker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.27.
|
4
|
+
version: 2.27.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bethany Skurrie
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2018-09-
|
13
|
+
date: 2018-09-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
@@ -380,20 +380,6 @@ dependencies:
|
|
380
380
|
- - "~>"
|
381
381
|
- !ruby/object:Gem::Version
|
382
382
|
version: '0.4'
|
383
|
-
- !ruby/object:Gem::Dependency
|
384
|
-
name: mysql2
|
385
|
-
requirement: !ruby/object:Gem::Requirement
|
386
|
-
requirements:
|
387
|
-
- - "~>"
|
388
|
-
- !ruby/object:Gem::Version
|
389
|
-
version: 0.3.15
|
390
|
-
type: :development
|
391
|
-
prerelease: false
|
392
|
-
version_requirements: !ruby/object:Gem::Requirement
|
393
|
-
requirements:
|
394
|
-
- - "~>"
|
395
|
-
- !ruby/object:Gem::Version
|
396
|
-
version: 0.3.15
|
397
383
|
- !ruby/object:Gem::Dependency
|
398
384
|
name: webmock
|
399
385
|
requirement: !ruby/object:Gem::Requirement
|
@@ -976,6 +962,7 @@ files:
|
|
976
962
|
- lib/rack/pact_broker/accepts_html_filter.rb
|
977
963
|
- lib/rack/pact_broker/add_pact_broker_version_header.rb
|
978
964
|
- lib/rack/pact_broker/configurable_make_it_later.rb
|
965
|
+
- lib/rack/pact_broker/convert_404_to_hal.rb
|
979
966
|
- lib/rack/pact_broker/convert_file_extension_to_accept_header.rb
|
980
967
|
- lib/rack/pact_broker/database_transaction.rb
|
981
968
|
- lib/rack/pact_broker/invalid_uri_protection.rb
|
@@ -1351,7 +1338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1351
1338
|
version: '0'
|
1352
1339
|
requirements: []
|
1353
1340
|
rubyforge_project:
|
1354
|
-
rubygems_version: 2.
|
1341
|
+
rubygems_version: 2.7.7
|
1355
1342
|
signing_key:
|
1356
1343
|
specification_version: 4
|
1357
1344
|
summary: See description
|