pact_broker 2.32.0 → 2.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +3 -0
  3. data/CHANGELOG.md +18 -0
  4. data/config/database.yml +5 -8
  5. data/db/migrations/20190510_set_version_sequence.rb +1 -0
  6. data/db/migrations/20190602_add_headers_column_to_webhooks.rb +6 -0
  7. data/db/migrations/20190603_migrate_webhook_headers.rb +10 -0
  8. data/lib/pact_broker/api/resources/index.rb +12 -0
  9. data/lib/pact_broker/api/resources/pact.rb +1 -1
  10. data/lib/pact_broker/api/resources/verifications.rb +1 -1
  11. data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
  12. data/lib/pact_broker/certificates/certificate.rb +1 -1
  13. data/lib/pact_broker/config/setting.rb +1 -1
  14. data/lib/pact_broker/db/data_migrations/migrate_webhook_headers.rb +30 -0
  15. data/lib/pact_broker/domain/pacticipant.rb +1 -1
  16. data/lib/pact_broker/domain/verification.rb +1 -1
  17. data/lib/pact_broker/domain/version.rb +1 -1
  18. data/lib/pact_broker/domain/webhook.rb +27 -1
  19. data/lib/pact_broker/domain/webhook_request.rb +9 -146
  20. data/lib/pact_broker/integrations/integration.rb +7 -0
  21. data/lib/pact_broker/matrix/repository.rb +0 -1
  22. data/lib/pact_broker/matrix/row.rb +58 -17
  23. data/lib/pact_broker/pacts/pact_publication.rb +8 -1
  24. data/lib/pact_broker/pacts/pact_version.rb +1 -1
  25. data/lib/pact_broker/pacts/repository.rb +5 -8
  26. data/lib/pact_broker/repositories/helpers.rb +5 -4
  27. data/lib/pact_broker/test/test_data_builder.rb +2 -2
  28. data/lib/pact_broker/version.rb +1 -1
  29. data/lib/pact_broker/versions/latest_version.rb +10 -0
  30. data/lib/pact_broker/webhooks/execution.rb +1 -1
  31. data/lib/pact_broker/webhooks/http_request_with_redacted_headers.rb +21 -0
  32. data/lib/pact_broker/webhooks/http_response_with_utf_8_safe_body.rb +21 -0
  33. data/lib/pact_broker/webhooks/job.rb +2 -2
  34. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +86 -0
  35. data/lib/pact_broker/webhooks/render.rb +10 -71
  36. data/lib/pact_broker/webhooks/repository.rb +2 -9
  37. data/lib/pact_broker/webhooks/service.rb +5 -5
  38. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -1
  39. data/lib/pact_broker/webhooks/webhook.rb +9 -30
  40. data/lib/pact_broker/webhooks/webhook_event.rb +1 -1
  41. data/lib/pact_broker/{domain → webhooks}/webhook_execution_result.rb +6 -5
  42. data/lib/pact_broker/webhooks/webhook_request_logger.rb +105 -0
  43. data/lib/pact_broker/webhooks/webhook_request_template.rb +7 -6
  44. data/pact_broker.gemspec +1 -0
  45. data/script/docker/db-restore.sh +5 -0
  46. data/script/docker/db-rm.sh +3 -0
  47. data/script/docker/db-start.sh +7 -0
  48. data/script/import-pg-database.sh +5 -0
  49. data/script/seed.rb +1 -1
  50. data/spec/features/execute_webhook_spec.rb +1 -1
  51. data/spec/features/publish_verification_spec.rb +1 -1
  52. data/spec/integration/webhooks/certificate_spec.rb +4 -6
  53. data/spec/lib/pact_broker/api/decorators/webhook_execution_result_decorator_spec.rb +1 -1
  54. data/spec/lib/pact_broker/api/resources/verifications_spec.rb +1 -1
  55. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +1 -1
  56. data/spec/lib/pact_broker/db/data_migrations/migrate_webhook_headers_spec.rb +78 -0
  57. data/spec/lib/pact_broker/domain/webhook_request_spec.rb +8 -163
  58. data/spec/lib/pact_broker/domain/webhook_spec.rb +45 -8
  59. data/spec/lib/pact_broker/matrix/repository_spec.rb +24 -0
  60. data/spec/lib/pact_broker/pacticipants/find_potential_duplicate_pacticipant_names_spec.rb +4 -4
  61. data/spec/lib/pact_broker/pacts/pact_publication_spec.rb +60 -0
  62. data/spec/lib/pact_broker/webhooks/job_spec.rb +3 -3
  63. data/spec/lib/pact_broker/webhooks/render_spec.rb +22 -7
  64. data/spec/lib/pact_broker/webhooks/repository_spec.rb +24 -24
  65. data/spec/lib/pact_broker/webhooks/service_spec.rb +5 -5
  66. data/spec/lib/pact_broker/webhooks/webhook_request_logger_spec.rb +197 -0
  67. data/spec/lib/pact_broker/webhooks/webhook_request_template_spec.rb +13 -4
  68. data/spec/support/database.rb +1 -1
  69. data/spec/support/ssl_pact_broker_server.rb +46 -0
  70. data/tasks/database.rb +12 -0
  71. data/tasks/db.rake +26 -6
  72. data/tasks/docker_database.rb +25 -0
  73. metadata +35 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9cc025b711061dcb0c7ceecb89e57b5df8560667
4
- data.tar.gz: 87e712268e55f5325f1ea3c6a81dd370504b34f9
3
+ metadata.gz: 97134f270141a482c9af9641cffd34827002be42
4
+ data.tar.gz: '058cf5c4bdddd00ffd77b8a366cfdfbf539e40ff'
5
5
  SHA512:
6
- metadata.gz: bc84f0a9394bb378f64bcb04796a4f594c395f4a1f1018e55e2e64a1a97738346be25f5ecf1a6632ec4b0ce100fd36d3fb1167de90af0db62b4abb95ae258e21
7
- data.tar.gz: 2b135a336313e79f8f448f8ab466bf9d50c1f096d425c406edbda93a415bb62a28abbea616f64dad1af226650f1340a5d43ac6f263020c9c877c9ec04b945662
6
+ metadata.gz: cf993532a2a921c255d35c52918f5aba61f310109f2d0beaacac3abddd16b8a55bcd12b4f21b7ecbade8a9c7e2104dc3198a2efbb1d3cfa3ec45c738e5357385
7
+ data.tar.gz: d5544a81be59d19d52b906f8a3c320bc25620e9020c9bc7e4d02217c7d3c549719564fa226f2df3ddd15bb8bb0776f8208d502105d0e8088cac3f018beb43804
@@ -4,6 +4,9 @@ I have already (please mark the applicable with an `x`):
4
4
 
5
5
  * [ ] Upgraded to the latest Pact Broker OR
6
6
  * [ ] Checked the CHANGELOG to see if the issue I am about to raise has been fixed
7
+ * [ ] Created an executable example that demonstrates the issue using either a:
8
+ * Dockerfile
9
+ * Git repository with a Travis or Appveyor (or similar) build
7
10
 
8
11
  ## Software versions
9
12
 
@@ -1,3 +1,21 @@
1
+ <a name="v2.33.0"></a>
2
+ ### v2.33.0 (2019-06-07)
3
+
4
+
5
+ #### Features
6
+
7
+ * add pb:pacticipant and pb:pacticipant-version-tag relations to the index resource ([2c4c258c](/../../commit/2c4c258c))
8
+
9
+
10
+ #### Bug Fixes
11
+
12
+ * correctly remove webhook consumer/provider when update params do not contain a consumer/provider ([118bbee1](/../../commit/118bbee1))
13
+ * duplicate key value violates unique constraint "cv_prov_revision_unq" error when publishing identical pact resources at the same time ([6c8e38fb](/../../commit/6c8e38fb))
14
+
15
+ * **matrix**
16
+ * ensure unrelated dependencies are not included in a matrix result when three pacticipants each have dependencies on each other ([a086ffec](/../../commit/a086ffec))
17
+
18
+
1
19
  <a name="v2.32.0"></a>
2
20
  ### v2.32.0 (2019-05-28)
3
21
 
@@ -18,11 +18,6 @@ test:
18
18
  password: postgres
19
19
  host: "localhost"
20
20
  port: "5432"
21
- docker_compose_postgres:
22
- <<: *default
23
- adapter: postgres
24
- host: postgres
25
- port: "5432"
26
21
  mysql:
27
22
  <<: *default
28
23
  adapter: mysql2
@@ -35,10 +30,12 @@ development:
35
30
  <<: *default
36
31
  adapter: postgres
37
32
  docker_postgres:
38
- <<: *default
39
33
  adapter: postgres
40
- host: "127.0.0.1"
41
- port: "5433"
34
+ database: postgres
35
+ username: postgres
36
+ password: postgres
37
+ host: "localhost"
38
+ port: "5432"
42
39
  mysql:
43
40
  <<: *default
44
41
  adapter: mysql2
@@ -1,4 +1,5 @@
1
1
  require 'pact_broker/db/data_migrations/set_latest_version_sequence_value'
2
+
2
3
  Sequel.migration do
3
4
  up do
4
5
  PactBroker::DB::DataMigrations::SetLatestVersionSequenceValue.call(self)
@@ -0,0 +1,6 @@
1
+ Sequel.migration do
2
+ change do
3
+ # TODO delete webhook headers table
4
+ add_column(:webhooks, :headers, String)
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ require 'pact_broker/db/data_migrations/migrate_webhook_headers'
2
+
3
+ Sequel.migration do
4
+ up do
5
+ PactBroker::DB::DataMigrations::MigrateWebhookHeaders.call(self)
6
+ end
7
+
8
+ down do
9
+ end
10
+ end
@@ -50,6 +50,12 @@ module PactBroker
50
50
  title: 'Pacticipants',
51
51
  templated: false
52
52
  },
53
+ 'pb:pacticipant' =>
54
+ {
55
+ href: base_url + '/pacticipants/{pacticipant}',
56
+ title: 'Fetch pacticipant by name',
57
+ templated: true
58
+ },
53
59
  'pb:latest-provider-pacts' =>
54
60
  {
55
61
  href: base_url + '/pacts/provider/{provider}/latest',
@@ -94,6 +100,12 @@ module PactBroker
94
100
  title: 'Integrations',
95
101
  templated: false
96
102
  },
103
+ 'pb:pacticipant-version-tag' =>
104
+ {
105
+ href: base_url + '/pacticipants/{pacticipant}/versions/{version}/tags/{tag}',
106
+ title: "Get, create or delete a tag for a pacticipant version",
107
+ templated: true
108
+ },
97
109
  'beta:pending-provider-pacts' =>
98
110
  {
99
111
  href: base_url + '/pacts/provider/{provider}/pending',
@@ -122,7 +122,7 @@ module PactBroker
122
122
  def webhook_options
123
123
  {
124
124
  database_connector: database_connector,
125
- execution_options: {
125
+ logging_options: {
126
126
  show_response: PactBroker.configuration.show_webhook_response?
127
127
  },
128
128
  webhook_context: {
@@ -78,7 +78,7 @@ module PactBroker
78
78
  def webhook_options
79
79
  {
80
80
  database_connector: database_connector,
81
- execution_options: {
81
+ logging_options: {
82
82
  show_response: PactBroker.configuration.show_webhook_response?
83
83
  },
84
84
  webhook_context: metadata.merge(
@@ -47,7 +47,7 @@ module PactBroker
47
47
 
48
48
  def webhook_options
49
49
  {
50
- execution_options: {
50
+ logging_options: {
51
51
  show_response: PactBroker.configuration.show_webhook_response?
52
52
  },
53
53
  webhook_context: {
@@ -9,7 +9,7 @@ end
9
9
 
10
10
  # Table: certificates
11
11
  # Columns:
12
- # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
12
+ # id | integer | PRIMARY KEY DEFAULT nextval('certificates_id_seq'::regclass)
13
13
  # uuid | text | NOT NULL
14
14
  # description | text |
15
15
  # content | text | NOT NULL
@@ -69,7 +69,7 @@ end
69
69
 
70
70
  # Table: config
71
71
  # Columns:
72
- # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
72
+ # id | integer | PRIMARY KEY DEFAULT nextval('config_id_seq'::regclass)
73
73
  # name | text | NOT NULL
74
74
  # type | text | NOT NULL
75
75
  # value | text |
@@ -0,0 +1,30 @@
1
+ require 'pact_broker/db/data_migrations/helpers'
2
+
3
+ module PactBroker
4
+ module DB
5
+ module DataMigrations
6
+ class MigrateWebhookHeaders
7
+ extend Helpers
8
+
9
+ def self.call(connection)
10
+ if columns_exist?(connection)
11
+ connection[:webhook_headers].for_update.each do | webhook_header |
12
+ webhook = connection[:webhooks].for_update.where(id: webhook_header[:webhook_id]).first
13
+ new_headers = webhook[:headers] ? JSON.parse(webhook[:headers]) : {}
14
+ new_headers.merge!(webhook_header[:name] => webhook_header[:value])
15
+ connection[:webhooks].where(id: webhook[:id]).update(headers: new_headers.to_json)
16
+ connection[:webhook_headers].where(webhook_header).delete
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.columns_exist?(connection)
22
+ column_exists?(connection, :webhooks, :headers) &&
23
+ column_exists?(connection, :webhook_headers, :name) &&
24
+ column_exists?(connection, :webhook_headers, :value) &&
25
+ column_exists?(connection, :webhook_headers, :webhook_id)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -52,7 +52,7 @@ end
52
52
 
53
53
  # Table: pacticipants
54
54
  # Columns:
55
- # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
55
+ # id | integer | PRIMARY KEY DEFAULT nextval('pacticipants_id_seq'::regclass)
56
56
  # name | text |
57
57
  # repository_url | text |
58
58
  # created_at | timestamp without time zone | NOT NULL
@@ -95,7 +95,7 @@ end
95
95
 
96
96
  # Table: verifications
97
97
  # Columns:
98
- # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
98
+ # id | integer | PRIMARY KEY DEFAULT nextval('verifications_id_seq'::regclass)
99
99
  # number | integer |
100
100
  # success | boolean | NOT NULL
101
101
  # provider_version | text |
@@ -48,7 +48,7 @@ end
48
48
 
49
49
  # Table: versions
50
50
  # Columns:
51
- # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
51
+ # id | integer | PRIMARY KEY DEFAULT nextval('versions_id_seq'::regclass)
52
52
  # number | text |
53
53
  # repository_ref | text |
54
54
  # pacticipant_id | integer | NOT NULL
@@ -2,6 +2,7 @@ require 'pact_broker/domain/webhook_request'
2
2
  require 'pact_broker/messages'
3
3
  require 'pact_broker/logging'
4
4
  require 'pact_broker/api/contracts/webhook_contract'
5
+ require 'pact_broker/webhooks/http_request_with_redacted_headers'
5
6
 
6
7
  module PactBroker
7
8
  module Domain
@@ -10,6 +11,7 @@ module PactBroker
10
11
  include Messages
11
12
  include Logging
12
13
 
14
+ # request is actually a request_template
13
15
  attr_accessor :uuid, :consumer, :provider, :request, :created_at, :updated_at, :events, :enabled, :description
14
16
  attr_reader :attributes
15
17
 
@@ -52,7 +54,31 @@ module PactBroker
52
54
 
53
55
  def execute pact, verification, options
54
56
  logger.info "Executing #{self}"
55
- request.build(pact: pact, verification: verification, webhook_context: options.fetch(:webhook_context)).execute(options.fetch(:execution_options))
57
+ webhook_request = request.build(pact: pact, verification: verification, webhook_context: options.fetch(:webhook_context))
58
+ http_response = nil
59
+ error = nil
60
+ begin
61
+ http_response = webhook_request.execute
62
+ rescue StandardError => e
63
+ error = e
64
+ end
65
+
66
+ PactBroker::Webhooks::WebhookExecutionResult.new(
67
+ webhook_request.http_request,
68
+ http_response,
69
+ generate_logs(webhook_request, http_response, error, options.fetch(:logging_options)),
70
+ error
71
+ )
72
+ end
73
+
74
+ def generate_logs(webhook_request, http_response, error, logging_options)
75
+ webhook_request_logger = PactBroker::Webhooks::WebhookRequestLogger.new(logging_options)
76
+ webhook_request_logger.log(
77
+ uuid,
78
+ webhook_request,
79
+ http_response,
80
+ error
81
+ )
56
82
  end
57
83
 
58
84
  def to_s
@@ -1,61 +1,21 @@
1
1
  require 'pact_broker/build_http_options'
2
2
  require 'pact_broker/domain/webhook_request_header'
3
- require 'pact_broker/domain/webhook_execution_result'
3
+ require 'pact_broker/webhooks/webhook_execution_result'
4
4
  require 'pact_broker/logging'
5
5
  require 'pact_broker/messages'
6
6
  require 'net/http'
7
- require 'pact_broker/webhooks/render'
8
- require 'pact_broker/api/pact_broker_urls'
9
7
  require 'pact_broker/build_http_options'
10
8
  require 'cgi'
11
9
  require 'delegate'
12
10
  require 'rack/utils'
11
+ require 'pact_broker/webhooks/webhook_request_logger'
13
12
 
14
13
  module PactBroker
15
-
16
14
  module Domain
17
-
18
- class WebhookRequestError < StandardError
19
- def initialize message, response
20
- super message
21
- @response = response
22
- end
23
- end
24
-
25
- class WebhookResponseWithUtf8SafeBody < SimpleDelegator
26
- def body
27
- if unsafe_body
28
- unsafe_body.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
29
- else
30
- unsafe_body
31
- end
32
- end
33
-
34
- def unsafe_body
35
- __getobj__().body
36
- end
37
-
38
- def unsafe_body?
39
- unsafe_body != body
40
- end
41
- end
42
-
43
- class WebhookRequestWithRedactedHeaders < SimpleDelegator
44
- def to_hash
45
- __getobj__().to_hash.each_with_object({}) do | (key, values), new_hash |
46
- new_hash[key] = redact?(key) ? ["**********"] : values
47
- end
48
- end
49
-
50
- def redact? name
51
- WebhookRequest::HEADERS_TO_REDACT.any?{ | pattern | name =~ pattern }
52
- end
53
- end
54
-
55
15
  class WebhookRequest
56
16
 
57
17
  include PactBroker::Logging
58
- include PactBroker::Messages
18
+
59
19
  HEADERS_TO_REDACT = [/authorization/i, /token/i]
60
20
 
61
21
  attr_accessor :method, :url, :headers, :body, :username, :password, :uuid
@@ -89,36 +49,14 @@ module PactBroker
89
49
  end
90
50
  end
91
51
 
92
- def execute options = {}
93
- @options = options
94
- @logs = StringIO.new
95
- @execution_logger = Logger.new(logs)
96
- begin
97
- execute_and_build_result
98
- rescue StandardError => e
99
- handle_error_and_build_result(e)
52
+ def execute
53
+ options = PactBroker::BuildHttpOptions.call(uri)
54
+ req = http_request
55
+ Net::HTTP.start(uri.hostname, uri.port, :ENV, options) do |http|
56
+ http.request req
100
57
  end
101
58
  end
102
59
 
103
- private
104
-
105
- attr_reader :options, :execution_logger, :logs
106
-
107
- def execute_and_build_result
108
- log_request
109
- response = do_request
110
- log_response(response)
111
- result = WebhookExecutionResult.new(WebhookRequestWithRedactedHeaders.new(http_request), response, logs.string)
112
- log_completion_message(result.success?)
113
- result
114
- end
115
-
116
- def handle_error_and_build_result e
117
- log_error(e)
118
- log_completion_message(false)
119
- WebhookExecutionResult.new(WebhookRequestWithRedactedHeaders.new(http_request), nil, logs.string, e)
120
- end
121
-
122
60
  def http_request
123
61
  @http_request ||= begin
124
62
  req = Net::HTTP.const_get(method.capitalize).new(url)
@@ -129,82 +67,7 @@ module PactBroker
129
67
  end
130
68
  end
131
69
 
132
- def do_request
133
- options = PactBroker::BuildHttpOptions.call(uri)
134
- req = http_request
135
- response = Net::HTTP.start(uri.hostname, uri.port, :ENV, options) do |http|
136
- http.request req
137
- end
138
- WebhookResponseWithUtf8SafeBody.new(response)
139
- end
140
-
141
- def log_request
142
- redacted_request = WebhookRequestWithRedactedHeaders.new(http_request)
143
- logger.info "Making webhook #{uuid} request #{http_method.upcase} URI=#{uri} (headers and body in debug logs)"
144
- logger.debug "Webhook #{uuid} request headers=#{redacted_request.to_hash}"
145
- logger.debug "Webhook #{uuid} request body=#{redacted_request.body}"
146
-
147
- execution_logger.info "HTTP/1.1 #{http_method.upcase} #{url}"
148
- redacted_request.to_hash.each do | name, value |
149
- execution_logger.info "#{name}: #{value.join(", ")}"
150
- end
151
- execution_logger.info(body) if body
152
- end
153
-
154
- def log_response response
155
- log_response_to_application_logger(response)
156
- if options.fetch(:show_response)
157
- log_response_to_execution_logger(response)
158
- else
159
- execution_logger.info response_body_hidden_message
160
- end
161
- end
162
-
163
- def response_body_hidden_message
164
- PactBroker::Messages.message('messages.response_body_hidden')
165
- end
166
-
167
- def log_response_to_application_logger response
168
- logger.info "Received response for webhook #{uuid} status=#{response.code} (headers and body in debug logs)"
169
- logger.debug "Webhook #{uuid} response headers=#{response.to_hash} "
170
- logger.debug "Webhook #{uuid} response body=#{response.unsafe_body}"
171
- end
172
-
173
- def log_response_to_execution_logger response
174
- execution_logger.info "HTTP/#{response.http_version} #{response.code} #{response.message}"
175
- response.each_header do | name, value |
176
- execution_logger.info "#{name}: #{value}"
177
- end
178
-
179
- if response.body
180
- if response.unsafe_body?
181
- execution_logger.debug "Note that invalid UTF-8 byte sequences were removed from response body before saving the logs"
182
- end
183
- execution_logger.info response.body
184
- end
185
- end
186
-
187
- def log_completion_message success
188
- if options[:success_log_message] && success
189
- execution_logger.info(options[:success_log_message])
190
- logger.info(options[:success_log_message])
191
- end
192
-
193
- if options[:failure_log_message] && !success
194
- execution_logger.info(options[:failure_log_message])
195
- logger.info(options[:failure_log_message])
196
- end
197
- end
198
-
199
- def log_error e
200
- logger.info "Error executing webhook #{uuid} #{e.class.name} - #{e.message} #{e.backtrace.join("\n")}"
201
-
202
- if options[:show_response]
203
- execution_logger.error "Error executing webhook #{uuid} #{e.class.name} - #{e.message}"
204
- else
205
- execution_logger.error "Error executing webhook #{uuid}. #{response_body_hidden_message}"
206
- end
207
- end
70
+ private
208
71
 
209
72
  def to_s
210
73
  "#{method.upcase} #{url}, username=#{username}, password=#{display_password}, headers=#{redacted_headers}, body=#{body}"