pact_broker 2.108.0 → 2.109.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 +13 -0
- data/Gemfile +0 -2
- data/lib/pact_broker/api/decorators/publish_contract_decorator.rb +6 -1
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +1 -1
- data/lib/pact_broker/api/resources/environment.rb +4 -0
- data/lib/pact_broker/api/resources/pact.rb +7 -3
- data/lib/pact_broker/api/resources/publish_contracts.rb +1 -1
- data/lib/pact_broker/app.rb +0 -5
- data/lib/pact_broker/contracts/contract_to_publish.rb +4 -5
- data/lib/pact_broker/contracts/service.rb +2 -2
- data/lib/pact_broker/logging.rb +10 -0
- data/lib/pact_broker/pacts/generate_sha.rb +9 -4
- data/lib/pact_broker/pacts/pact_params.rb +1 -1
- data/lib/pact_broker/pacts/service.rb +11 -12
- data/lib/pact_broker/test/test_data_builder.rb +7 -1
- data/lib/pact_broker/ui/controllers/base_controller.rb +4 -2
- data/lib/pact_broker/ui.rb +20 -9
- data/lib/pact_broker/version.rb +1 -1
- data/pact_broker.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a915f7f2cb962cfc2d315338305f170cc875746ce0567826b54a8245dc06afa9
|
4
|
+
data.tar.gz: 3f2db5d2e4c1a5ece6b6b5fef712f3bbcaf85eae49856b9309632ff525d23173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4cc5845f6611967e5a33865b05da2a214d8fa2d28762943ea4f112bab8a02163830acde551342486cb2b03690564b8a33eb3e5242afd93bc5e70249c1416ca56
|
7
|
+
data.tar.gz: 12f531f2a74c399bc48a26b7afb82e68453b35764c3f5aca5434a1fc55c9f377590508ea6ee41840547652ce240cce2dc4d244d88e4fc2b4074b8c8a8f441dfb
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
<a name="v2.109.0"></a>
|
2
|
+
### v2.109.0 (2024-02-01)
|
3
|
+
|
4
|
+
#### Features
|
5
|
+
|
6
|
+
* use SemanticLogger for Padrino (#662) ([5d9d7002](/../../commit/5d9d7002))
|
7
|
+
* improve performance of publication for very large pacts by calculating the content SHA only once per request ([a947e409](/../../commit/a947e409))
|
8
|
+
|
9
|
+
#### Bug Fixes
|
10
|
+
|
11
|
+
* pass in environment to environment policy when getting an individual environment ([5c386a43](/../../commit/5c386a43))
|
12
|
+
* Dockerfile to reduce vulnerabilities (#650) ([9aaa3484](/../../commit/9aaa3484))
|
13
|
+
|
1
14
|
<a name="v2.108.0"></a>
|
2
15
|
### v2.108.0 (2024-01-05)
|
3
16
|
|
data/Gemfile
CHANGED
@@ -2,8 +2,6 @@ source "https://rubygems.org"
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
# While https://github.com/brandonhilkert/sucker_punch/pull/253 is outstanding
|
6
|
-
gem "sucker_punch", git: "https://github.com/pact-foundation/sucker_punch.git", ref: "fix/rename-is-singleton-class-method-2"
|
7
5
|
|
8
6
|
gem "rake", "~>12.3.3"
|
9
7
|
gem "sqlite3", "~>1.3"
|
@@ -11,8 +11,13 @@ module PactBroker
|
|
11
11
|
property :provider_name
|
12
12
|
property :specification
|
13
13
|
property :content_type
|
14
|
-
property :decoded_content
|
14
|
+
property :decoded_content, setter: -> (fragment:, represented:, user_options:, **) {
|
15
|
+
represented.decoded_content = fragment
|
16
|
+
# Set the pact version sha when we set the content
|
17
|
+
represented.pact_version_sha = user_options.fetch(:sha_generator).call(fragment)
|
18
|
+
}
|
15
19
|
property :on_conflict, default: "overwrite"
|
20
|
+
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
@@ -71,9 +71,9 @@ module PactBroker
|
|
71
71
|
subscribe(PactBroker::Integrations::EventListener.new) do
|
72
72
|
handle_webhook_events do
|
73
73
|
if request.patch? && resource_exists?
|
74
|
-
@pact = pact_service.merge_pact(pact_params)
|
74
|
+
@pact = pact_service.merge_pact(pact_params.merge(pact_version_sha: pact_version_sha))
|
75
75
|
else
|
76
|
-
@pact = pact_service.create_or_update_pact(pact_params)
|
76
|
+
@pact = pact_service.create_or_update_pact(pact_params.merge(pact_version_sha: pact_version_sha))
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -114,7 +114,7 @@ module PactBroker
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def disallowed_modification?
|
117
|
-
if request.really_put? && pact_service.disallowed_modification?(pact,
|
117
|
+
if request.really_put? && pact_service.disallowed_modification?(pact, pact_version_sha)
|
118
118
|
message_params = { consumer_name: pact_params.consumer_name, consumer_version_number: pact_params.consumer_version_number, provider_name: pact_params.provider_name }
|
119
119
|
set_json_error_message(message("errors.validation.pact_content_modification_not_allowed", message_params))
|
120
120
|
true
|
@@ -126,6 +126,10 @@ module PactBroker
|
|
126
126
|
def schema
|
127
127
|
api_contract_class(:put_pact_params_contract)
|
128
128
|
end
|
129
|
+
|
130
|
+
def pact_version_sha
|
131
|
+
@pact_version_sha ||= pact_service.generate_sha(pact_params.json_content)
|
132
|
+
end
|
129
133
|
end
|
130
134
|
end
|
131
135
|
end
|
@@ -53,7 +53,7 @@ module PactBroker
|
|
53
53
|
private
|
54
54
|
|
55
55
|
def parsed_contracts
|
56
|
-
@parsed_contracts ||= decorator_class(:publish_contracts_decorator).new(PactBroker::Contracts::ContractsToPublish.new).from_hash(params)
|
56
|
+
@parsed_contracts ||= decorator_class(:publish_contracts_decorator).new(PactBroker::Contracts::ContractsToPublish.new).from_hash(params, { user_options: { sha_generator: PactBroker.configuration.sha_generator } } )
|
57
57
|
end
|
58
58
|
|
59
59
|
def params
|
data/lib/pact_broker/app.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
# Must be defined before loading Padrino
|
2
|
-
PADRINO_LOGGER ||= {
|
3
|
-
ENV.fetch("RACK_ENV", "production").to_sym => { log_level: :error, stream: :stdout, format_datetime: "%Y-%m-%dT%H:%M:%S.000%:z" }
|
4
|
-
}
|
5
|
-
|
6
1
|
require "pact_broker/configuration"
|
7
2
|
require "pact_broker/db"
|
8
3
|
require "pact_broker/initializers/database_connection"
|
@@ -1,11 +1,10 @@
|
|
1
1
|
module PactBroker
|
2
2
|
module Contracts
|
3
|
-
ContractToPublish = Struct.new(:consumer_name, :provider_name, :decoded_content, :content_type, :specification, :on_conflict) do
|
4
|
-
|
5
|
-
def self.from_hash(
|
6
|
-
new(
|
3
|
+
ContractToPublish = Struct.new(:consumer_name, :provider_name, :decoded_content, :content_type, :specification, :on_conflict, :pact_version_sha, keyword_init: true) do
|
4
|
+
|
5
|
+
def self.from_hash(hash)
|
6
|
+
new(**hash)
|
7
7
|
end
|
8
|
-
# rubocop: enable Metrics/ParameterLists
|
9
8
|
|
10
9
|
def pact?
|
11
10
|
specification == "pact"
|
@@ -57,7 +57,7 @@ module PactBroker
|
|
57
57
|
parsed_contracts.contracts.collect do | contract_to_publish |
|
58
58
|
pact_params = create_pact_params(parsed_contracts, contract_to_publish)
|
59
59
|
existing_pact = pact_service.find_pact(pact_params)
|
60
|
-
if existing_pact && pact_service.disallowed_modification?(existing_pact, contract_to_publish.
|
60
|
+
if existing_pact && pact_service.disallowed_modification?(existing_pact, contract_to_publish.pact_version_sha)
|
61
61
|
add_pact_conflict_notice(notices, parsed_contracts, contract_to_publish, existing_pact.json_content, contract_to_publish.decoded_content)
|
62
62
|
end
|
63
63
|
end
|
@@ -134,7 +134,7 @@ module PactBroker
|
|
134
134
|
pact_params = create_pact_params(parsed_contracts, contract_to_publish)
|
135
135
|
existing_pact = pact_service.find_pact(pact_params)
|
136
136
|
listener = TriggeredWebhooksCreatedListener.new
|
137
|
-
created_pact = create_or_merge_pact(contract_to_publish.merge?, existing_pact, pact_params, listener)
|
137
|
+
created_pact = create_or_merge_pact(contract_to_publish.merge?, existing_pact, pact_params.merge(pact_version_sha: contract_to_publish.pact_version_sha), listener)
|
138
138
|
notices.concat(notices_for_pact(parsed_contracts, contract_to_publish, existing_pact, created_pact, listener, base_url))
|
139
139
|
created_pact
|
140
140
|
end
|
data/lib/pact_broker/logging.rb
CHANGED
@@ -42,6 +42,16 @@ module PactBroker
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
def measure_info(message, payload: {})
|
46
|
+
if logger.respond_to?(:measure_info)
|
47
|
+
logger.measure_info(message, payload: payload) do
|
48
|
+
yield
|
49
|
+
end
|
50
|
+
else
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
45
55
|
def log_error e, description = nil
|
46
56
|
if logger.instance_of?(SemanticLogger::Logger)
|
47
57
|
if description
|
@@ -3,22 +3,27 @@ require "pact_broker/configuration"
|
|
3
3
|
require "pact_broker/pacts/sort_content"
|
4
4
|
require "pact_broker/pacts/parse"
|
5
5
|
require "pact_broker/pacts/content"
|
6
|
+
require "pact_broker/logging"
|
6
7
|
|
7
8
|
module PactBroker
|
8
9
|
module Pacts
|
9
10
|
class GenerateSha
|
11
|
+
include PactBroker::Logging
|
12
|
+
|
10
13
|
# @param [String] json_content
|
11
|
-
def self.call
|
14
|
+
def self.call(json_content, _options = {})
|
12
15
|
content_for_sha = if PactBroker.configuration.base_equality_only_on_content_that_affects_verification_results
|
13
16
|
extract_verifiable_content_for_sha(json_content)
|
14
17
|
else
|
15
18
|
json_content
|
16
19
|
end
|
17
|
-
Digest::SHA1.hexdigest(content_for_sha)
|
20
|
+
measure_info("Generating SHA1 hexdigest for pact", payload: { length: content_for_sha.length } ){ Digest::SHA1.hexdigest(content_for_sha) }
|
18
21
|
end
|
19
22
|
|
20
|
-
def self.extract_verifiable_content_for_sha
|
21
|
-
Content.from_json(json_content)
|
23
|
+
def self.extract_verifiable_content_for_sha(json_content)
|
24
|
+
objects = Content.from_json(json_content)
|
25
|
+
sorted_content = measure_info("Sorting content", payload: { length: json_content.length }){ objects.sort }
|
26
|
+
sorted_content.content_that_affects_verification_results.to_json
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
@@ -22,6 +22,10 @@ module PactBroker
|
|
22
22
|
extend PactBroker::Messages
|
23
23
|
extend SquashPactsForVerification
|
24
24
|
|
25
|
+
def generate_sha(json_content)
|
26
|
+
PactBroker.configuration.sha_generator.call(json_content)
|
27
|
+
end
|
28
|
+
|
25
29
|
def find_latest_pact params
|
26
30
|
pact_repository.find_latest_pact(params[:consumer_name], params[:provider_name], params[:tag], params[:branch_name])
|
27
31
|
end
|
@@ -154,10 +158,12 @@ module PactBroker
|
|
154
158
|
end
|
155
159
|
|
156
160
|
# Overwriting an existing pact with the same consumer/provider/consumer version number
|
161
|
+
# by creating a new revision (that is, a new PactPublication with an incremented revision number)
|
162
|
+
# Modifing pacts is strongly discouraged now, and support for it will be dropped in the next major version of the Pact Broker
|
157
163
|
def create_pact_revision params, existing_pact
|
158
164
|
logger.info("Updating existing pact publication", params.without(:json_content))
|
159
165
|
logger.debug("Content #{params[:json_content]}")
|
160
|
-
pact_version_sha =
|
166
|
+
pact_version_sha = params.fetch(:pact_version_sha)
|
161
167
|
json_content = add_interaction_ids(params[:json_content])
|
162
168
|
update_params = { pact_version_sha: pact_version_sha, json_content: json_content }
|
163
169
|
updated_pact = pact_repository.update(existing_pact.id, update_params)
|
@@ -178,21 +184,20 @@ module PactBroker
|
|
178
184
|
|
179
185
|
private :create_pact_revision
|
180
186
|
|
181
|
-
def disallowed_modification?(existing_pact,
|
182
|
-
!PactBroker.configuration.allow_dangerous_contract_modification && existing_pact && existing_pact.pact_version_sha !=
|
187
|
+
def disallowed_modification?(existing_pact, new_pact_version_sha)
|
188
|
+
!PactBroker.configuration.allow_dangerous_contract_modification && existing_pact && existing_pact.pact_version_sha != new_pact_version_sha
|
183
189
|
end
|
184
190
|
|
185
191
|
# When no publication for the given consumer/provider/consumer version number exists
|
186
|
-
def create_pact
|
192
|
+
def create_pact(params, version, provider)
|
187
193
|
logger.info("Creating new pact publication", params.without(:json_content))
|
188
194
|
logger.debug("Content #{params[:json_content]}")
|
189
|
-
pact_version_sha = generate_sha(params[:json_content])
|
190
195
|
json_content = add_interaction_ids(params[:json_content])
|
191
196
|
pact = pact_repository.create(
|
192
197
|
version_id: version.id,
|
193
198
|
provider_id: provider.id,
|
194
199
|
consumer_id: version.pacticipant_id,
|
195
|
-
pact_version_sha: pact_version_sha,
|
200
|
+
pact_version_sha: params.fetch(:pact_version_sha),
|
196
201
|
json_content: json_content,
|
197
202
|
version: version
|
198
203
|
)
|
@@ -212,12 +217,6 @@ module PactBroker
|
|
212
217
|
|
213
218
|
private :create_pact
|
214
219
|
|
215
|
-
def generate_sha(json_content)
|
216
|
-
PactBroker.configuration.sha_generator.call(json_content)
|
217
|
-
end
|
218
|
-
|
219
|
-
private :generate_sha
|
220
|
-
|
221
220
|
def add_interaction_ids(json_content)
|
222
221
|
Content.from_json(json_content).with_ids.to_json
|
223
222
|
end
|
@@ -256,7 +256,13 @@ module PactBroker
|
|
256
256
|
def publish_pact(consumer_name:, provider_name:, consumer_version_number: , tags: nil, branch: nil, build_url: nil, json_content: nil)
|
257
257
|
json_content = json_content || random_json_content(consumer_name, provider_name)
|
258
258
|
contracts = [
|
259
|
-
PactBroker::Contracts::ContractToPublish.from_hash(
|
259
|
+
PactBroker::Contracts::ContractToPublish.from_hash(
|
260
|
+
consumer_name: consumer_name,
|
261
|
+
provider_name: provider_name,
|
262
|
+
decoded_content: json_content,
|
263
|
+
content_type: "application/json",
|
264
|
+
specification: "pact",
|
265
|
+
pact_version_sha: PactBroker::Pacts::GenerateSha.call(json_content))
|
260
266
|
]
|
261
267
|
contracts_to_publish = PactBroker::Contracts::ContractsToPublish.from_hash(
|
262
268
|
pacticipant_name: consumer_name,
|
@@ -10,8 +10,10 @@ module PactBroker
|
|
10
10
|
using PactBroker::StringRefinements
|
11
11
|
|
12
12
|
set :root, File.join(File.dirname(__FILE__), "..")
|
13
|
-
set :show_exceptions, ENV["RACK_ENV"]
|
14
|
-
|
13
|
+
set :show_exceptions, ENV["RACK_ENV"] == "development"
|
14
|
+
# The padrino logger logs these for us, but only in production. If this is enabled we get duplicate logging.
|
15
|
+
set :dump_errors, ENV["RACK_ENV"] != "production"
|
16
|
+
set :raise_errors, ENV["RACK_ENV"] == "test"
|
15
17
|
|
16
18
|
def base_url
|
17
19
|
# Using the X-Forwarded headers in the UI can leave the app vulnerable
|
data/lib/pact_broker/ui.rb
CHANGED
@@ -1,14 +1,25 @@
|
|
1
|
-
|
1
|
+
# Must be defined before loading Padrino
|
2
2
|
# Stop Padrino creating a log file, as it will try to create it in the gems directory
|
3
3
|
# http://www.padrinorb.com/api/Padrino/Logger.html
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
# This configuration will be replaced by the SemanticLogger later on.
|
5
|
+
PADRINO_LOGGER ||= {
|
6
|
+
ENV.fetch("RACK_ENV", "production").to_sym => { stream: :stdout }
|
7
|
+
}
|
8
|
+
|
9
|
+
require "padrino-core"
|
10
|
+
|
11
|
+
class PactBrokerPadrinoLogger < SemanticLogger::Logger
|
12
|
+
include Padrino::Logger::Extensions
|
13
|
+
|
14
|
+
# Padrino expects level to return an integer, not a symbol
|
15
|
+
def level
|
16
|
+
Padrino::Logger::Levels[SemanticLogger.default_level]
|
17
|
+
end
|
12
18
|
end
|
13
19
|
|
20
|
+
Padrino.logger = PactBrokerPadrinoLogger.new("Padrino")
|
21
|
+
# Log a test message to ensure that the logger works properly, as it only
|
22
|
+
# seems to be used in production.
|
23
|
+
Padrino.logger.info("Padrino has been configured with SemanticLogger")
|
24
|
+
|
14
25
|
require "pact_broker/ui/app"
|
data/lib/pact_broker/version.rb
CHANGED
data/pact_broker.gemspec
CHANGED
@@ -64,7 +64,7 @@ Gem::Specification.new do |gem|
|
|
64
64
|
gem.add_runtime_dependency "padrino-core", ">= 0.14.3", "~> 0.14"
|
65
65
|
gem.add_runtime_dependency "sinatra", "~> 3.0"
|
66
66
|
gem.add_runtime_dependency "haml", "~>5.0"
|
67
|
-
gem.add_runtime_dependency "sucker_punch", "~>
|
67
|
+
gem.add_runtime_dependency "sucker_punch", "~>3.0"
|
68
68
|
gem.add_runtime_dependency "rack-protection", "~> 3.0"
|
69
69
|
gem.add_runtime_dependency "table_print", "~> 1.5"
|
70
70
|
gem.add_runtime_dependency "semantic_logger", "~> 4.11"
|
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.
|
4
|
+
version: 2.109.0
|
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: 2024-
|
13
|
+
date: 2024-02-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -258,14 +258,14 @@ dependencies:
|
|
258
258
|
requirements:
|
259
259
|
- - "~>"
|
260
260
|
- !ruby/object:Gem::Version
|
261
|
-
version: '
|
261
|
+
version: '3.0'
|
262
262
|
type: :runtime
|
263
263
|
prerelease: false
|
264
264
|
version_requirements: !ruby/object:Gem::Requirement
|
265
265
|
requirements:
|
266
266
|
- - "~>"
|
267
267
|
- !ruby/object:Gem::Version
|
268
|
-
version: '
|
268
|
+
version: '3.0'
|
269
269
|
- !ruby/object:Gem::Dependency
|
270
270
|
name: rack-protection
|
271
271
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1260,7 +1260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1260
1260
|
- !ruby/object:Gem::Version
|
1261
1261
|
version: '0'
|
1262
1262
|
requirements: []
|
1263
|
-
rubygems_version: 3.5.
|
1263
|
+
rubygems_version: 3.5.5
|
1264
1264
|
signing_key:
|
1265
1265
|
specification_version: 4
|
1266
1266
|
summary: See description
|