pact_broker 2.12.0 → 2.13.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 +42 -5
- data/README.md +13 -8
- data/bethtest.rb +21 -94
- data/db/migrations/20171112_add_test_results.rb +7 -0
- data/db/migrations/20171117_create_webhook_events.rb +14 -0
- data/db/migrations/20171118_create_webhook_events.rb +18 -0
- data/db/migrations/20180108_create_certificates_table.rb +14 -0
- data/db/migrations/20180109_migrate_trigger_type.rb +9 -0
- data/db/pact_broker_database.sqlite3 +0 -0
- data/db/test/backwards_compatibility/gemfiles/1.18.0.gemfile.lock +5 -5
- data/db/test/backwards_compatibility/gemfiles/2.0.0.gemfile.lock +5 -5
- data/db/test/backwards_compatibility/gemfiles/2.1.0.gemfile.lock +5 -5
- data/db/test/backwards_compatibility/gemfiles/2.2.0.gemfile.lock +12 -14
- data/db/test/backwards_compatibility/gemfiles/2.3.0.gemfile.lock +12 -14
- data/db/test/backwards_compatibility/gemfiles/2.4.2.gemfile.lock +12 -14
- data/db/test/backwards_compatibility/gemfiles/2.5.1.gemfile.lock +12 -14
- data/db/test/backwards_compatibility/gemfiles/2.6.0.gemfile.lock +12 -14
- data/db/test/backwards_compatibility/gemfiles/head.gemfile.lock +16 -15
- data/db/test/change_migration_strategy/before/Gemfile +1 -0
- data/example/README.md +65 -0
- data/example/config.ru +1 -0
- data/example/example_data.sql +17 -0
- data/lib/pact_broker/api.rb +1 -1
- data/lib/pact_broker/api/contracts/webhook_contract.rb +9 -1
- data/lib/pact_broker/api/decorators/verification_decorator.rb +1 -0
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +35 -5
- data/lib/pact_broker/api/resources/matrix_badge.rb +21 -0
- data/lib/pact_broker/certificates/certificate.rb +8 -0
- data/lib/pact_broker/certificates/service.rb +41 -0
- data/lib/pact_broker/doc/controllers/app.rb +12 -2
- data/lib/pact_broker/doc/views/webhooks.markdown +37 -2
- data/lib/pact_broker/domain/verification.rb +2 -0
- data/lib/pact_broker/domain/webhook.rb +2 -1
- data/lib/pact_broker/domain/webhook_request.rb +22 -4
- data/lib/pact_broker/error.rb +5 -0
- data/lib/pact_broker/matrix/parse_query.rb +7 -10
- data/lib/pact_broker/matrix/repository.rb +5 -32
- data/lib/pact_broker/matrix/service.rb +21 -3
- data/lib/pact_broker/pacts/repository.rb +9 -2
- data/lib/pact_broker/pacts/service.rb +2 -2
- data/lib/pact_broker/services.rb +5 -0
- data/lib/pact_broker/ui/app.rb +15 -0
- data/lib/pact_broker/ui/controllers/matrix.rb +58 -3
- data/lib/pact_broker/ui/views/matrix/show.haml +65 -10
- data/lib/pact_broker/verifications/service.rb +6 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/job.rb +1 -1
- data/lib/pact_broker/webhooks/repository.rb +17 -0
- data/lib/pact_broker/webhooks/service.rb +8 -7
- data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -1
- data/lib/pact_broker/webhooks/webhook.rb +3 -0
- data/lib/pact_broker/webhooks/webhook_event.rb +24 -0
- data/pact_broker.gemspec +2 -1
- data/public/javascripts/matrix.js +60 -0
- data/public/stylesheets/matrix.css +12 -0
- data/script/db-spec.sh +1 -0
- data/script/foo-bar-verification.json +57 -0
- data/script/insert-self-signed-certificate-from-url.rb +32 -0
- data/script/publish-verification.sh +5 -0
- data/script/seed-matrix.rb +6 -5
- data/script/seed.rb +67 -59
- data/spec/features/create_webhook_spec.rb +4 -1
- data/spec/features/get_matrix_badge_spec.rb +40 -0
- data/spec/features/publish_verification_spec.rb +28 -4
- data/spec/fixtures/certificate-invalid.pem +29 -0
- data/spec/fixtures/certificate.pem +53 -0
- data/spec/fixtures/certificates/cacert.pem +21 -0
- data/spec/fixtures/certificates/cert.pem +20 -0
- data/spec/fixtures/certificates/key.pem +27 -0
- data/spec/fixtures/certificates/self-signed.badssl.com.pem +21 -0
- data/spec/fixtures/verification.json +4 -1
- data/spec/fixtures/webhook_valid.json +3 -0
- data/spec/integration/webhooks/certificate_spec.rb +80 -0
- data/spec/lib/pact_broker/api/contracts/webhook_contract_spec.rb +20 -0
- data/spec/lib/pact_broker/api/decorators/pact_webhooks_status_decorator_spec.rb +2 -2
- data/spec/lib/pact_broker/api/decorators/verification_decorator_spec.rb +5 -0
- data/spec/lib/pact_broker/api/decorators/verification_summary_decorator_spec.rb +1 -0
- data/spec/lib/pact_broker/api/decorators/webhook_decorator_spec.rb +29 -19
- data/spec/lib/pact_broker/api/resources/badge_spec.rb +61 -0
- data/spec/lib/pact_broker/api/resources/matrix_badge_spec.rb +11 -0
- data/spec/lib/pact_broker/api/resources/pact_webhooks_spec.rb +8 -9
- data/spec/lib/pact_broker/certificates/service_spec.rb +60 -0
- data/spec/lib/pact_broker/domain/verification_spec.rb +13 -0
- data/spec/lib/pact_broker/domain/webhook_request_spec.rb +0 -4
- data/spec/lib/pact_broker/matrix/service_spec.rb +40 -8
- data/spec/lib/pact_broker/pacts/repository_spec.rb +18 -1
- data/spec/lib/pact_broker/webhooks/job_spec.rb +1 -1
- data/spec/lib/pact_broker/webhooks/repository_spec.rb +53 -13
- data/spec/lib/pact_broker/webhooks/service_spec.rb +9 -6
- data/spec/migrations/change_migration_strategy_spec.rb +13 -14
- data/spec/spec_helper.rb +4 -0
- data/spec/support/ssl_webhook_server.rb +37 -0
- data/spec/support/test_data_builder.rb +12 -4
- data/tasks/database.rb +9 -7
- data/tasks/database/table_dependency_calculator.rb +44 -0
- metadata +57 -6
- data/lib/pact_broker/doc/views/pact-webhooks.markdown +0 -50
- data/lib/pact_broker/doc/views/webhooks-create.markdown +0 -38
- data/lib/pact_broker/doc/views/webhooks-webhooks.markdown +0 -15
@@ -2,5 +2,6 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gem "rake", "~>12.0"
|
4
4
|
gem "pact_broker", git: "https://github.com/pact-foundation/pact_broker.git", ref: "11d3464a120ed5f76e23241c79992fa04b702701"
|
5
|
+
gem "webrick", "~>1.3.0" # Webrick requires Ruby version >= 2.5.0dev. TODO remove dependency on Pact gem.
|
5
6
|
gem "sqlite3", "~>1.3"
|
6
7
|
gem "pg"
|
data/example/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Run Pact Broker example
|
2
|
+
|
3
|
+
Clone project
|
4
|
+
|
5
|
+
```bash
|
6
|
+
git clone https://github.com/pact-foundation/pact_broker
|
7
|
+
```
|
8
|
+
|
9
|
+
Change directory to `example`
|
10
|
+
|
11
|
+
```bash
|
12
|
+
cd pact_broker/example
|
13
|
+
```
|
14
|
+
|
15
|
+
## Run with sqlite database
|
16
|
+
|
17
|
+
Install dependencies
|
18
|
+
|
19
|
+
```bash
|
20
|
+
bundle install
|
21
|
+
```
|
22
|
+
|
23
|
+
Run Pact Broker
|
24
|
+
|
25
|
+
```bash
|
26
|
+
bundle exec rackup
|
27
|
+
```
|
28
|
+
|
29
|
+
## Run with postgres database
|
30
|
+
|
31
|
+
Uncomment `gem 'pg'` in the [Gemfile](Gemfile)
|
32
|
+
|
33
|
+
Comment out `gem 'sqlite3'` in the [Gemfile](Gemfile)
|
34
|
+
|
35
|
+
Comment out the line with `DATABASE_CREDENTIALS = {adapter: "sqlite"...` in the [config.ru](config.ru#L9).
|
36
|
+
|
37
|
+
Uncomment the line with `DATABASE_CREDENTIALS = {adapter: "postgres"...`. in the [config.ru](config.ru#L17).
|
38
|
+
|
39
|
+
Set up postgres database
|
40
|
+
|
41
|
+
```bash
|
42
|
+
psql postgres -c "CREATE DATABASE pact_broker;"
|
43
|
+
psql postgres -c "CREATE ROLE pact_broker WITH LOGIN PASSWORD 'pact_broker';"
|
44
|
+
psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker TO pact_broker;"
|
45
|
+
```
|
46
|
+
|
47
|
+
Install dependencies
|
48
|
+
|
49
|
+
```bash
|
50
|
+
bundle install
|
51
|
+
```
|
52
|
+
|
53
|
+
Run Pact Broker
|
54
|
+
|
55
|
+
```bash
|
56
|
+
bundle exec rackup
|
57
|
+
```
|
58
|
+
|
59
|
+
If you need an example data run following command
|
60
|
+
|
61
|
+
```bash
|
62
|
+
psql pact_broker < example_data.sql
|
63
|
+
```
|
64
|
+
|
65
|
+
Now Pact Broker can be access locally at [http://localhost:9292](http://localhost:9292).
|
data/example/config.ru
CHANGED
@@ -11,6 +11,7 @@ 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 'pact_broker';"
|
14
15
|
# $ psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE pact_broker TO pact_broker;"
|
15
16
|
#
|
16
17
|
# DATABASE_CREDENTIALS = {adapter: "postgres", database: "pact_broker", username: 'pact_broker', password: 'pact_broker', :encoding => 'utf8'}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
BEGIN TRANSACTION;
|
2
|
+
INSERT INTO pacticipants VALUES(1,'Animal Service',NULL,'2014-11-18 06:28:36.261868','2014-11-18 06:28:36.261868');
|
3
|
+
INSERT INTO pacticipants VALUES(2,'Zoo App',NULL,'2014-11-18 06:28:36.290466','2014-11-18 06:28:36.290466');
|
4
|
+
INSERT INTO pacticipants VALUES(3,'Bar',NULL,'2017-05-23 06:10:23.235822','2017-05-23 06:10:23.235822');
|
5
|
+
INSERT INTO pacticipants VALUES(4,'Foo',NULL,'2017-05-23 06:10:23.239004','2017-05-23 06:10:23.239004');
|
6
|
+
INSERT INTO versions VALUES(1,'1.0.0',NULL,2,0,'2014-11-18 06:28:36.295750','2014-11-18 06:28:36.333021');
|
7
|
+
INSERT INTO versions VALUES(2,'1.0.1',NULL,2,1,'2015-01-19 22:13:57.743993','2015-01-19 22:13:57.746417');
|
8
|
+
INSERT INTO versions VALUES(3,'1.0.2',NULL,2,2,'2016-11-08 22:45:37.244731','2016-11-08 22:45:37.274760');
|
9
|
+
INSERT INTO versions VALUES(4,'1.0.0',NULL,4,0,'2017-05-23 06:10:23.243015','2017-05-23 06:10:23.245281');
|
10
|
+
INSERT INTO pact_versions VALUES(1,2,1,'15a22e805caa9d0153b815fc6566a0c03d4a82ae',replace('{\n "provider": {\n "name": "Animal Service"\n },\n "consumer": {\n "name": "Zoo App"\n },\n "interactions": [\n {\n "description": "a request for an alligator",\n "provider_state": "there is an alligator named Mary",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 200,\n "headers": {\n "Content-Type": "application/json;charset=utf-8"\n },\n "body": {\n "name": "Mary"\n }\n }\n },\n {\n "description": "a request for an alligator",\n "provider_state": "there is not an alligator named Mary",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 404\n }\n },\n {\n "description": "a request for an alligator",\n "provider_state": "an error occurs retrieving an alligator",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 500,\n "headers": {\n "Content-Type": "application/json;charset=utf-8"\n },\n "body": {\n "error": "Argh!!!"\n }\n }\n }\n ],\n "metadata": {\n "pactSpecificationVersion": "1.0.0"\n }\n}','\n',''),'2014-11-18 06:28:36.340041');
|
11
|
+
INSERT INTO pact_versions VALUES(3,2,1,'23b64b5c5f5baf0e56dd92c4deddf9eb1e249d11',replace('{\n "provider": {\n "name": "Animal Service"\n },\n "consumer": {\n "name": "Zoo App"\n },\n "interactions": [\n {\n "description": "a request for an alligator",\n "provider_state": "there is an alligator named Mary",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 200,\n "headers": {\n "Content-Type": "application/json;charset=utf-8"\n },\n "body": {\n "name": "Mary"\n }\n }\n },\n {\n "description": "a request for an alligator",\n "provider_state": "there is not an alligator named Mary",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 404\n }\n },\n {\n "description": "a request for an alligator",\n "provider_state": "an error occurs retrieving an alligator",\n "request": {\n "method": "get",\n "path": "/alligators/Mary",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 500,\n "headers": {\n "Content-Type": "application/json;charset=utf-8"\n },\n "body": {\n "error": "Argh!!!"\n }\n }\n },\n {\n "description": "a request for an alligator''s sister",\n "provider_state": "there is an alligator named Mary",\n "request": {\n "method": "get",\n "path": "/alligators/Mary/sister",\n "headers": {\n "Accept": "application/json"\n }\n },\n "response": {\n "status": 200,\n "headers": {\n "Content-Type": "application/json;charset=utf-8"\n },\n "body": {\n "name": "Sue"\n }\n }\n }\n ],\n "metadata": {\n "pactSpecificationVersion": "1.0.0"\n }\n}','\n',''),'2015-01-19 22:15:10.964768');
|
12
|
+
INSERT INTO pact_versions VALUES(4,4,3,'73cd294d54d900e5ebb313896b1df8d1da8914f9',replace('{\n "consumer": {\n "name": "Foo"\n },\n "provider": {\n "name": "Bar"\n },\n "interactions": [\n {\n "description": "a retrieve thing request",\n "request": {\n "method": "get",\n "path": "/thing"\n },\n "response": {\n "status": 200,\n "headers": {\n "Content-Type": "application/json"\n },\n "body": [\n {\n "status": "4"\n }\n ],\n "matchingRules": {\n "$.body": {\n "min": 1\n },\n "$.body[*].*": {\n "match": "type"\n },\n "$.body[*].status": {\n "match": "regex",\n "regex": "\\d+"\n }\n }\n }\n }\n ],\n "metadata": {\n "pactSpecification": {\n "version": "2.0.0"\n }\n }\n}','\n',''),'2017-05-23 06:10:23.249813');
|
13
|
+
INSERT INTO pact_publications VALUES(1,1,1,1,1,'2014-11-18 06:28:36.340041');
|
14
|
+
INSERT INTO pact_publications VALUES(2,2,1,1,3,'2015-01-19 22:15:10.969518');
|
15
|
+
INSERT INTO pact_publications VALUES(3,3,1,1,1,'2016-11-08 22:45:37.291839');
|
16
|
+
INSERT INTO pact_publications VALUES(4,4,3,1,4,'2017-05-23 06:10:23.252829');
|
17
|
+
COMMIT;
|
data/lib/pact_broker/api.rb
CHANGED
@@ -61,6 +61,7 @@ module PactBroker
|
|
61
61
|
|
62
62
|
# matrix
|
63
63
|
add ['matrix', 'provider', :provider_name, 'consumer', :consumer_name], Api::Resources::MatrixForConsumerAndProvider, {resource_name: "matrix_consumer_provider"}
|
64
|
+
add ['matrix', 'provider', :provider_name, 'latest', :provider_tag, 'consumer', :consumer_name, 'latest', :tag, 'badge'], Api::Resources::MatrixBadge, {resource_name: "matrix_tag_badge"}
|
64
65
|
add ['matrix'], Api::Resources::Matrix, {resource_name: "matrix"}
|
65
66
|
|
66
67
|
add [], Api::Resources::Index, {resource_name: "index"}
|
@@ -73,5 +74,4 @@ module PactBroker
|
|
73
74
|
|
74
75
|
pact_api.adapter
|
75
76
|
end
|
76
|
-
|
77
77
|
end
|
@@ -5,7 +5,6 @@ module PactBroker
|
|
5
5
|
module Api
|
6
6
|
module Contracts
|
7
7
|
class WebhookContract < Reform::Form
|
8
|
-
property :request
|
9
8
|
|
10
9
|
validation do
|
11
10
|
configure do
|
@@ -13,6 +12,7 @@ module PactBroker
|
|
13
12
|
end
|
14
13
|
|
15
14
|
required(:request).filled
|
15
|
+
optional(:events).maybe(min_size?: 1)
|
16
16
|
end
|
17
17
|
|
18
18
|
property :request do
|
@@ -39,6 +39,14 @@ module PactBroker
|
|
39
39
|
required(:url).filled(:valid_url?)
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
collection :events do
|
44
|
+
property :name
|
45
|
+
|
46
|
+
validation do
|
47
|
+
required(:name).filled
|
48
|
+
end
|
49
|
+
end
|
42
50
|
end
|
43
51
|
end
|
44
52
|
end
|
@@ -2,19 +2,24 @@ require_relative 'base_decorator'
|
|
2
2
|
require 'pact_broker/api/decorators/webhook_request_decorator'
|
3
3
|
require 'pact_broker/api/decorators/timestamps'
|
4
4
|
require 'pact_broker/domain/webhook_request'
|
5
|
+
require 'pact_broker/webhooks/webhook_event'
|
5
6
|
require 'pact_broker/api/decorators/basic_pacticipant_decorator'
|
7
|
+
require_relative 'pact_pacticipant_decorator'
|
8
|
+
require_relative 'pacticipant_decorator'
|
6
9
|
|
7
10
|
module PactBroker
|
8
11
|
module Api
|
9
12
|
module Decorators
|
10
13
|
class WebhookDecorator < BaseDecorator
|
11
14
|
|
12
|
-
|
15
|
+
class WebhookEventDecorator < BaseDecorator
|
16
|
+
property :name
|
17
|
+
end
|
13
18
|
|
14
|
-
|
19
|
+
property :request, :class => PactBroker::Domain::WebhookRequest, extend: WebhookRequestDecorator
|
20
|
+
collection :events, :class => PactBroker::Webhooks::WebhookEvent, extend: WebhookEventDecorator
|
15
21
|
|
16
|
-
|
17
|
-
property :provider, :extend => PactBroker::Api::Decorators::BasicPacticipantDecorator, :embedded => true, writeable: false
|
22
|
+
include Timestamps
|
18
23
|
|
19
24
|
link :self do | options |
|
20
25
|
{
|
@@ -31,9 +36,26 @@ module PactBroker
|
|
31
36
|
}
|
32
37
|
end
|
33
38
|
|
39
|
+
|
40
|
+
link :'pb:consumer' do | options |
|
41
|
+
{
|
42
|
+
title: "Consumer",
|
43
|
+
name: represented.consumer.name,
|
44
|
+
href: pacticipant_url(options.fetch(:base_url), represented.consumer)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
link :'pb:provider' do | options |
|
49
|
+
{
|
50
|
+
title: "Provider",
|
51
|
+
name: represented.provider.name,
|
52
|
+
href: pacticipant_url(options.fetch(:base_url), represented.provider)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
34
56
|
link :'pb:pact-webhooks' do | options |
|
35
57
|
{
|
36
|
-
title: "All webhooks for
|
58
|
+
title: "All webhooks for consumer #{represented.consumer.name} and provider #{represented.provider.name}",
|
37
59
|
href: webhooks_for_pact_url(represented.consumer, represented.provider, options[:base_url])
|
38
60
|
}
|
39
61
|
end
|
@@ -44,6 +66,14 @@ module PactBroker
|
|
44
66
|
href: webhooks_url(options[:base_url])
|
45
67
|
}
|
46
68
|
end
|
69
|
+
|
70
|
+
def from_json represented
|
71
|
+
super.tap do | webhook |
|
72
|
+
if webhook.events == nil
|
73
|
+
webhook.events = [PactBroker::Webhooks::WebhookEvent.new(name: PactBroker::Webhooks::WebhookEvent::DEFAULT_EVENT_NAME)]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
47
77
|
end
|
48
78
|
end
|
49
79
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'pact_broker/api/resources/badge'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Api
|
5
|
+
module Resources
|
6
|
+
class MatrixBadge < Badge
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def latest_verification
|
11
|
+
@latest_verification ||= begin
|
12
|
+
matrix_row = matrix_service.find_for_consumer_and_provider_with_tags(identifier_from_path)
|
13
|
+
if matrix_row && matrix_row[:verification_id]
|
14
|
+
verification_service.find_by_id(matrix_row[:verification_id])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pact_broker/certificates/certificate'
|
2
|
+
require 'pact_broker/logging'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module PactBroker
|
6
|
+
module Certificates
|
7
|
+
module Service
|
8
|
+
|
9
|
+
extend self
|
10
|
+
extend PactBroker::Logging
|
11
|
+
|
12
|
+
def cert_store
|
13
|
+
cert_store = OpenSSL::X509::Store.new
|
14
|
+
cert_store.set_default_paths
|
15
|
+
find_all_certificates.each do | certificate |
|
16
|
+
begin
|
17
|
+
logger.debug("Loading certificate #{certificate.subject} in to cert store")
|
18
|
+
cert_store.add_cert(certificate)
|
19
|
+
rescue StandardError => e
|
20
|
+
log_error e, "Error adding certificate object #{certificate.to_s} to store"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
cert_store
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_all_certificates
|
27
|
+
Certificate.collect do | certificate |
|
28
|
+
cert_arr = certificate.content.split(/(-----END [^\-]+-----)/).each_slice(2).map(&:join)
|
29
|
+
cert_arr.collect do |c|
|
30
|
+
begin
|
31
|
+
OpenSSL::X509::Certificate.new(c)
|
32
|
+
rescue StandardError => e
|
33
|
+
log_error e, "Error creating certificate object from certificate #{certificate.uuid} '#{certificate.description}'"
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end.flatten.compact
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -11,16 +11,26 @@ module PactBroker
|
|
11
11
|
set :root, File.join(File.dirname(__FILE__), '..')
|
12
12
|
set :show_exceptions, true
|
13
13
|
|
14
|
+
MAPPINGS = {
|
15
|
+
'webhooks-create' => 'webhooks',
|
16
|
+
'webhooks-webhooks' => 'webhooks',
|
17
|
+
'pact-webhooks' => 'webhooks',
|
18
|
+
}.freeze
|
19
|
+
|
14
20
|
helpers do
|
21
|
+
def view_name_for rel_name
|
22
|
+
MAPPINGS[rel_name] || rel_name
|
23
|
+
end
|
24
|
+
|
15
25
|
def resource_exists? rel_name
|
16
|
-
File.exist? File.join(self.class.root, 'views', "#{rel_name}.markdown")
|
26
|
+
File.exist? File.join(self.class.root, 'views', "#{view_name_for(rel_name)}.markdown")
|
17
27
|
end
|
18
28
|
end
|
19
29
|
|
20
30
|
get ":rel_name" do
|
21
31
|
rel_name = params[:rel_name]
|
22
32
|
if resource_exists? rel_name
|
23
|
-
markdown rel_name.to_sym, {:layout_engine => :haml, layout: :'layouts/main'}, {}
|
33
|
+
markdown view_name_for(rel_name).to_sym, {:layout_engine => :haml, layout: :'layouts/main'}, {}
|
24
34
|
else
|
25
35
|
response.status = 404
|
26
36
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# Webhooks
|
2
2
|
|
3
|
-
Allowed methods: GET
|
3
|
+
Allowed methods (collection resource): `GET`, `POST`
|
4
|
+
|
5
|
+
Allowed methods (individual resource): `GET`, `PUT`, `DELETE`
|
4
6
|
|
5
7
|
### Creating
|
6
8
|
|
@@ -9,9 +11,12 @@ Allowed methods: GET, POST, DELETE
|
|
9
11
|
2. Click the "NON-GET" button for the "pact-webhooks" relation.
|
10
12
|
3. Paste in the webhook JSON (example shown below) in the body section and click "Make Request".
|
11
13
|
|
12
|
-
An example webhook to trigger a Bamboo job.
|
14
|
+
An example webhook to trigger a Bamboo job when a contract has changed.
|
13
15
|
|
14
16
|
{
|
17
|
+
"events": [{
|
18
|
+
"name": "contract_content_changed"
|
19
|
+
}],
|
15
20
|
"request": {
|
16
21
|
"method": "POST",
|
17
22
|
"url": "http://master.ci.my.domain:8085/rest/api/latest/queue/SOME-PROJECT?os_authType=basic",
|
@@ -26,6 +31,9 @@ An example webhook to trigger a Bamboo job.
|
|
26
31
|
A request body can be specified as well.
|
27
32
|
|
28
33
|
{
|
34
|
+
"events": [{
|
35
|
+
"name": "contract_content_changed"
|
36
|
+
}],
|
29
37
|
"request": {
|
30
38
|
"method": "POST",
|
31
39
|
"url": "http://example.org/something",
|
@@ -37,6 +45,33 @@ A request body can be specified as well.
|
|
37
45
|
|
38
46
|
**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!
|
39
47
|
|
48
|
+
#### Event types
|
49
|
+
|
50
|
+
`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.
|
51
|
+
|
52
|
+
`provider_verification_published:` triggered whenever a provider publishes a verification.
|
53
|
+
|
54
|
+
### Dynamic variable substitution
|
55
|
+
|
56
|
+
The following variables may be used in the request parameters or body, and will be replaced with their appropriate values at runtime.
|
57
|
+
|
58
|
+
`${pactbroker.pactUrl}`: the "permalink" URL to the newly published pact (the URL specifying the consumer version URL, rather than the "/latest" format.)
|
59
|
+
|
60
|
+
Example usage:
|
61
|
+
|
62
|
+
{
|
63
|
+
"events": [{
|
64
|
+
"name": "contract_content_changed"
|
65
|
+
}],
|
66
|
+
"request": {
|
67
|
+
"method": "POST",
|
68
|
+
"url": "http://example.org/something",
|
69
|
+
"body": {
|
70
|
+
"thisPactWasPublished" : "${pactbroker.pactUrl}"
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
40
75
|
### Testing
|
41
76
|
|
42
77
|
To test a webhook, navigate to the webhook in the HAL browser, then make a POST request to the "execute" relation. The response or error will be shown in the window.
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'pact_broker/db'
|
2
2
|
require 'pact_broker/repositories/helpers'
|
3
|
+
require 'json'
|
3
4
|
|
4
5
|
module PactBroker
|
5
6
|
|
@@ -9,6 +10,7 @@ module PactBroker
|
|
9
10
|
set_primary_key :id
|
10
11
|
associate(:many_to_one, :pact_version, class: "PactBroker::Pacts::PactVersion", key: :pact_version_id, primary_key: :id)
|
11
12
|
associate(:many_to_one, :provider_version, class: "PactBroker::Domain::Version", key: :provider_version_id, primary_key: :id)
|
13
|
+
plugin :serialization, :json, :test_results
|
12
14
|
|
13
15
|
def before_create
|
14
16
|
super
|
@@ -10,7 +10,7 @@ module PactBroker
|
|
10
10
|
include Messages
|
11
11
|
include Logging
|
12
12
|
|
13
|
-
attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at
|
13
|
+
attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at, :events
|
14
14
|
attr_reader :attributes
|
15
15
|
|
16
16
|
def initialize attributes = {}
|
@@ -19,6 +19,7 @@ module PactBroker
|
|
19
19
|
@request = attributes[:request]
|
20
20
|
@consumer = attributes[:consumer]
|
21
21
|
@provider = attributes[:provider]
|
22
|
+
@events = attributes[:events]
|
22
23
|
@created_at = attributes[:created_at]
|
23
24
|
@updated_at = attributes[:updated_at]
|
24
25
|
end
|
@@ -5,6 +5,7 @@ require 'pact_broker/messages'
|
|
5
5
|
require 'net/http'
|
6
6
|
require 'pact_broker/webhooks/redact_logs'
|
7
7
|
require 'pact_broker/api/pact_broker_urls'
|
8
|
+
require 'pact_broker/services'
|
8
9
|
|
9
10
|
module PactBroker
|
10
11
|
|
@@ -23,6 +24,7 @@ module PactBroker
|
|
23
24
|
|
24
25
|
include PactBroker::Logging
|
25
26
|
include PactBroker::Messages
|
27
|
+
include PactBroker::Services
|
26
28
|
|
27
29
|
attr_accessor :method, :url, :headers, :body, :username, :password, :uuid
|
28
30
|
|
@@ -102,8 +104,13 @@ module PactBroker
|
|
102
104
|
|
103
105
|
def do_request uri, req
|
104
106
|
logger.info "Making webhook #{uuid} request #{to_s}"
|
105
|
-
|
106
|
-
|
107
|
+
options = {}
|
108
|
+
if uri.scheme == 'https'
|
109
|
+
options[:use_ssl] = true
|
110
|
+
options[:verify_mode] = OpenSSL::SSL::VERIFY_PEER
|
111
|
+
options[:cert_store] = cert_store
|
112
|
+
end
|
113
|
+
Net::HTTP.start(uri.hostname, uri.port, options) do |http|
|
107
114
|
http.request req
|
108
115
|
end
|
109
116
|
end
|
@@ -120,8 +127,15 @@ module PactBroker
|
|
120
127
|
end
|
121
128
|
|
122
129
|
def log_completion_message options, execution_logger, success
|
123
|
-
|
124
|
-
|
130
|
+
if options[:success_log_message] && success
|
131
|
+
execution_logger.info(options[:success_log_message])
|
132
|
+
logger.info(options[:success_log_message])
|
133
|
+
end
|
134
|
+
|
135
|
+
if options[:failure_log_message] && !success
|
136
|
+
execution_logger.info(options[:failure_log_message])
|
137
|
+
logger.info(options[:failure_log_message])
|
138
|
+
end
|
125
139
|
end
|
126
140
|
|
127
141
|
def to_s
|
@@ -153,6 +167,10 @@ module PactBroker
|
|
153
167
|
escaped_pact_url = CGI::escape(pact_url)
|
154
168
|
url.gsub('${pactbroker.pactUrl}', escaped_pact_url)
|
155
169
|
end
|
170
|
+
|
171
|
+
def cert_store
|
172
|
+
certificate_service.cert_store
|
173
|
+
end
|
156
174
|
end
|
157
175
|
end
|
158
176
|
end
|