pact_broker 2.106.0 → 2.107.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/Gemfile +3 -0
- data/db/migrations/20230131_add_cons_ver_id_ndx_to_latest_pp_id_for_cons_ver.rb +8 -4
- data/db/migrations/20230216_add_branch_heads_branch_version_id_index.rb +21 -0
- data/db/migrations/20230428_add_index_for_webhook_executions_pact_publication_id.rb +17 -0
- data/lib/pact_broker/api/contracts/base_contract.rb +22 -7
- data/lib/pact_broker/api/contracts/can_i_deploy_query_schema.rb +34 -0
- data/lib/pact_broker/api/contracts/configuration.rb +2 -0
- data/lib/pact_broker/api/contracts/consumer_version_selector_contract.rb +140 -0
- data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +50 -0
- data/lib/pact_broker/api/contracts/dry_validation_macros.rb +79 -0
- data/lib/pact_broker/api/contracts/dry_validation_methods.rb +71 -0
- data/lib/pact_broker/api/contracts/environment_schema.rb +19 -33
- data/lib/pact_broker/api/contracts/pacticipant_create_schema.rb +4 -17
- data/lib/pact_broker/api/contracts/pacticipant_schema.rb +15 -24
- data/lib/pact_broker/api/contracts/pacts_for_verification_json_query_schema.rb +37 -146
- data/lib/pact_broker/api/contracts/pacts_for_verification_query_string_schema.rb +7 -20
- data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +62 -0
- data/lib/pact_broker/api/contracts/publish_contracts_schema.rb +25 -124
- data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +21 -26
- data/lib/pact_broker/api/contracts/utf_8_validation.rb +2 -0
- data/lib/pact_broker/api/contracts/validation_helpers.rb +71 -0
- data/lib/pact_broker/api/contracts/verification_contract.rb +10 -29
- data/lib/pact_broker/api/contracts/webhook_contract.rb +20 -172
- data/lib/pact_broker/api/contracts/webhook_pacticipant_contract.rb +33 -0
- data/lib/pact_broker/api/contracts/webhook_request_contract.rb +125 -0
- data/lib/pact_broker/api/contracts.rb +3 -0
- data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +4 -4
- data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/matrix_decorator.rb +4 -4
- data/lib/pact_broker/api/decorators/matrix_text_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/pact_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/pacticipant_collection_decorator.rb +2 -2
- data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +2 -1
- data/lib/pact_broker/api/decorators/pacts_for_verification_query_decorator.rb +4 -1
- data/lib/pact_broker/api/decorators/pagination_links.rb +6 -6
- data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +4 -4
- data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +6 -6
- data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -4
- data/lib/pact_broker/api/decorators/webhook_decorator.rb +2 -3
- data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +5 -12
- data/lib/pact_broker/api/resources/all_webhooks.rb +5 -11
- data/lib/pact_broker/api/resources/base_resource.rb +3 -20
- data/lib/pact_broker/api/resources/branch_version.rb +3 -3
- data/lib/pact_broker/api/resources/can_i_deploy.rb +4 -19
- data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb +1 -4
- data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag.rb +0 -2
- data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag_badge.rb +1 -2
- data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +2 -2
- data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +2 -2
- data/lib/pact_broker/api/resources/dashboard.rb +3 -3
- data/lib/pact_broker/api/resources/deployed_version.rb +1 -1
- data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +2 -2
- data/lib/pact_broker/api/resources/environment.rb +1 -1
- data/lib/pact_broker/api/resources/environments.rb +2 -2
- data/lib/pact_broker/api/resources/error_handling_methods.rb +2 -2
- data/lib/pact_broker/api/resources/integrations.rb +1 -1
- data/lib/pact_broker/api/resources/label.rb +1 -1
- data/lib/pact_broker/api/resources/latest_pact.rb +2 -2
- data/lib/pact_broker/api/resources/latest_pacts.rb +1 -1
- data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +1 -1
- data/lib/pact_broker/api/resources/matrix.rb +2 -2
- data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
- data/lib/pact_broker/api/resources/pact.rb +7 -4
- data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -1
- data/lib/pact_broker/api/resources/pact_versions.rb +1 -1
- data/lib/pact_broker/api/resources/pact_webhooks.rb +7 -14
- data/lib/pact_broker/api/resources/pact_webhooks_status.rb +6 -2
- data/lib/pact_broker/api/resources/pacticipant.rb +1 -1
- data/lib/pact_broker/api/resources/pacticipant_webhooks.rb +7 -5
- data/lib/pact_broker/api/resources/pacticipants.rb +2 -2
- data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
- data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +1 -1
- data/lib/pact_broker/api/resources/provider_pacts.rb +1 -1
- data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +4 -13
- data/lib/pact_broker/api/resources/publish_contracts.rb +8 -3
- data/lib/pact_broker/api/resources/released_version.rb +1 -1
- data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +2 -2
- data/lib/pact_broker/api/resources/tag.rb +1 -1
- data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -1
- data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +2 -2
- data/lib/pact_broker/api/resources/verification.rb +2 -2
- data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +1 -1
- data/lib/pact_broker/api/resources/verifications.rb +4 -6
- data/lib/pact_broker/api/resources/version.rb +1 -1
- data/lib/pact_broker/api/resources/versions.rb +1 -1
- data/lib/pact_broker/api/resources/webhook.rb +7 -6
- data/lib/pact_broker/api/resources/webhook_execution.rb +6 -4
- data/lib/pact_broker/api.rb +3 -12
- data/lib/pact_broker/certificates/certificate.rb +1 -0
- data/lib/pact_broker/config/setting.rb +1 -0
- data/lib/pact_broker/contracts/service.rb +1 -0
- data/lib/pact_broker/date_helper.rb +1 -1
- data/lib/pact_broker/db/clean_incremental.rb +1 -1
- data/lib/pact_broker/db/delete_overwritten_data.rb +6 -2
- data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -0
- data/lib/pact_broker/deployments/deployed_version.rb +2 -0
- data/lib/pact_broker/deployments/deployed_version_service.rb +5 -1
- data/lib/pact_broker/deployments/environment.rb +2 -0
- data/lib/pact_broker/deployments/environment_service.rb +4 -3
- data/lib/pact_broker/deployments/released_version.rb +2 -0
- data/lib/pact_broker/deployments/released_version_service.rb +4 -0
- data/lib/pact_broker/diagnostic/resources/base_resource.rb +1 -1
- data/lib/pact_broker/doc/views/index/publish-contracts.markdown +5 -5
- data/lib/pact_broker/domain/label.rb +1 -0
- data/lib/pact_broker/domain/tag.rb +2 -0
- data/lib/pact_broker/domain/verification.rb +1 -1
- data/lib/pact_broker/domain/version.rb +4 -1
- data/lib/pact_broker/domain/webhook.rb +1 -1
- data/lib/pact_broker/index/service.rb +1 -1
- data/lib/pact_broker/integrations/integration.rb +1 -0
- data/lib/pact_broker/locale/en.yml +35 -14
- data/lib/pact_broker/matrix/query_ids.rb +4 -4
- data/lib/pact_broker/matrix/resolved_selector.rb +6 -1
- data/lib/pact_broker/matrix/service.rb +1 -0
- data/lib/pact_broker/messages.rb +5 -1
- data/lib/pact_broker/pacticipants/repository.rb +12 -3
- data/lib/pact_broker/pacticipants/service.rb +7 -0
- data/lib/pact_broker/pacts/pact_params.rb +6 -17
- data/lib/pact_broker/pacts/pact_version.rb +1 -0
- data/lib/pact_broker/policies.rb +4 -4
- data/lib/pact_broker/test/http_test_data_builder.rb +46 -2
- data/lib/pact_broker/ui/app.rb +2 -2
- data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +1 -1
- data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +1 -0
- data/lib/pact_broker/verifications/service.rb +0 -6
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/branch.rb +1 -0
- data/lib/pact_broker/versions/branch_head.rb +2 -1
- data/lib/pact_broker/versions/branch_version.rb +11 -0
- data/lib/pact_broker/webhooks/execution.rb +1 -1
- data/lib/pact_broker/webhooks/repository.rb +1 -1
- data/lib/pact_broker/webhooks/service.rb +3 -25
- data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
- data/lib/pact_broker/webhooks/webhook_event.rb +1 -0
- data/lib/pact_broker/webmachine.rb +22 -0
- data/lib/rack/pact_broker/invalid_uri_protection.rb +1 -1
- data/lib/rack/pact_broker/use_when.rb +6 -5
- data/lib/sequel/plugins/age.rb +13 -0
- data/lib/webmachine/application_monkey_patch.rb +5 -0
- data/lib/webmachine/describe_routes.rb +35 -8
- data/lib/webmachine/render_error_monkey_patch.rb +1 -1
- data/pact_broker.gemspec +6 -17
- metadata +56 -72
- data/lib/pact/doc/README.md +0 -5
- data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +0 -36
- data/lib/pact_broker/api/contracts/dry_validation_workarounds.rb +0 -39
- data/lib/pact_broker/api/contracts/pacticipant_name_contract.rb +0 -24
- data/lib/pact_broker/api/contracts/pacticipant_name_validation.rb +0 -30
- data/lib/pact_broker/api/contracts/request_validations.rb +0 -33
- data/lib/pact_broker/api/resources/webhook_resource_methods.rb +0 -17
- data/lib/pact_broker/matrix/can_i_deploy_query_schema.rb +0 -46
@@ -1,41 +1,22 @@
|
|
1
1
|
require "pact_broker/api/contracts/base_contract"
|
2
|
-
require "uri"
|
3
2
|
|
4
3
|
module PactBroker
|
5
4
|
module Api
|
6
5
|
module Contracts
|
7
6
|
class VerificationContract < BaseContract
|
7
|
+
json do
|
8
|
+
required(:success).filled(:bool)
|
9
|
+
required(:providerApplicationVersion).filled(:string)
|
10
|
+
optional(:buildUrl).maybe(:string)
|
11
|
+
end
|
8
12
|
|
9
|
-
|
10
|
-
property :provider_version, as: :providerApplicationVersion
|
11
|
-
property :build_url, as: :buildUrl
|
12
|
-
|
13
|
-
validation do
|
14
|
-
configure do
|
15
|
-
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
16
|
-
|
17
|
-
def not_blank? value
|
18
|
-
value && value.to_s.strip.size > 0
|
19
|
-
end
|
20
|
-
|
21
|
-
def valid_url? url
|
22
|
-
URI(url)
|
23
|
-
rescue URI::InvalidURIError, ArgumentError
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
def valid_version_number?(value)
|
28
|
-
return true if PactBroker.configuration.order_versions_by_date
|
29
|
-
|
30
|
-
parsed_version_number = PactBroker.configuration.version_parser.call(value)
|
31
|
-
!!parsed_version_number
|
32
|
-
end
|
33
|
-
end
|
13
|
+
rule(:providerApplicationVersion).validate(:not_blank_if_present)
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
optional(:build_url).maybe(:valid_url?)
|
15
|
+
rule(:providerApplicationVersion) do
|
16
|
+
validate_version_number(value, key) unless rule_error?(:providerApplicationVersion)
|
38
17
|
end
|
18
|
+
|
19
|
+
rule(:buildUrl).validate(:valid_url_if_present)
|
39
20
|
end
|
40
21
|
end
|
41
22
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require "pact_broker/api/contracts/base_contract"
|
2
|
-
require "pact_broker/
|
3
|
-
require "pact_broker/
|
4
|
-
require "pact_broker/pacticipants/service"
|
2
|
+
require "pact_broker/api/contracts/webhook_request_contract"
|
3
|
+
require "pact_broker/api/contracts/webhook_pacticipant_contract"
|
5
4
|
require "pact_broker/webhooks/webhook_event"
|
6
5
|
|
7
6
|
module PactBroker
|
@@ -9,182 +8,31 @@ module PactBroker
|
|
9
8
|
module Contracts
|
10
9
|
class WebhookContract < BaseContract
|
11
10
|
|
12
|
-
|
13
|
-
result = super
|
14
|
-
# I just cannot seem to get the validation to stop on the first error.
|
15
|
-
# If one rule fails, they all come back failed, and it's driving me nuts.
|
16
|
-
# Why on earth would I want that behaviour?
|
17
|
-
# I cannot believe I have to do this shit.
|
18
|
-
@first_errors = errors
|
19
|
-
@first_errors.messages.keys.each do | key |
|
20
|
-
@first_errors.messages[key] = @first_errors.messages[key][0...1]
|
21
|
-
end
|
22
|
-
|
23
|
-
# rubocop: disable Lint/NestedMethodDefinition
|
24
|
-
def self.errors; @first_errors end
|
25
|
-
# rubocop: enable Lint/NestedMethodDefinition
|
26
|
-
|
27
|
-
result
|
28
|
-
end
|
29
|
-
|
30
|
-
validation do
|
31
|
-
configure do
|
32
|
-
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
33
|
-
end
|
34
|
-
|
35
|
-
optional(:consumer)
|
36
|
-
optional(:provider)
|
37
|
-
required(:request).filled
|
38
|
-
optional(:events).maybe(min_size?: 1)
|
39
|
-
end
|
40
|
-
|
41
|
-
property :consumer do
|
42
|
-
property :name
|
43
|
-
property :label
|
44
|
-
|
45
|
-
validation do
|
46
|
-
configure do
|
47
|
-
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
48
|
-
|
49
|
-
def pacticipant_exists?(name)
|
50
|
-
!!PactBroker::Pacticipants::Service.find_pacticipant_by_name(name)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
optional(:name)
|
55
|
-
.maybe(:pacticipant_exists?)
|
56
|
-
.when(:none?) { value(:label).filled? }
|
57
|
-
|
58
|
-
optional(:label)
|
59
|
-
.maybe(:str?)
|
60
|
-
.when(:none?) { value(:name).filled? }
|
61
|
-
|
62
|
-
rule(label: [:name, :label]) do |name, label|
|
63
|
-
(name.filled? & label.filled?) > label.none?
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
property :provider do
|
69
|
-
property :name
|
70
|
-
property :label
|
71
|
-
|
72
|
-
validation do
|
73
|
-
configure do
|
74
|
-
config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
|
75
|
-
|
76
|
-
def pacticipant_exists?(name)
|
77
|
-
!!PactBroker::Pacticipants::Service.find_pacticipant_by_name(name)
|
78
|
-
end
|
79
|
-
end
|
11
|
+
UUID_REGEX = /^[A-Za-z0-9_\-]{16,}$/
|
80
12
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
optional(:label)
|
86
|
-
.maybe(:str?)
|
87
|
-
.when(:none?) { value(:name).filled? }
|
88
|
-
|
89
|
-
rule(label: [:name, :label]) do |name, label|
|
90
|
-
(name.filled? & label.filled?) > label.none?
|
91
|
-
end
|
13
|
+
class EventContract < BaseContract
|
14
|
+
json do
|
15
|
+
required(:name).filled(included_in?: PactBroker::Webhooks::WebhookEvent::EVENT_NAMES)
|
92
16
|
end
|
93
17
|
end
|
94
18
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
def self.messages
|
104
|
-
super.merge(
|
105
|
-
en: {
|
106
|
-
errors: {
|
107
|
-
allowed_webhook_method?: http_method_error_message,
|
108
|
-
allowed_webhook_scheme?: scheme_error_message,
|
109
|
-
allowed_webhook_host?: host_error_message
|
110
|
-
}
|
111
|
-
}
|
112
|
-
)
|
113
|
-
end
|
114
|
-
|
115
|
-
def self.http_method_error_message
|
116
|
-
if PactBroker.configuration.webhook_http_method_whitelist.size == 1
|
117
|
-
"must be #{PactBroker.configuration.webhook_http_method_whitelist.first}. See /doc/webhooks#whitelist for more information."
|
118
|
-
else
|
119
|
-
"must be one of #{PactBroker.configuration.webhook_http_method_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def self.scheme_error_message
|
124
|
-
"scheme must be #{PactBroker.configuration.webhook_scheme_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
125
|
-
end
|
126
|
-
|
127
|
-
def self.host_error_message
|
128
|
-
"host must be in the whitelist #{PactBroker.configuration.webhook_host_whitelist.join(",")}. See /doc/webhooks#whitelist for more information."
|
129
|
-
end
|
130
|
-
|
131
|
-
def valid_method?(http_method)
|
132
|
-
Net::HTTP.const_defined?(http_method.capitalize)
|
133
|
-
rescue StandardError
|
134
|
-
false
|
135
|
-
end
|
136
|
-
|
137
|
-
def valid_url?(url)
|
138
|
-
uri = parse_uri(url)
|
139
|
-
uri.scheme && uri.host
|
140
|
-
rescue URI::InvalidURIError, ArgumentError
|
141
|
-
nil
|
142
|
-
end
|
143
|
-
|
144
|
-
def allowed_webhook_method?(http_method)
|
145
|
-
PactBroker.configuration.webhook_http_method_whitelist.any? do | allowed_method |
|
146
|
-
http_method.downcase == allowed_method.downcase
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def allowed_webhook_scheme?(url)
|
151
|
-
scheme = parse_uri(url).scheme
|
152
|
-
PactBroker.configuration.webhook_scheme_whitelist.any? do | allowed_scheme |
|
153
|
-
scheme.downcase == allowed_scheme.downcase
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def allowed_webhook_host?(url)
|
158
|
-
if host_whitelist.any?
|
159
|
-
PactBroker::Webhooks::CheckHostWhitelist.call(parse_uri(url).host, host_whitelist).any?
|
160
|
-
else
|
161
|
-
true
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def non_templated_host?(url)
|
166
|
-
parse_uri(url).host == parse_uri(url, "differentplaceholder").host
|
167
|
-
end
|
168
|
-
|
169
|
-
def host_whitelist
|
170
|
-
PactBroker.configuration.webhook_host_whitelist
|
171
|
-
end
|
172
|
-
|
173
|
-
def parse_uri(uri_string, placeholder = "placeholder")
|
174
|
-
URI(PactBroker::Webhooks::Render.render_with_placeholder(uri_string, placeholder))
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
required(:http_method).filled(:valid_method?, :allowed_webhook_method?)
|
179
|
-
required(:url).filled(:valid_url?, :allowed_webhook_scheme?, :allowed_webhook_host?, :non_templated_host?)
|
180
|
-
end
|
19
|
+
json do
|
20
|
+
optional(:uuid).maybe(:string) # set in resource class from the path info - doesn't come in in the request body
|
21
|
+
optional(:consumer).maybe(:hash)
|
22
|
+
optional(:provider).maybe(:hash)
|
23
|
+
required(:request).filled(:hash)
|
24
|
+
optional(:events).maybe(min_size?: 1)
|
25
|
+
optional(:enabled).filled(:bool)
|
181
26
|
end
|
182
27
|
|
183
|
-
|
184
|
-
|
28
|
+
rule(:consumer).validate(validate_with_contract: WebhookPacticipantContract)
|
29
|
+
rule(:provider).validate(validate_with_contract: WebhookPacticipantContract)
|
30
|
+
rule(:request).validate(validate_with_contract: WebhookRequestContract)
|
31
|
+
rule(:events).validate(validate_each_with_contract: EventContract)
|
185
32
|
|
186
|
-
|
187
|
-
|
33
|
+
rule(:uuid) do
|
34
|
+
if value && !(value =~ UUID_REGEX)
|
35
|
+
key.failure(validation_message("invalid_webhook_uuid"))
|
188
36
|
end
|
189
37
|
end
|
190
38
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "pact_broker/api/contracts/base_contract"
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Api
|
5
|
+
module Contracts
|
6
|
+
class WebhookPacticipantContract < BaseContract
|
7
|
+
json do
|
8
|
+
optional(:name).maybe(:string)
|
9
|
+
optional(:label).maybe(:string)
|
10
|
+
end
|
11
|
+
|
12
|
+
register_macro(:name_or_label_required) do
|
13
|
+
if !provided?(values[:name]) && !provided?(values[:label])
|
14
|
+
key(path.keys).failure(validation_message("blank"))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
register_macro(:name_and_label_exclusive) do
|
19
|
+
if provided?(values[:name]) && provided?(values[:label])
|
20
|
+
key([:label]).failure(validation_message("cannot_be_provided_at_same_time", name_1: "name", name_2: "label"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
rule(:name, :label).validate(:name_or_label_required)
|
25
|
+
rule(:name, :label).validate(:name_and_label_exclusive)
|
26
|
+
|
27
|
+
rule(:name) do
|
28
|
+
validate_pacticipant_with_name_exists(value, key) if provided?(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require "pact_broker/api/contracts/base_contract"
|
2
|
+
require "pact_broker/webhooks/render"
|
3
|
+
require "pact_broker/webhooks/check_host_whitelist"
|
4
|
+
require "pact_broker/api/contracts/validation_helpers"
|
5
|
+
|
6
|
+
module PactBroker
|
7
|
+
module Api
|
8
|
+
module Contracts
|
9
|
+
class WebhookRequestContract < BaseContract
|
10
|
+
include ValidationHelpers
|
11
|
+
|
12
|
+
json do
|
13
|
+
required(:method).filled(:string)
|
14
|
+
required(:url).filled(:string)
|
15
|
+
end
|
16
|
+
|
17
|
+
rule(:url) do
|
18
|
+
if !valid_webhook_url?(value)
|
19
|
+
key.failure(validation_message("invalid_url"))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rule(:method) do
|
24
|
+
if !valid_http_method?(value)
|
25
|
+
key.failure(validation_message("invalid_http_method"))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
rule(:method) do
|
30
|
+
if_still_valid(self) do
|
31
|
+
if !allowed_webhook_method?(value)
|
32
|
+
key.failure(http_method_error_message)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
rule(:url) do
|
38
|
+
if_still_valid(self) do
|
39
|
+
if templated_host?(value)
|
40
|
+
key.failure(validation_message("webhook_templated_host_not_allowed"))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
rule(:url) do
|
46
|
+
if_still_valid(self) do
|
47
|
+
if !allowed_webhook_scheme?(value)
|
48
|
+
key.failure(scheme_error_message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
rule(:url) do
|
54
|
+
if_still_valid(self) do
|
55
|
+
if !allowed_webhook_host?(value)
|
56
|
+
key.failure(host_error_message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def allowed_webhook_method?(http_method)
|
62
|
+
PactBroker.configuration.webhook_http_method_whitelist.any? do | allowed_method |
|
63
|
+
http_method.downcase == allowed_method.downcase
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def http_method_error_message
|
68
|
+
if PactBroker.configuration.webhook_http_method_whitelist.size == 1
|
69
|
+
"must be #{PactBroker.configuration.webhook_http_method_whitelist.first}. See /doc/webhooks#whitelist for more information."
|
70
|
+
else
|
71
|
+
"must be one of #{PactBroker.configuration.webhook_http_method_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def allowed_webhook_scheme?(url)
|
76
|
+
scheme = parse_uri(url).scheme
|
77
|
+
PactBroker.configuration.webhook_scheme_whitelist.any? do | allowed_scheme |
|
78
|
+
scheme.downcase == allowed_scheme.downcase
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def scheme_error_message
|
83
|
+
"scheme must be #{PactBroker.configuration.webhook_scheme_whitelist.join(", ")}. See /doc/webhooks#whitelist for more information."
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_uri(uri_string, placeholder = "placeholder")
|
87
|
+
URI(PactBroker::Webhooks::Render.render_with_placeholder(uri_string, placeholder))
|
88
|
+
end
|
89
|
+
|
90
|
+
def allowed_webhook_host?(url)
|
91
|
+
if host_whitelist.any?
|
92
|
+
PactBroker::Webhooks::CheckHostWhitelist.call(parse_uri(url).host, host_whitelist).any?
|
93
|
+
else
|
94
|
+
true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def host_whitelist
|
99
|
+
PactBroker.configuration.webhook_host_whitelist
|
100
|
+
end
|
101
|
+
|
102
|
+
def host_error_message
|
103
|
+
"host must be in the whitelist #{PactBroker.configuration.webhook_host_whitelist.collect(&:inspect).join(", ")}. See /doc/webhooks#whitelist for more information."
|
104
|
+
end
|
105
|
+
|
106
|
+
def valid_webhook_url?(url)
|
107
|
+
uri = parse_uri(url)
|
108
|
+
uri.scheme && uri.host
|
109
|
+
rescue URI::InvalidURIError, ArgumentError
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def templated_host?(url)
|
114
|
+
parse_uri(url).host != parse_uri(url, "differentplaceholder").host
|
115
|
+
end
|
116
|
+
|
117
|
+
def if_still_valid(context)
|
118
|
+
if !context.rule_error?(context.path.keys)
|
119
|
+
yield
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -17,18 +17,18 @@ module PactBroker
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# @return [Hash]
|
20
|
-
def to_hash(
|
20
|
+
def to_hash(user_options: {}, **__other)
|
21
21
|
{
|
22
22
|
"title" => @title,
|
23
|
-
"type" => "#{
|
23
|
+
"type" => "#{user_options[:base_url]}/problem/#{@type}",
|
24
24
|
"detail" => @detail,
|
25
25
|
"status" => @status
|
26
26
|
}
|
27
27
|
end
|
28
28
|
|
29
29
|
# @return [String] JSON
|
30
|
-
def to_json(
|
31
|
-
to_hash(
|
30
|
+
def to_json(*args, **kwargs)
|
31
|
+
to_hash(*args, **kwargs).to_json
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -17,8 +17,8 @@ module PactBroker
|
|
17
17
|
to_hash(options).to_json
|
18
18
|
end
|
19
19
|
|
20
|
-
def to_text(
|
21
|
-
data = items(index_items,
|
20
|
+
def to_text(user_options:, **_other)
|
21
|
+
data = items(index_items, user_options[:base_url])
|
22
22
|
printer = TablePrint::Printer.new(data)
|
23
23
|
printer.table_print + "\n"
|
24
24
|
end
|
@@ -32,7 +32,7 @@ module PactBroker
|
|
32
32
|
|
33
33
|
# TODO rather than remove the contract keys that we added in the super class,
|
34
34
|
# it would be better to inherit from a shared super class
|
35
|
-
def to_hash(
|
35
|
+
def to_hash(*)
|
36
36
|
keys_to_remove = represented.content_hash.keys
|
37
37
|
super.each_with_object({}) do | (key, value), new_hash |
|
38
38
|
new_hash[key] = value unless keys_to_remove.include?(key)
|
@@ -16,18 +16,18 @@ module PactBroker
|
|
16
16
|
@query_results_with_deployment_status_summary = query_results_with_deployment_status_summary
|
17
17
|
end
|
18
18
|
|
19
|
-
def to_json(
|
20
|
-
to_hash(
|
19
|
+
def to_json(*args, **kwargs)
|
20
|
+
to_hash(*args, **kwargs).to_json
|
21
21
|
end
|
22
22
|
|
23
|
-
def to_hash(
|
23
|
+
def to_hash(user_options:, **_other)
|
24
24
|
{
|
25
25
|
summary: {
|
26
26
|
deployable: deployable,
|
27
27
|
reason: reason
|
28
28
|
},
|
29
29
|
notices: notices,
|
30
|
-
matrix: matrix(
|
30
|
+
matrix: matrix(user_options[:base_url])
|
31
31
|
}.tap do | hash |
|
32
32
|
hash[:summary].merge!(query_results_with_deployment_status_summary.deployment_status_summary.counts)
|
33
33
|
end
|
@@ -14,7 +14,7 @@ module PactBroker
|
|
14
14
|
@lines = lines
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_text(_options)
|
17
|
+
def to_text(**_options)
|
18
18
|
json_decorator = PactBroker::Api::Decorators::MatrixDecorator.new(lines)
|
19
19
|
data = lines.collect do | line |
|
20
20
|
Line.new(line.consumer_name, line.consumer_version_number, line.pact_revision_number, line.provider_name, line.provider_version_number, line.verification_number, line.success)
|
@@ -37,7 +37,7 @@ module PactBroker
|
|
37
37
|
end
|
38
38
|
|
39
39
|
class DeprecatedPacticipantDecorator < PactBroker::Api::Decorators::PacticipantDecorator
|
40
|
-
property :title, getter: ->(
|
40
|
+
property :title, getter: ->(_) { "DEPRECATED - Please use the embedded pacticipants collection" }
|
41
41
|
end
|
42
42
|
|
43
43
|
class NonEmbeddedPacticipantCollectionDecorator < BaseDecorator
|
@@ -46,7 +46,7 @@ module PactBroker
|
|
46
46
|
|
47
47
|
# TODO deprecate this - breaking change for v 3.0
|
48
48
|
class DeprecatedPacticipantCollectionDecorator < PacticipantCollectionDecorator
|
49
|
-
def to_hash(options
|
49
|
+
def to_hash(options)
|
50
50
|
embedded_pacticipant_hash = super
|
51
51
|
non_embedded_pacticipant_hash = NonEmbeddedPacticipantCollectionDecorator.new(represented).to_hash(options)
|
52
52
|
embedded_pacticipant_hash.merge(non_embedded_pacticipant_hash)
|
@@ -106,7 +106,8 @@ module PactBroker
|
|
106
106
|
}]
|
107
107
|
end
|
108
108
|
|
109
|
-
|
109
|
+
# representable passes through the kwargs from to_json as normal args
|
110
|
+
def to_hash(options)
|
110
111
|
h = super
|
111
112
|
dasherized = DasherizedVersionDecorator.new(represented).to_hash(options)
|
112
113
|
if dasherized["_embedded"]
|
@@ -15,7 +15,10 @@ module PactBroker
|
|
15
15
|
property :provider_version_branch
|
16
16
|
|
17
17
|
collection :consumer_version_selectors, default: PactBroker::Pacts::Selectors.new, class: PactBroker::Pacts::Selector do
|
18
|
-
property :main_branch
|
18
|
+
property :main_branch, setter: -> (fragment:, represented:, **) {
|
19
|
+
represented.main_branch = fragment
|
20
|
+
represented.latest = true
|
21
|
+
}
|
19
22
|
property :tag
|
20
23
|
property :branch, setter: -> (fragment:, represented:, **) {
|
21
24
|
represented.branch = fragment
|
@@ -8,13 +8,13 @@ module PactBroker
|
|
8
8
|
include Roar::JSON::HAL
|
9
9
|
include Roar::JSON::HAL::Links
|
10
10
|
|
11
|
-
property :page, getter: lambda { |
|
12
|
-
if
|
11
|
+
property :page, getter: lambda { |represented:, **|
|
12
|
+
if represented.respond_to?(:current_page)
|
13
13
|
{
|
14
|
-
number:
|
15
|
-
size:
|
16
|
-
totalElements:
|
17
|
-
totalPages:
|
14
|
+
number: represented.current_page,
|
15
|
+
size: represented.page_size,
|
16
|
+
totalElements: represented.pagination_record_count,
|
17
|
+
totalPages: represented.page_count,
|
18
18
|
}
|
19
19
|
end
|
20
20
|
}
|
@@ -11,18 +11,18 @@ module PactBroker
|
|
11
11
|
end
|
12
12
|
|
13
13
|
# @return [Hash]
|
14
|
-
def to_hash(
|
14
|
+
def to_hash(user_options:, **)
|
15
15
|
{
|
16
16
|
"title" => "Server error",
|
17
|
-
"type" => "#{
|
17
|
+
"type" => "#{user_options[:base_url]}/problems/server_error",
|
18
18
|
"detail" => message,
|
19
19
|
"status" => 500
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
23
|
# @return [String] JSON
|
24
|
-
def to_json(
|
25
|
-
to_hash(
|
24
|
+
def to_json(*args, **kwargs)
|
25
|
+
to_hash(*args, **kwargs).to_json
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
@@ -15,12 +15,12 @@ module PactBroker
|
|
15
15
|
end
|
16
16
|
|
17
17
|
# @return [Hash]
|
18
|
-
def to_hash(
|
18
|
+
def to_hash(user_options:, **)
|
19
19
|
error_list = []
|
20
|
-
walk_errors(errors, error_list, "",
|
20
|
+
walk_errors(errors, error_list, "", user_options[:base_url])
|
21
21
|
{
|
22
22
|
"title" => "Validation errors",
|
23
|
-
"type" => "#{
|
23
|
+
"type" => "#{user_options[:base_url]}/problems/validation-error",
|
24
24
|
"status" => 400,
|
25
25
|
"instance" => "/",
|
26
26
|
"errors" => error_list
|
@@ -28,8 +28,8 @@ module PactBroker
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# @return [String] JSON
|
31
|
-
def to_json(
|
32
|
-
to_hash(
|
31
|
+
def to_json(*args, **kwargs)
|
32
|
+
to_hash(*args, **kwargs).to_json
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
@@ -57,7 +57,7 @@ module PactBroker
|
|
57
57
|
"detail" => message,
|
58
58
|
"status" => 400
|
59
59
|
}
|
60
|
-
error["pointer"] = path if path.present?
|
60
|
+
error["pointer"] = path.tr(".", "/") if path.present?
|
61
61
|
list << error
|
62
62
|
end
|
63
63
|
end
|
@@ -9,17 +9,17 @@ module PactBroker
|
|
9
9
|
class VerifiablePactDecorator < BaseDecorator
|
10
10
|
include PactBroker::Pacts::Metadata
|
11
11
|
|
12
|
-
property :shortDescription, getter:
|
12
|
+
property :shortDescription, getter: lambda { | represented:, ** | PactBroker::Pacts::VerifiablePactMessages.new(represented, nil).pact_version_short_description }
|
13
13
|
|
14
14
|
nested :verificationProperties do
|
15
15
|
include PactBroker::Api::PactBrokerUrls
|
16
16
|
|
17
17
|
property :pending,
|
18
|
-
if: ->(
|
18
|
+
if: ->(options:, **_other) { options.dig(:user_options, :include_pending_status) }
|
19
19
|
property :wip,
|
20
|
-
if: -> (
|
20
|
+
if: -> (represented:, **_other) { represented.wip }
|
21
21
|
property :notices,
|
22
|
-
getter: -> (
|
22
|
+
getter: -> (decorator:, options:, **) { decorator.notices(options[:user_options]) }
|
23
23
|
|
24
24
|
def notices(user_options)
|
25
25
|
metadata = represented.wip ? { wip: true } : nil
|