pact_broker 2.106.0 → 2.107.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/Gemfile +3 -0
  4. data/db/migrations/20230131_add_cons_ver_id_ndx_to_latest_pp_id_for_cons_ver.rb +8 -4
  5. data/db/migrations/20230216_add_branch_heads_branch_version_id_index.rb +21 -0
  6. data/db/migrations/20230428_add_index_for_webhook_executions_pact_publication_id.rb +17 -0
  7. data/lib/pact_broker/api/contracts/base_contract.rb +22 -7
  8. data/lib/pact_broker/api/contracts/can_i_deploy_query_schema.rb +34 -0
  9. data/lib/pact_broker/api/contracts/configuration.rb +2 -0
  10. data/lib/pact_broker/api/contracts/consumer_version_selector_contract.rb +140 -0
  11. data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +50 -0
  12. data/lib/pact_broker/api/contracts/dry_validation_macros.rb +79 -0
  13. data/lib/pact_broker/api/contracts/dry_validation_methods.rb +71 -0
  14. data/lib/pact_broker/api/contracts/environment_schema.rb +19 -33
  15. data/lib/pact_broker/api/contracts/pacticipant_create_schema.rb +4 -17
  16. data/lib/pact_broker/api/contracts/pacticipant_schema.rb +15 -24
  17. data/lib/pact_broker/api/contracts/pacts_for_verification_json_query_schema.rb +37 -146
  18. data/lib/pact_broker/api/contracts/pacts_for_verification_query_string_schema.rb +7 -20
  19. data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +62 -0
  20. data/lib/pact_broker/api/contracts/publish_contracts_schema.rb +25 -124
  21. data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +21 -26
  22. data/lib/pact_broker/api/contracts/utf_8_validation.rb +2 -0
  23. data/lib/pact_broker/api/contracts/validation_helpers.rb +71 -0
  24. data/lib/pact_broker/api/contracts/verification_contract.rb +10 -29
  25. data/lib/pact_broker/api/contracts/webhook_contract.rb +20 -172
  26. data/lib/pact_broker/api/contracts/webhook_pacticipant_contract.rb +33 -0
  27. data/lib/pact_broker/api/contracts/webhook_request_contract.rb +125 -0
  28. data/lib/pact_broker/api/contracts.rb +3 -0
  29. data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +4 -4
  30. data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +2 -2
  31. data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +1 -1
  32. data/lib/pact_broker/api/decorators/matrix_decorator.rb +4 -4
  33. data/lib/pact_broker/api/decorators/matrix_text_decorator.rb +1 -1
  34. data/lib/pact_broker/api/decorators/pact_decorator.rb +1 -1
  35. data/lib/pact_broker/api/decorators/pacticipant_collection_decorator.rb +2 -2
  36. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +2 -1
  37. data/lib/pact_broker/api/decorators/pacts_for_verification_query_decorator.rb +4 -1
  38. data/lib/pact_broker/api/decorators/pagination_links.rb +6 -6
  39. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +4 -4
  40. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +6 -6
  41. data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -4
  42. data/lib/pact_broker/api/decorators/webhook_decorator.rb +2 -3
  43. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +5 -12
  44. data/lib/pact_broker/api/resources/all_webhooks.rb +5 -11
  45. data/lib/pact_broker/api/resources/base_resource.rb +3 -20
  46. data/lib/pact_broker/api/resources/branch_version.rb +3 -3
  47. data/lib/pact_broker/api/resources/can_i_deploy.rb +4 -19
  48. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb +1 -4
  49. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag.rb +0 -2
  50. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_tag_to_tag_badge.rb +1 -2
  51. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +2 -2
  52. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +2 -2
  53. data/lib/pact_broker/api/resources/dashboard.rb +3 -3
  54. data/lib/pact_broker/api/resources/deployed_version.rb +1 -1
  55. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +2 -2
  56. data/lib/pact_broker/api/resources/environment.rb +1 -1
  57. data/lib/pact_broker/api/resources/environments.rb +2 -2
  58. data/lib/pact_broker/api/resources/error_handling_methods.rb +2 -2
  59. data/lib/pact_broker/api/resources/integrations.rb +1 -1
  60. data/lib/pact_broker/api/resources/label.rb +1 -1
  61. data/lib/pact_broker/api/resources/latest_pact.rb +2 -2
  62. data/lib/pact_broker/api/resources/latest_pacts.rb +1 -1
  63. data/lib/pact_broker/api/resources/latest_verifications_for_consumer_version.rb +1 -1
  64. data/lib/pact_broker/api/resources/matrix.rb +2 -2
  65. data/lib/pact_broker/api/resources/matrix_for_consumer_and_provider.rb +1 -1
  66. data/lib/pact_broker/api/resources/pact.rb +7 -4
  67. data/lib/pact_broker/api/resources/pact_triggered_webhooks.rb +1 -1
  68. data/lib/pact_broker/api/resources/pact_versions.rb +1 -1
  69. data/lib/pact_broker/api/resources/pact_webhooks.rb +7 -14
  70. data/lib/pact_broker/api/resources/pact_webhooks_status.rb +6 -2
  71. data/lib/pact_broker/api/resources/pacticipant.rb +1 -1
  72. data/lib/pact_broker/api/resources/pacticipant_webhooks.rb +7 -5
  73. data/lib/pact_broker/api/resources/pacticipants.rb +2 -2
  74. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +1 -1
  75. data/lib/pact_broker/api/resources/previous_distinct_pact_version.rb +1 -1
  76. data/lib/pact_broker/api/resources/provider_pacts.rb +1 -1
  77. data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +4 -13
  78. data/lib/pact_broker/api/resources/publish_contracts.rb +8 -3
  79. data/lib/pact_broker/api/resources/released_version.rb +1 -1
  80. data/lib/pact_broker/api/resources/released_versions_for_version_and_environment.rb +2 -2
  81. data/lib/pact_broker/api/resources/tag.rb +1 -1
  82. data/lib/pact_broker/api/resources/tagged_pact_versions.rb +1 -1
  83. data/lib/pact_broker/api/resources/triggered_webhook_logs.rb +2 -2
  84. data/lib/pact_broker/api/resources/verification.rb +2 -2
  85. data/lib/pact_broker/api/resources/verification_triggered_webhooks.rb +1 -1
  86. data/lib/pact_broker/api/resources/verifications.rb +4 -6
  87. data/lib/pact_broker/api/resources/version.rb +1 -1
  88. data/lib/pact_broker/api/resources/versions.rb +1 -1
  89. data/lib/pact_broker/api/resources/webhook.rb +7 -6
  90. data/lib/pact_broker/api/resources/webhook_execution.rb +6 -4
  91. data/lib/pact_broker/api.rb +3 -12
  92. data/lib/pact_broker/certificates/certificate.rb +1 -0
  93. data/lib/pact_broker/config/setting.rb +1 -0
  94. data/lib/pact_broker/contracts/service.rb +1 -0
  95. data/lib/pact_broker/date_helper.rb +1 -1
  96. data/lib/pact_broker/db/clean_incremental.rb +1 -1
  97. data/lib/pact_broker/db/delete_overwritten_data.rb +6 -2
  98. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -0
  99. data/lib/pact_broker/deployments/deployed_version.rb +2 -0
  100. data/lib/pact_broker/deployments/deployed_version_service.rb +5 -1
  101. data/lib/pact_broker/deployments/environment.rb +2 -0
  102. data/lib/pact_broker/deployments/environment_service.rb +4 -3
  103. data/lib/pact_broker/deployments/released_version.rb +2 -0
  104. data/lib/pact_broker/deployments/released_version_service.rb +4 -0
  105. data/lib/pact_broker/diagnostic/resources/base_resource.rb +1 -1
  106. data/lib/pact_broker/doc/views/index/publish-contracts.markdown +5 -5
  107. data/lib/pact_broker/domain/label.rb +1 -0
  108. data/lib/pact_broker/domain/tag.rb +2 -0
  109. data/lib/pact_broker/domain/verification.rb +1 -1
  110. data/lib/pact_broker/domain/version.rb +4 -1
  111. data/lib/pact_broker/domain/webhook.rb +1 -1
  112. data/lib/pact_broker/index/service.rb +1 -1
  113. data/lib/pact_broker/integrations/integration.rb +1 -0
  114. data/lib/pact_broker/locale/en.yml +35 -14
  115. data/lib/pact_broker/matrix/query_ids.rb +4 -4
  116. data/lib/pact_broker/matrix/resolved_selector.rb +6 -1
  117. data/lib/pact_broker/matrix/service.rb +1 -0
  118. data/lib/pact_broker/messages.rb +5 -1
  119. data/lib/pact_broker/pacticipants/repository.rb +12 -3
  120. data/lib/pact_broker/pacticipants/service.rb +7 -0
  121. data/lib/pact_broker/pacts/pact_params.rb +6 -17
  122. data/lib/pact_broker/pacts/pact_version.rb +1 -0
  123. data/lib/pact_broker/policies.rb +4 -4
  124. data/lib/pact_broker/test/http_test_data_builder.rb +46 -2
  125. data/lib/pact_broker/ui/app.rb +2 -2
  126. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +1 -1
  127. data/lib/pact_broker/verifications/pact_version_provider_tag_successful_verification.rb +1 -0
  128. data/lib/pact_broker/verifications/service.rb +0 -6
  129. data/lib/pact_broker/version.rb +1 -1
  130. data/lib/pact_broker/versions/branch.rb +1 -0
  131. data/lib/pact_broker/versions/branch_head.rb +2 -1
  132. data/lib/pact_broker/versions/branch_version.rb +11 -0
  133. data/lib/pact_broker/webhooks/execution.rb +1 -1
  134. data/lib/pact_broker/webhooks/repository.rb +1 -1
  135. data/lib/pact_broker/webhooks/service.rb +3 -25
  136. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
  137. data/lib/pact_broker/webhooks/webhook_event.rb +1 -0
  138. data/lib/pact_broker/webmachine.rb +22 -0
  139. data/lib/rack/pact_broker/invalid_uri_protection.rb +1 -1
  140. data/lib/rack/pact_broker/use_when.rb +6 -5
  141. data/lib/sequel/plugins/age.rb +13 -0
  142. data/lib/webmachine/application_monkey_patch.rb +5 -0
  143. data/lib/webmachine/describe_routes.rb +35 -8
  144. data/lib/webmachine/render_error_monkey_patch.rb +1 -1
  145. data/pact_broker.gemspec +7 -17
  146. metadata +65 -67
  147. data/lib/pact/doc/README.md +0 -5
  148. data/lib/pact_broker/api/contracts/dry_validation_predicates.rb +0 -36
  149. data/lib/pact_broker/api/contracts/dry_validation_workarounds.rb +0 -39
  150. data/lib/pact_broker/api/contracts/pacticipant_name_contract.rb +0 -24
  151. data/lib/pact_broker/api/contracts/pacticipant_name_validation.rb +0 -30
  152. data/lib/pact_broker/api/contracts/request_validations.rb +0 -33
  153. data/lib/pact_broker/api/resources/webhook_resource_methods.rb +0 -17
  154. 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
- property :success
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
- required(:success).filled(:bool?)
36
- required(:provider_version) { not_blank? & valid_version_number? }
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/webhooks/check_host_whitelist"
3
- require "pact_broker/webhooks/render"
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
- def validate(*)
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
- optional(:name)
82
- .maybe(:pacticipant_exists?)
83
- .when(:none?) { value(:label).filled? }
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
- property :request do
96
- property :url
97
- property :http_method
98
-
99
- validation do
100
- configure do
101
- config.messages_file = File.expand_path("../../../locale/en.yml", __FILE__)
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
- collection :events do
184
- property :name
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
- validation do
187
- required(:name).filled(included_in?: PactBroker::Webhooks::WebhookEvent::EVENT_NAMES)
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
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.expand_path(File.join(__FILE__, "..", "contracts", "*.rb"))).sort.each do | path |
2
+ require path
3
+ end
@@ -17,18 +17,18 @@ module PactBroker
17
17
  end
18
18
 
19
19
  # @return [Hash]
20
- def to_hash(decorator_options = {})
20
+ def to_hash(user_options: {}, **__other)
21
21
  {
22
22
  "title" => @title,
23
- "type" => "#{decorator_options.dig(:user_options, :base_url)}/problem/#{@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(decorator_options = {})
31
- to_hash(decorator_options).to_json
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(options)
21
- data = items(index_items, options[:user_options][:base_url])
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(options = {})
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(options)
20
- to_hash(options).to_json
19
+ def to_json(*args, **kwargs)
20
+ to_hash(*args, **kwargs).to_json
21
21
  end
22
22
 
23
- def to_hash(options)
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(options[:user_options][:base_url])
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)
@@ -9,7 +9,7 @@ module PactBroker
9
9
 
10
10
  include Timestamps
11
11
 
12
- def to_hash(options = {})
12
+ def to_hash(*)
13
13
  parsed_content = represented.content_hash
14
14
  if parsed_content.is_a?(::Hash)
15
15
  parsed_content.merge super
@@ -37,7 +37,7 @@ module PactBroker
37
37
  end
38
38
 
39
39
  class DeprecatedPacticipantDecorator < PactBroker::Api::Decorators::PacticipantDecorator
40
- property :title, getter: ->(_something) { "DEPRECATED - Please use the embedded pacticipants collection" }
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
- def to_hash options
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 { |context|
12
- if context[:represented].respond_to?(:current_page)
11
+ property :page, getter: lambda { |represented:, **|
12
+ if represented.respond_to?(:current_page)
13
13
  {
14
- number: context[:represented].current_page,
15
- size: context[:represented].page_size,
16
- totalElements: context[:represented].pagination_record_count,
17
- totalPages: context[:represented].page_count,
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(decorator_options = {})
14
+ def to_hash(user_options:, **)
15
15
  {
16
16
  "title" => "Server error",
17
- "type" => "#{decorator_options.dig(:user_options, :base_url)}/problems/server_error",
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(decorator_options = {})
25
- to_hash(decorator_options).to_json
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(decorator_options = {})
18
+ def to_hash(user_options:, **)
19
19
  error_list = []
20
- walk_errors(errors, error_list, "", decorator_options.dig(:user_options, :base_url))
20
+ walk_errors(errors, error_list, "", user_options[:base_url])
21
21
  {
22
22
  "title" => "Validation errors",
23
- "type" => "#{decorator_options.dig(:user_options, :base_url)}/problems/validation-error",
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(decorator_options = {})
32
- to_hash(decorator_options).to_json
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: -> (context) { PactBroker::Pacts::VerifiablePactMessages.new(context[:represented], nil).pact_version_short_description }
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: ->(context) { context[:options][:user_options][:include_pending_status] }
18
+ if: ->(options:, **_other) { options.dig(:user_options, :include_pending_status) }
19
19
  property :wip,
20
- if: -> (context) { context[:represented].wip }
20
+ if: -> (represented:, **_other) { represented.wip }
21
21
  property :notices,
22
- getter: -> (context) { context[:decorator].notices(context[:options][:user_options]) }
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