pact_broker 2.81.0 → 2.82.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/CHANGELOG.md +30 -0
  4. data/DEVELOPER_SETUP.md +1 -1
  5. data/README.md +7 -5
  6. data/config.ru +3 -28
  7. data/db/migrations/20210722_add_index_to_triggered_webhooks_webhook_uuid.rb +7 -0
  8. data/db/migrations/20210810_set_allow_contract_modification.rb +17 -0
  9. data/docs/CONFIGURATION.md +398 -0
  10. data/docs/configuration.yml +320 -0
  11. data/example/Gemfile +4 -4
  12. data/example/README.md +15 -22
  13. data/example/config.ru +1 -24
  14. data/example/config/pact_broker.yml +9 -0
  15. data/example/config/puma.rb +3 -0
  16. data/lib/db.rb +1 -1
  17. data/lib/pact_broker/api/authorization/resource_access_policy.rb +68 -0
  18. data/lib/pact_broker/api/authorization/resource_access_rules.rb +40 -0
  19. data/lib/pact_broker/api/decorators/deployed_version_decorator.rb +2 -0
  20. data/lib/pact_broker/api/decorators/released_version_decorator.rb +2 -0
  21. data/lib/pact_broker/api/middleware/basic_auth.rb +63 -0
  22. data/lib/pact_broker/api/resources/pact.rb +15 -6
  23. data/lib/pact_broker/api/resources/tag.rb +1 -14
  24. data/lib/pact_broker/app.rb +52 -30
  25. data/lib/pact_broker/config/basic_auth_configuration.rb +38 -0
  26. data/lib/pact_broker/config/load.rb +21 -10
  27. data/lib/pact_broker/config/runtime_configuration.rb +188 -0
  28. data/lib/pact_broker/config/runtime_configuration_coercion_methods.rb +41 -0
  29. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +119 -0
  30. data/lib/pact_broker/config/runtime_configuration_logging_methods.rb +61 -0
  31. data/lib/pact_broker/configuration.rb +67 -131
  32. data/lib/pact_broker/contracts/notice.rb +4 -0
  33. data/lib/pact_broker/contracts/service.rb +4 -4
  34. data/lib/pact_broker/db/models.rb +3 -0
  35. data/lib/pact_broker/db/validate_encoding.rb +0 -4
  36. data/lib/pact_broker/deployments/deployed_version.rb +8 -2
  37. data/lib/pact_broker/deployments/deployed_version_service.rb +13 -6
  38. data/lib/pact_broker/deployments/environment.rb +1 -1
  39. data/lib/pact_broker/deployments/released_version.rb +8 -0
  40. data/lib/pact_broker/deployments/released_version_service.rb +12 -0
  41. data/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown +4 -0
  42. data/lib/pact_broker/domain/pacticipant.rb +17 -13
  43. data/lib/pact_broker/domain/verification.rb +4 -22
  44. data/lib/pact_broker/domain/version.rb +9 -5
  45. data/lib/pact_broker/domain/webhook.rb +4 -0
  46. data/lib/pact_broker/error.rb +1 -0
  47. data/lib/pact_broker/errors.rb +1 -1
  48. data/lib/pact_broker/feature_toggle.rb +3 -5
  49. data/lib/pact_broker/hash_refinements.rb +0 -1
  50. data/lib/pact_broker/index/service.rb +4 -6
  51. data/lib/pact_broker/initializers/database_connection.rb +80 -0
  52. data/lib/pact_broker/integrations/integration.rb +5 -0
  53. data/lib/pact_broker/integrations/service.rb +4 -2
  54. data/lib/pact_broker/locale/en.yml +1 -0
  55. data/lib/pact_broker/logging.rb +2 -1
  56. data/lib/pact_broker/matrix/integration.rb +1 -1
  57. data/lib/pact_broker/matrix/parse_can_i_deploy_query.rb +2 -2
  58. data/lib/pact_broker/matrix/quick_row.rb +10 -0
  59. data/lib/pact_broker/matrix/repository.rb +64 -3
  60. data/lib/pact_broker/metrics/service.rb +16 -13
  61. data/lib/pact_broker/pacticipants/repository.rb +4 -0
  62. data/lib/pact_broker/pacticipants/service.rb +9 -1
  63. data/lib/pact_broker/pacts/pact_publication.rb +10 -13
  64. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +6 -1
  65. data/lib/pact_broker/pacts/pact_publication_selector_dataset_module.rb +1 -2
  66. data/lib/pact_broker/pacts/pact_version.rb +25 -11
  67. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +54 -77
  68. data/lib/pact_broker/pacts/selected_pact.rb +1 -1
  69. data/lib/pact_broker/pacts/selector.rb +15 -2
  70. data/lib/pact_broker/pacts/selectors.rb +4 -0
  71. data/lib/pact_broker/pacts/service.rb +4 -0
  72. data/lib/pact_broker/repositories/scopes.rb +12 -1
  73. data/lib/pact_broker/string_refinements.rb +6 -0
  74. data/lib/pact_broker/tags/service.rb +8 -1
  75. data/lib/pact_broker/test/http_test_data_builder.rb +11 -5
  76. data/lib/pact_broker/ui/views/index/_css_and_js.haml +11 -9
  77. data/lib/pact_broker/ui/views/index/_pagination.haml +3 -1
  78. data/lib/pact_broker/ui/views/layouts/main.haml +5 -3
  79. data/lib/pact_broker/ui/views/matrix/show.haml +10 -8
  80. data/lib/pact_broker/verifications/required_verification.rb +28 -0
  81. data/lib/pact_broker/verifications/service.rb +49 -1
  82. data/lib/pact_broker/version.rb +1 -1
  83. data/lib/pact_broker/versions/repository.rb +15 -0
  84. data/lib/pact_broker/versions/service.rb +32 -2
  85. data/lib/pact_broker/webhooks/event_listener.rb +3 -0
  86. data/lib/pact_broker/webhooks/trigger_service.rb +30 -14
  87. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
  88. data/lib/pact_broker/webhooks/webhook.rb +2 -2
  89. data/lib/pact_broker/webhooks/webhook_event.rb +6 -1
  90. data/lib/semantic_logger/formatters/short.rb +29 -0
  91. data/pact_broker.gemspec +1 -0
  92. data/script/data/auto-create-things-for-tags.rb +19 -0
  93. data/script/data/contract-published-requiring-verification.rb +27 -0
  94. data/script/{reproduce-issue-expand-currently-deployed.rb → data/expand-currently-deployed.rb} +0 -0
  95. data/script/docs/generate-configuration-docs.rb +86 -0
  96. data/spec/features/get_latest_pact_badge_spec.rb +1 -0
  97. data/spec/features/get_matrix_badge_spec.rb +1 -0
  98. data/spec/features/publish_pact_spec.rb +21 -7
  99. data/spec/features/wip_pacts_spec.rb +1 -1
  100. data/spec/fixtures/approvals/matrix_integration_environment_spec.approved.json +62 -0
  101. data/spec/fixtures/approvals/matrix_integration_ignore_spec.approved.json +124 -0
  102. data/spec/fixtures/approvals/matrix_integration_spec.approved.json +173 -0
  103. data/spec/fixtures/approvals/publish_contract_no_branch.approved.json +9 -9
  104. data/spec/fixtures/approvals/publish_contract_nothing_exists.approved.json +7 -7
  105. data/spec/fixtures/approvals/publish_contract_nothing_exists_with_webhook.approved.json +5 -5
  106. data/spec/fixtures/approvals/publish_contract_verification_already_exists.approved.json +5 -5
  107. data/spec/lib/pact_broker/api/middleware/basic_auth_spec.rb +312 -0
  108. data/spec/lib/pact_broker/api/resources/tag_spec.rb +14 -39
  109. data/spec/lib/pact_broker/app_basic_auth_spec.rb +122 -0
  110. data/spec/lib/pact_broker/config/load_spec.rb +33 -6
  111. data/spec/lib/pact_broker/config/runtime_configuration_logging_methods_spec.rb +22 -0
  112. data/spec/lib/pact_broker/config/runtime_configuration_spec.rb +71 -0
  113. data/spec/lib/pact_broker/configuration_spec.rb +51 -25
  114. data/spec/lib/pact_broker/errors/error_logger_spec.rb +3 -0
  115. data/spec/lib/pact_broker/feature_toggle_spec.rb +18 -19
  116. data/spec/lib/pact_broker/matrix/integration_environment_spec.rb +12 -0
  117. data/spec/lib/pact_broker/matrix/integration_ignore_spec.rb +15 -3
  118. data/spec/lib/pact_broker/matrix/integration_spec.rb +47 -6
  119. data/spec/lib/pact_broker/matrix/parse_can_i_deploy_query_spec.rb +16 -1
  120. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +0 -2
  121. data/spec/lib/pact_broker/matrix/repository_spec.rb +0 -2
  122. data/spec/lib/pact_broker/metrics/service_spec.rb +44 -0
  123. data/spec/lib/pact_broker/pacticipants/service_spec.rb +28 -5
  124. data/spec/lib/pact_broker/pacts/pact_publication_selector_dataset_module_spec.rb +25 -0
  125. data/spec/lib/pact_broker/pacts/pact_version_spec.rb +30 -1
  126. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +107 -20
  127. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +1 -1
  128. data/spec/lib/pact_broker/tags/service_spec.rb +24 -8
  129. data/spec/lib/pact_broker/verifications/service_spec.rb +146 -0
  130. data/spec/lib/pact_broker/versions/repository_spec.rb +38 -2
  131. data/spec/lib/pact_broker/versions/service_spec.rb +93 -2
  132. data/spec/lib/pact_broker/webhooks/trigger_service_spec.rb +54 -2
  133. data/spec/lib/rack/pact_broker/invalid_uri_protection_spec.rb +3 -3
  134. data/spec/spec_helper.rb +2 -1
  135. data/spec/support/approvals.rb +29 -0
  136. metadata +52 -13
  137. data/example/basic_auth/Gemfile +0 -5
  138. data/example/basic_auth/Procfile +0 -1
  139. data/example/basic_auth/README.md +0 -43
  140. data/example/basic_auth/config.ru +0 -19
  141. data/example/example_data.sql +0 -19
  142. data/spec/lib/pact_broker/config/save_and_load_spec.rb +0 -25
  143. data/spec/lib/pact_broker/pacts/service_find_for_verification_spec.rb +0 -50
@@ -0,0 +1,38 @@
1
+ require "pact_broker/config/runtime_configuration_logging_methods"
2
+ require "pact_broker/string_refinements"
3
+
4
+ module PactBroker
5
+ module Config
6
+ module RuntimeConfigurationBasicAuthMethods
7
+ using PactBroker::StringRefinements
8
+
9
+ def self.included(anyway_config)
10
+ anyway_config.class_eval do
11
+ attr_config(
12
+ basic_auth_enabled: false,
13
+ basic_auth_username: nil,
14
+ basic_auth_password: nil,
15
+ basic_auth_read_only_username: nil,
16
+ basic_auth_read_only_password: nil,
17
+ allow_public_read: false,
18
+ public_heartbeat: false
19
+ )
20
+
21
+ sensitive_values(:basic_auth_password, :basic_auth_read_only_password)
22
+
23
+ def basic_auth_credentials_provided?
24
+ basic_auth_username&.not_blank? && basic_auth_password&.not_blank?
25
+ end
26
+
27
+ def basic_auth_write_credentials
28
+ [basic_auth_username, basic_auth_password]
29
+ end
30
+
31
+ def basic_auth_read_credentials
32
+ [basic_auth_read_only_username, basic_auth_read_only_password]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -9,12 +9,12 @@ module PactBroker
9
9
 
10
10
  include PactBroker::Logging
11
11
 
12
- def self.call configuration
13
- new(configuration).call
12
+ def self.call runtime_configuration
13
+ new(runtime_configuration).call
14
14
  end
15
15
 
16
- def initialize configuration
17
- @configuration = configuration
16
+ def initialize runtime_configuration
17
+ @runtime_configuration = runtime_configuration
18
18
  end
19
19
 
20
20
  def call
@@ -25,18 +25,29 @@ module PactBroker
25
25
 
26
26
  private
27
27
 
28
- attr_reader :configuration
28
+ attr_reader :runtime_configuration
29
29
 
30
30
  def configuration_attribute_exists? setting
31
- configuration.respond_to?("#{setting.name}=")
31
+ runtime_configuration.respond_to?("#{setting.name}=")
32
+ end
33
+
34
+ def unset_or_value_from_default? setting
35
+ setting_source(setting).nil? || setting_source(setting)[:type] == :defaults
36
+ end
37
+
38
+ def setting_source(setting)
39
+ runtime_configuration.to_source_trace.dig(setting.name, :source)
32
40
  end
33
41
 
34
42
  def set_value_on_configuration setting
35
- if configuration_attribute_exists? setting
36
- logger.debug("Loading #{setting.name} configuration from database.")
37
- configuration.send("#{setting.name}=", setting.value_object)
43
+ if configuration_attribute_exists?(setting)
44
+ if unset_or_value_from_default?(setting)
45
+ runtime_configuration.send("#{setting.name}=", setting.value_object)
46
+ else
47
+ logger.debug("Ignoring #{setting.name} configuration from database, as it has been set by another source #{setting_source(setting)}")
48
+ end
38
49
  else
39
- logger.warn("Could not load configuration setting \"#{setting.name}\" as there is no matching attribute on the Configuration class")
50
+ logger.warn("Could not load configuration setting \"#{setting.name}\" as there is no matching attribute on the #{runtime_configuration.class} class")
40
51
  end
41
52
  end
42
53
  end
@@ -0,0 +1,188 @@
1
+ require "anyway_config"
2
+ require "pact_broker/config/runtime_configuration_logging_methods"
3
+ require "pact_broker/config/runtime_configuration_database_methods"
4
+ require "pact_broker/config/runtime_configuration_coercion_methods"
5
+ require "pact_broker/version"
6
+ require "pact_broker/config/basic_auth_configuration"
7
+ require "pact_broker/string_refinements"
8
+ require "pact_broker/hash_refinements"
9
+ require "pact_broker/error"
10
+
11
+ module PactBroker
12
+ module Config
13
+ class RuntimeConfiguration < Anyway::Config
14
+ using PactBroker::StringRefinements
15
+ using PactBroker::HashRefinements
16
+ include RuntimeConfigurationLoggingMethods
17
+ include RuntimeConfigurationCoercionMethods
18
+
19
+ include RuntimeConfigurationDatabaseMethods
20
+ include RuntimeConfigurationBasicAuthMethods
21
+
22
+ # logging attributes
23
+ attr_config(
24
+ log_dir: File.expand_path("./log"),
25
+ log_stream: :file,
26
+ log_level: :info,
27
+ log_format: nil,
28
+ warning_error_class_names: ["Sequel::ForeignKeyConstraintViolation"],
29
+ hide_pactflow_messages: false,
30
+ log_configuration_on_startup: true
31
+ )
32
+
33
+ on_load :validate_logging_attributes!
34
+
35
+ # webhook attributes
36
+ attr_config(
37
+ webhook_retry_schedule: [10, 60, 120, 300, 600, 1200], #10 sec, 1 min, 2 min, 5 min, 10 min, 20 min => 38 minutes
38
+ webhook_http_method_whitelist: ["POST"],
39
+ webhook_http_code_success: [200, 201, 202, 203, 204, 205, 206],
40
+ webhook_scheme_whitelist: ["https"],
41
+ webhook_host_whitelist: [],
42
+ disable_ssl_verification: false,
43
+ user_agent: "Pact Broker v#{PactBroker::VERSION}",
44
+ )
45
+
46
+ # resource attributes
47
+ attr_config(
48
+ port: 9292,
49
+ base_url: nil,
50
+ base_urls: [],
51
+ use_hal_browser: true,
52
+ enable_diagnostic_endpoints: true,
53
+ use_rack_protection: true,
54
+ badge_provider_mode: :redirect,
55
+ enable_public_badge_access: false,
56
+ shields_io_base_url: "https://img.shields.io",
57
+ use_case_sensitive_resource_names: true
58
+ )
59
+
60
+ # domain attributes
61
+ attr_config(
62
+ order_versions_by_date: true,
63
+ base_equality_only_on_content_that_affects_verification_results: true,
64
+ check_for_potential_duplicate_pacticipant_names: true,
65
+ create_deployed_versions_for_tags: true,
66
+ use_first_tag_as_branch: true,
67
+ use_first_tag_as_branch_time_limit: 10,
68
+ auto_detect_main_branch: true,
69
+ main_branch_candidates: ["develop", "main", "master"],
70
+ allow_dangerous_contract_modification: true,
71
+ semver_formats: ["%M.%m.%p%s%d", "%M.%m", "%M"],
72
+ seed_example_data: true,
73
+ features: []
74
+ )
75
+
76
+ def self.getter_and_setter_method_names
77
+ extra_methods = [
78
+ :warning_error_classes,
79
+ :database_configuration,
80
+ :basic_auth_credentials_provided?,
81
+ :basic_auth_write_credentials,
82
+ :basic_auth_read_credentials
83
+ ]
84
+ config_attributes + config_attributes.collect{ |k| "#{k}=".to_sym } + extra_methods - [:base_url]
85
+ end
86
+
87
+ config_name :pact_broker
88
+
89
+ sensitive_values(:database_url, :database_password)
90
+
91
+ def log_level= log_level
92
+ super(log_level&.downcase&.to_sym)
93
+ end
94
+
95
+ def log_stream= log_stream
96
+ super(log_stream&.to_sym)
97
+ end
98
+
99
+ def log_format= log_format
100
+ super(log_format&.to_sym)
101
+ end
102
+
103
+ def custom_log_formatters= custom_log_formatters
104
+ super(custom_log_formatters&.symbolize_keys)
105
+ end
106
+
107
+ def base_url= base_url
108
+ super(value_to_string_array(base_url, "base_url"))
109
+ end
110
+
111
+ alias_method :original_base_url, :base_url
112
+
113
+ def base_url
114
+ raise NotImplementedError
115
+ end
116
+
117
+ def base_urls= base_urls
118
+ super(value_to_string_array(base_urls, "base_urls"))
119
+ end
120
+
121
+ def base_urls
122
+ (super + [*original_base_url]).uniq
123
+ end
124
+
125
+ def badge_provider_mode= badge_provider_mode
126
+ super(badge_provider_mode&.to_sym)
127
+ end
128
+
129
+ def warning_error_class_names= warning_error_class_names
130
+ super(value_to_string_array(warning_error_class_names, "warning_error_class_names"))
131
+ end
132
+
133
+ def semver_formats= semver_formats
134
+ super(value_to_string_array(semver_formats, "semver_formats"))
135
+ end
136
+
137
+ def webhook_retry_schedule= webhook_retry_schedule
138
+ super(value_to_integer_array(webhook_retry_schedule, "webhook_retry_schedule"))
139
+ end
140
+
141
+ def webhook_http_method_whitelist= webhook_http_method_whitelist
142
+ super(value_to_string_array(webhook_http_method_whitelist, "webhook_http_method_whitelist"))
143
+ end
144
+
145
+ def webhook_http_code_success= webhook_http_code_success
146
+ super(value_to_integer_array(webhook_http_code_success, "webhook_http_code_success"))
147
+ end
148
+
149
+ def webhook_scheme_whitelist= webhook_scheme_whitelist
150
+ super(value_to_string_array(webhook_scheme_whitelist, "webhook_scheme_whitelist"))
151
+ end
152
+
153
+ def webhook_host_whitelist= webhook_host_whitelist
154
+ super(value_to_string_array(webhook_host_whitelist, "webhook_host_whitelist"))
155
+ end
156
+
157
+ def features= features
158
+ super(value_to_string_array(features, "features").collect(&:downcase))
159
+ end
160
+
161
+ def warning_error_classes
162
+ warning_error_class_names.collect do | class_name |
163
+ begin
164
+ Object.const_get(class_name)
165
+ rescue NameError => e
166
+ puts("Class #{class_name} couldn't be loaded as a warning error class (#{e.class} - #{e.message}). Ignoring.")
167
+ nil
168
+ end
169
+ end.compact
170
+ end
171
+
172
+ def validate_logging_attributes!
173
+ valid_log_streams = [:file, :stdout]
174
+ unless valid_log_streams.include?(log_stream)
175
+ raise_validation_error("log_stream must be one of: #{valid_log_streams.join(", ")}")
176
+ end
177
+
178
+ if log_stream == :file && log_dir.blank?
179
+ raise_validation_error("Must specify log_dir if log_stream is set to file")
180
+ end
181
+ end
182
+
183
+ def raise_validation_error(msg)
184
+ raise PactBroker::ConfigurationError, msg
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,41 @@
1
+ require "pact_broker/config/space_delimited_string_list"
2
+ require "pact_broker/config/space_delimited_integer_list"
3
+
4
+ module PactBroker
5
+ module Config
6
+ module RuntimeConfigurationCoercionMethods
7
+ def value_to_string_array value, property_name
8
+ if value.is_a?(String)
9
+ PactBroker::Config::SpaceDelimitedStringList.parse(value)
10
+ elsif value.is_a?(Array)
11
+ # parse structured values to possible regexp
12
+ [*value].flat_map do | val |
13
+ if val.is_a?(String)
14
+ PactBroker::Config::SpaceDelimitedStringList.parse(val)
15
+ else
16
+ [val]
17
+ end
18
+ end
19
+ elsif value
20
+ raise ConfigurationError.new("Pact Broker configuration property `#{property_name}` must be a space delimited String or an Array. Got: #{value.inspect}")
21
+ end
22
+ end
23
+
24
+ private :value_to_string_array
25
+
26
+ def value_to_integer_array value, property_name
27
+ if value.is_a?(String)
28
+ PactBroker::Config::SpaceDelimitedIntegerList.parse(value)
29
+ elsif value.is_a?(Array)
30
+ value.collect { |v| v.to_i }
31
+ elsif value.is_a?(Integer)
32
+ [value]
33
+ elsif value
34
+ raise ConfigurationError.new("Pact Broker configuration property `#{property_name}` must be a space delimited String or an Array of Integers. Got: #{value.inspect}")
35
+ end
36
+ end
37
+
38
+ private :value_to_integer_array
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,119 @@
1
+ module PactBroker
2
+ module Config
3
+ module RuntimeConfigurationDatabaseMethods
4
+
5
+ # rubocop: disable Metrics/MethodLength
6
+ # rubocop: disable Metrics/CyclomaticComplexity
7
+ def self.included(anyway_config)
8
+ anyway_config.class_eval do
9
+
10
+ attr_config(
11
+ database_adapter: "postgres",
12
+ database_username: nil,
13
+ database_password: nil,
14
+ database_name: nil,
15
+ database_host: nil,
16
+ database_port: nil,
17
+ database_url: nil,
18
+ database_sslmode: nil,
19
+ sql_log_level: :debug,
20
+ sql_log_warn_duration: 5,
21
+ database_max_connections: nil,
22
+ database_pool_timeout: 5,
23
+ database_connect_max_retries: 0,
24
+ auto_migrate_db: true,
25
+ auto_migrate_db_data: true,
26
+ allow_missing_migration_files: true,
27
+ validate_database_connection_config: true,
28
+ database_statement_timeout: 15,
29
+ metrics_sql_statement_timeout: 30,
30
+ database_connection_validation_timeout: -1
31
+ )
32
+
33
+ def database_configuration
34
+ database_credentials
35
+ .merge(
36
+ encoding: "utf8",
37
+ sslmode: database_sslmode,
38
+ sql_log_level: sql_log_level,
39
+ log_warn_duration: sql_log_warn_duration,
40
+ max_connections: database_max_connections,
41
+ pool_timeout: database_pool_timeout,
42
+ driver_options: driver_options,
43
+ connect_max_retries: database_connect_max_retries,
44
+ connection_validation_timeout: database_connection_validation_timeout
45
+ ).compact
46
+ end
47
+
48
+ def database_connect_max_retries= database_connect_max_retries
49
+ super(database_connect_max_retries&.to_i)
50
+ end
51
+
52
+ def sql_log_level= sql_log_level
53
+ super(sql_log_level&.downcase&.to_sym)
54
+ end
55
+
56
+ def sql_log_warn_duration= sql_log_warn_duration
57
+ super(sql_log_warn_duration&.to_f)
58
+ end
59
+
60
+ def database_port= database_port
61
+ super(database_port&.to_i)
62
+ end
63
+
64
+ def metrics_sql_statement_timeout= metrics_sql_statement_timeout
65
+ super(metrics_sql_statement_timeout&.to_i)
66
+ end
67
+
68
+ def postgres?
69
+ database_credentials[:adapter] == "postgres"
70
+ end
71
+ private :postgres?
72
+
73
+ def driver_options
74
+ if postgres?
75
+ { options: "-c statement_timeout=#{database_statement_timeout}s" }
76
+ end
77
+ end
78
+ private :driver_options
79
+
80
+ def database_credentials
81
+ if database_url
82
+ database_configuration_from_url
83
+ else
84
+ database_configuration_from_parts
85
+ end
86
+ end
87
+ private :database_credentials
88
+
89
+ def database_configuration_from_parts
90
+ {
91
+ adapter: database_adapter,
92
+ user: database_username,
93
+ password: database_password,
94
+ host: database_host,
95
+ database: database_name,
96
+ database_port: database_port
97
+ }.compact
98
+ end
99
+ private :database_credentials
100
+
101
+ def database_configuration_from_url
102
+ uri = URI(database_url)
103
+ {
104
+ adapter: uri.scheme,
105
+ user: uri.user,
106
+ password: uri.password,
107
+ host: uri.host,
108
+ database: uri.path.sub(/^\//, ""),
109
+ port: uri.port&.to_i,
110
+ }.compact
111
+ end
112
+ private :database_configuration_from_url
113
+ end
114
+ end
115
+ # rubocop: enable Metrics/MethodLength
116
+ # rubocop: enable Metrics/CyclomaticComplexity
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,61 @@
1
+ require "uri"
2
+
3
+ module PactBroker
4
+ module Config
5
+ module RuntimeConfigurationLoggingMethods
6
+ module ClassMethods
7
+ def sensitive_values(*values)
8
+ @sensitive_values ||= []
9
+ if values
10
+ @sensitive_values.concat([*values])
11
+ else
12
+ @sensitive_values
13
+ end
14
+ end
15
+
16
+ def sensitive_value?(value)
17
+ sensitive_values.any? { |key| key == value || key == value.to_sym || key.kind_of?(Regexp) && key =~ value }
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def log_configuration(logger)
23
+ to_source_trace.sort_by { |key, _| key }.each { |key, value| log_config_inner(key, value, logger) }
24
+ end
25
+
26
+ def log_config_inner(key, value, logger)
27
+ if !value.has_key? :value
28
+ value.sort_by { |inner_key, _| inner_key }.each { |inner_key, inner_value| log_config_inner("#{key}.#{inner_key}", inner_value, logger) }
29
+ elsif self.class.sensitive_value?(key)
30
+ logger.info "#{key}=#{redact(key, value[:value])} source=#{value[:source]}"
31
+ else
32
+ logger.info "#{key}=#{value[:value]} source=#{value[:source]}"
33
+ end
34
+ end
35
+ private :log_config_inner
36
+
37
+ def redact name, value
38
+ if value && name.to_s.end_with?("_url")
39
+ begin
40
+ uri = URI(value)
41
+ uri.password = "*****"
42
+ uri.to_s
43
+ rescue StandardError
44
+ "*****"
45
+ end
46
+ elsif !value.nil?
47
+ "*****"
48
+ else
49
+ nil
50
+ end
51
+ end
52
+ private :redact
53
+ end
54
+
55
+ def self.included(receiver)
56
+ receiver.extend ClassMethods
57
+ receiver.send :include, InstanceMethods
58
+ end
59
+ end
60
+ end
61
+ end