contrast-agent 7.0.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/ext/extconf_common.rb +88 -14
  3. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  4. data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
  5. data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
  6. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  7. data/lib/contrast/agent/excluder/excluder.rb +64 -31
  8. data/lib/contrast/agent/patching/policy/policy.rb +2 -2
  9. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
  10. data/lib/contrast/agent/protect/rule/base.rb +4 -6
  11. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
  12. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
  13. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
  14. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
  15. data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
  16. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
  17. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
  19. data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
  20. data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
  21. data/lib/contrast/agent/reporting/client/interface.rb +132 -0
  22. data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
  23. data/lib/contrast/agent/reporting/connection_status.rb +0 -1
  24. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
  25. data/lib/contrast/agent/reporting/reporter.rb +23 -23
  26. data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
  27. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  28. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
  29. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
  30. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
  31. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +57 -12
  32. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +55 -38
  33. data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
  34. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
  35. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
  36. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -12
  37. data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
  38. data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
  39. data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
  40. data/lib/contrast/agent/request/request.rb +27 -12
  41. data/lib/contrast/agent/telemetry/base.rb +55 -31
  42. data/lib/contrast/agent/telemetry/client.rb +1 -3
  43. data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
  44. data/lib/contrast/agent/telemetry/exception.rb +1 -0
  45. data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
  46. data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
  47. data/lib/contrast/agent/version.rb +1 -1
  48. data/lib/contrast/components/agent.rb +1 -1
  49. data/lib/contrast/components/api.rb +2 -2
  50. data/lib/contrast/components/app_context.rb +1 -1
  51. data/lib/contrast/components/assess.rb +1 -1
  52. data/lib/contrast/components/assess_rules.rb +1 -1
  53. data/lib/contrast/components/base.rb +3 -3
  54. data/lib/contrast/components/config/sources.rb +13 -9
  55. data/lib/contrast/components/config.rb +2 -2
  56. data/lib/contrast/components/protect.rb +2 -2
  57. data/lib/contrast/components/sampling.rb +6 -4
  58. data/lib/contrast/components/settings.rb +10 -1
  59. data/lib/contrast/config/certification_configuration.rb +1 -1
  60. data/lib/contrast/config/configuration_files.rb +47 -0
  61. data/lib/contrast/config/diagnostics/command_line.rb +24 -0
  62. data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
  63. data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
  64. data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
  65. data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
  66. data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
  67. data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
  68. data/lib/contrast/config/diagnostics/source_config_value.rb +55 -0
  69. data/lib/contrast/config/diagnostics/tools.rb +188 -0
  70. data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
  71. data/lib/contrast/config/request_audit_configuration.rb +1 -1
  72. data/lib/contrast/config/server_configuration.rb +1 -1
  73. data/lib/contrast/config/validate.rb +2 -2
  74. data/lib/contrast/configuration.rb +82 -57
  75. data/lib/contrast/framework/grape/support.rb +1 -2
  76. data/lib/contrast/framework/manager.rb +17 -8
  77. data/lib/contrast/framework/rack/support.rb +99 -1
  78. data/lib/contrast/framework/rails/support.rb +1 -2
  79. data/lib/contrast/framework/sinatra/support.rb +1 -2
  80. data/lib/contrast/logger/aliased_logging.rb +18 -9
  81. data/lib/contrast/utils/hash_utils.rb +62 -0
  82. data/lib/contrast/utils/json.rb +46 -0
  83. data/lib/contrast/utils/net_http_base.rb +75 -26
  84. data/lib/contrast/utils/request_utils.rb +14 -0
  85. data/resources/assess/policy.json +11 -0
  86. metadata +20 -8
  87. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
  88. data/lib/contrast/config/diagnostics_tools.rb +0 -99
  89. data/lib/contrast/config/effective_config.rb +0 -131
  90. data/lib/contrast/config/effective_config_value.rb +0 -32
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'net/http'
5
+ require 'resolv'
5
6
  require 'contrast/components/logger'
6
7
  require 'contrast/utils/object_share'
7
8
  require 'socket'
@@ -10,8 +11,25 @@ module Contrast
10
11
  module Utils
11
12
  # This module creates a Net::HTTP client base to be used by different services
12
13
  # All HTTP clients reporting to Telemetry or TS should inherit from this
13
- class NetHttpBase
14
+ class NetHttpBase # rubocop:disable Metrics/ClassLength
14
15
  include Contrast::Components::Logger::InstanceMethods
16
+
17
+ class << self
18
+ # Last recorded error
19
+ # @return [StandardError]
20
+ def last_error
21
+ @_last_error
22
+ end
23
+
24
+ # @param [StandardError]
25
+ def last_error= error
26
+ @_last_error = error
27
+ end
28
+ end
29
+
30
+ # @return [String]
31
+ attr_reader :client_name
32
+
15
33
  # This method initializes the Net::HTTP client we'll need. it will validate
16
34
  # the connection and make the first request. If connection is valid and response
17
35
  # is available then the open connection is returned.
@@ -23,29 +41,22 @@ module Contrast
23
41
  # self signed certificates provided by config [default = false]
24
42
  # @return [Net::HTTP, nil] Return open connection or nil
25
43
  def initialize_connection service_name, url, use_proxy: false, use_custom_cert: false
26
- return unless url
27
-
28
- addr = URI(url)
29
- return if addr.host.nil? || addr.port.nil?
30
- return if addr.scheme != 'https' && !addr.host.to_s.include?('localhost')
31
-
32
- # the proxy is enabled only if there is provided url even if the enable is set to true
33
- proxy_addr = URI(Contrast::API.proxy_url) if proxy_enabled?
34
- net_http_client = initialize_client(addr, proxy_addr, use_proxy, use_custom_cert)
35
- return if net_http_client.nil?
36
-
37
- net_http_client.start
38
- return unless net_http_client.started?
44
+ Contrast::Utils::NetHttpBase.last_error = nil
45
+ @client_name = service_name
46
+ return unless (addr = retrieve_address(url))
47
+ return unless (net_http_client = configure_new_client(addr, use_proxy, use_custom_cert))
48
+ return unless client_started?(net_http_client)
39
49
 
40
- logger.debug("Starting #{ service_name } connection test")
50
+ logger.debug("Starting #{ client_name } connection test")
41
51
  return unless connection_verified?(net_http_client, url)
42
52
 
43
- logger.debug('Client verified', service: service_name, url: url)
53
+ logger.debug('Client verified', service: client_name, url: url)
44
54
  net_http_client
45
55
  rescue StandardError => e
46
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
47
- # an infinite loop w/ telemetry
48
- logger.debug('Connection failed', e, service: service_name, url: url)
56
+ Contrast::Utils::NetHttpBase.last_error = e
57
+ return if client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
58
+
59
+ logger.error('Connection failed', e, service: client_name, url: url)
49
60
  nil
50
61
  end
51
62
 
@@ -74,14 +85,51 @@ module Contrast
74
85
  Errno::ETIMEDOUT, Errno::ESHUTDOWN, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::EISCONN,
75
86
  Errno::ECONNABORTED, Errno::ENETRESET, Errno::ENETUNREACH => e
76
87
 
77
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
78
- # an infinite loop w/ telemetry
79
- logger.debug("#{ service_name } connection failed", e.message)
80
- false
88
+ Contrast::Utils::NetHttpBase.last_error = e
89
+ unless client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
90
+ logger.error("#{ client_name } connection failed", e.message)
91
+ end
92
+ @_connection_verified = false
81
93
  end
82
94
 
83
95
  private
84
96
 
97
+ # Starts connection and return started status.
98
+ #
99
+ # @param client [Net::HTTP] client instance.
100
+ # @return [Boolean] status indicates whether connection has started.
101
+ def client_started? client
102
+ return false unless client
103
+
104
+ client.start
105
+ client.started?
106
+ end
107
+
108
+ # @param url
109
+ # @return [URI::Generic, nil]
110
+ def retrieve_address url
111
+ return unless (addr = URI(url))
112
+ return if addr.host.nil? || addr.port.nil?
113
+ return if addr.scheme != 'https' && !addr.host.to_s.include?('localhost')
114
+
115
+ addr
116
+ end
117
+
118
+ # Assigns proxy and custom certificates if enabled, and initializes new client.
119
+ #
120
+ # @param addr [URI::Generic, nil]
121
+ # @param use_proxy [Boolean] flag used to indicate proxy connections [default = false]
122
+ # @param use_custom_cert [Boolean] flag used to indicate whether the client is to use
123
+ # @return client [Net::HTTP, nil] initialized client.
124
+ def configure_new_client addr, use_proxy, use_custom_cert
125
+ # the proxy is enabled only if there is provided url even if the enable is set to true
126
+ proxy_addr = URI(Contrast::API.proxy_url) if proxy_enabled?
127
+ net_http_client = initialize_client(addr, proxy_addr, use_proxy, use_custom_cert)
128
+ return if net_http_client.nil?
129
+
130
+ net_http_client
131
+ end
132
+
85
133
  # Resolves the address of the assigned domain to array of corresponding IPs (if more than one)
86
134
  # and runs a matcher to see if current connection IP is in the list.
87
135
  # This is called within #verify_connection, if called on it's own there will be no
@@ -114,9 +162,10 @@ module Contrast
114
162
  client.key = OpenSSL::PKey::RSA.new(File.read(Contrast::API.certification_key_file)).to_s
115
163
  end
116
164
  rescue Errno::ENOENT => e
117
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
118
- # an infinite loop w/ telemetry
119
- logger.debug('Custom certificates failed', e.message)
165
+ Contrast::Utils::NetHttpBase.last_error = e
166
+ unless client_name == Contrast::Agent::Telemetry::Client::SERVICE_NAME
167
+ logger.error('Custom certificates failed', e.message)
168
+ end
120
169
  end
121
170
 
122
171
  # sets default setting for client validation of certificates and
@@ -5,6 +5,20 @@ module Contrast
5
5
  module Utils
6
6
  # used in Contrast::Agent::Request
7
7
  module RequestUtils
8
+ # TOKENS:
9
+ NUM_ = '/{n}/'
10
+ ID_ = '{ID}'
11
+ # PATTERNS:
12
+ NUM_PATTERN = %r{/\d+/}.cs__freeze
13
+ END_PATTERN = %r{/\d+$}.cs__freeze
14
+ STATIC_SUFFIXES = /\.(?:js|css|jpeg|jpg|gif|png|ico|woff|svg|pdf|eot|ttf|jar)$/i.cs__freeze
15
+ UUID_PATTERN = Regexp.new('[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}').cs__freeze # rubocop:disable Metrics/LineLength
16
+ # Regular expression to match any type of hash pattern that is 16 bytes like uuid with no
17
+ # slashes, md5, sha1, sha256, etc
18
+ HASH_PATTERN = Regexp.new('([a-fA-F0-9]{2}){16,}').cs__freeze
19
+ WIN_PATTERN = Regexp.new('S-1-5-((32-\d+)|(21-\d+-\d+-\d+-\d+))').cs__freeze
20
+ MEDIA_TYPE_MARKERS = %w[image/ text/css text/javascript].cs__freeze
21
+
8
22
  # Return a flattened hash of params with realized paths for keys, in
9
23
  # addition to a separate, valueless, entry for each nest key.
10
24
  # See RUBY-621 for more details.
@@ -1258,6 +1258,17 @@
1258
1258
  "tags":["HTML_ENCODED"],
1259
1259
  "untags":["HTML_DECODED"]
1260
1260
  },
1261
+ {
1262
+ "class_name": "Rails::HTML::Concern::ComposedSanitize",
1263
+ "method_name": "sanitize",
1264
+ "method_visibility": "public",
1265
+ "instance_method": true,
1266
+ "source": "P0",
1267
+ "target": "R",
1268
+ "action": "REMOVE",
1269
+ "tags":["HTML_ENCODED"],
1270
+ "untags":["HTML_DECODED"]
1271
+ },
1261
1272
  {
1262
1273
  "class_name": "Rails::Html::SafeListSanitizer",
1263
1274
  "method_name": "sanitize",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrast-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.0
4
+ version: 7.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - galen.palmer@contrastsecurity.com
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: exe
15
15
  cert_chain: []
16
- date: 2023-04-03 00:00:00.000000000 Z
16
+ date: 2023-05-31 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: bundler
@@ -1051,6 +1051,8 @@ files:
1051
1051
  - lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb
1052
1052
  - lib/contrast/agent/reporting/attack_result/response_type.rb
1053
1053
  - lib/contrast/agent/reporting/attack_result/user_input.rb
1054
+ - lib/contrast/agent/reporting/client/interface.rb
1055
+ - lib/contrast/agent/reporting/client/interface_base.rb
1054
1056
  - lib/contrast/agent/reporting/connection_status.rb
1055
1057
  - lib/contrast/agent/reporting/details/bot_blocker_details.rb
1056
1058
  - lib/contrast/agent/reporting/details/cmd_injection_details.rb
@@ -1069,7 +1071,6 @@ files:
1069
1071
  - lib/contrast/agent/reporting/details/xxe_details.rb
1070
1072
  - lib/contrast/agent/reporting/details/xxe_match.rb
1071
1073
  - lib/contrast/agent/reporting/details/xxe_wrapper.rb
1072
- - lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb
1073
1074
  - lib/contrast/agent/reporting/input_analysis/details/protect_rule_details.rb
1074
1075
  - lib/contrast/agent/reporting/input_analysis/input_analysis.rb
1075
1076
  - lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb
@@ -1079,6 +1080,7 @@ files:
1079
1080
  - lib/contrast/agent/reporting/masker/masker_utils.rb
1080
1081
  - lib/contrast/agent/reporting/report.rb
1081
1082
  - lib/contrast/agent/reporting/reporter.rb
1083
+ - lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb
1082
1084
  - lib/contrast/agent/reporting/reporting_events/agent_startup.rb
1083
1085
  - lib/contrast/agent/reporting/reporting_events/application_activity.rb
1084
1086
  - lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb
@@ -1129,6 +1131,7 @@ files:
1129
1131
  - lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb
1130
1132
  - lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb
1131
1133
  - lib/contrast/agent/reporting/reporting_utilities/reporting_storage.rb
1134
+ - lib/contrast/agent/reporting/reporting_utilities/resend.rb
1132
1135
  - lib/contrast/agent/reporting/reporting_utilities/response.rb
1133
1136
  - lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb
1134
1137
  - lib/contrast/agent/reporting/reporting_utilities/response_handler.rb
@@ -1180,6 +1183,7 @@ files:
1180
1183
  - lib/contrast/agent/telemetry/exception/event.rb
1181
1184
  - lib/contrast/agent/telemetry/exception/message.rb
1182
1185
  - lib/contrast/agent/telemetry/exception/message_exception.rb
1186
+ - lib/contrast/agent/telemetry/exception/obfuscate.rb
1183
1187
  - lib/contrast/agent/telemetry/exception/stack_frame.rb
1184
1188
  - lib/contrast/agent/telemetry/hash.rb
1185
1189
  - lib/contrast/agent/telemetry/identifier.rb
@@ -1224,11 +1228,17 @@ files:
1224
1228
  - lib/contrast/config/api_proxy_configuration.rb
1225
1229
  - lib/contrast/config/base_configuration.rb
1226
1230
  - lib/contrast/config/certification_configuration.rb
1227
- - lib/contrast/config/config.rb
1228
- - lib/contrast/config/diagnostics.rb
1229
- - lib/contrast/config/diagnostics_tools.rb
1230
- - lib/contrast/config/effective_config.rb
1231
- - lib/contrast/config/effective_config_value.rb
1231
+ - lib/contrast/config/configuration_files.rb
1232
+ - lib/contrast/config/diagnostics/command_line.rb
1233
+ - lib/contrast/config/diagnostics/config.rb
1234
+ - lib/contrast/config/diagnostics/contrast_ui.rb
1235
+ - lib/contrast/config/diagnostics/effective_config.rb
1236
+ - lib/contrast/config/diagnostics/effective_config_value.rb
1237
+ - lib/contrast/config/diagnostics/environment_variables.rb
1238
+ - lib/contrast/config/diagnostics/monitor.rb
1239
+ - lib/contrast/config/diagnostics/source_config_value.rb
1240
+ - lib/contrast/config/diagnostics/tools.rb
1241
+ - lib/contrast/config/diagnostics/user_configuration_file.rb
1232
1242
  - lib/contrast/config/env_variables.rb
1233
1243
  - lib/contrast/config/exception_configuration.rb
1234
1244
  - lib/contrast/config/protect_rule_configuration.rb
@@ -1297,12 +1307,14 @@ files:
1297
1307
  - lib/contrast/utils/findings.rb
1298
1308
  - lib/contrast/utils/hash_digest.rb
1299
1309
  - lib/contrast/utils/hash_digest_extend.rb
1310
+ - lib/contrast/utils/hash_utils.rb
1300
1311
  - lib/contrast/utils/head_dump_utils_extend.rb
1301
1312
  - lib/contrast/utils/heap_dump_util.rb
1302
1313
  - lib/contrast/utils/input_classification_base.rb
1303
1314
  - lib/contrast/utils/invalid_configuration_util.rb
1304
1315
  - lib/contrast/utils/io_util.rb
1305
1316
  - lib/contrast/utils/job_servers_running.rb
1317
+ - lib/contrast/utils/json.rb
1306
1318
  - lib/contrast/utils/log_utils.rb
1307
1319
  - lib/contrast/utils/lru_cache.rb
1308
1320
  - lib/contrast/utils/metrics_hash.rb
@@ -1,27 +0,0 @@
1
- # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
- # frozen_string_literal: true
3
-
4
- require 'contrast/agent/reporting/input_analysis/details/protect_rule_details'
5
-
6
- module Contrast
7
- module Agent
8
- module Reporting
9
- # Bot blocker IA result details info.
10
- class BotBlockerDetails < ProtectRuleDetails
11
- # @return [String]
12
- attr_accessor :bot
13
- # User agent header value
14
- #
15
- # @return [String]
16
- attr_accessor :user_agent
17
-
18
- def to_controlled_hash
19
- {
20
- bot: bot,
21
- userAgent: user_agent
22
- }
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,99 +0,0 @@
1
- # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
- # frozen_string_literal: true
3
-
4
- require 'contrast/utils/object_share'
5
- require 'contrast/config/effective_config_value'
6
-
7
- module Contrast
8
- module Agent
9
- module DiagnosticsConfig
10
- # Diagnostics tools to be included in config components.
11
- module DiagnosticsTools
12
- CHECK = 'd'
13
-
14
- # Converts current configuration for array of values to effective config values class and appends them to
15
- # EffectiveConfig class. Must be used inside Config Components only.
16
- #
17
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
18
- # @param config_values [Array<String>] array of the names of values.
19
- # @param canonical_prefix [String] starting of the path to config => api.proxy...
20
- # @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
21
- def add_effective_config_values effective_config, config_values, canonical_prefix, name_prefix
22
- return if config_values.to_s.empty?
23
-
24
- config_values.each do |config|
25
- Contrast::Agent::DiagnosticsConfig::EffectiveConfigValue.new.tap do |value|
26
- next if (config_val = send(config.to_sym)).to_s.empty?
27
-
28
- config_name = assign_name(config)
29
- value.canonical_name = "#{ canonical_prefix }.#{ config_name }"
30
- value.name = "#{ name_prefix }.#{ config_name }"
31
- value.value = config_val
32
- value.source = Contrast::CONFIG.sources.get(value.canonical_name)
33
- if value.source == Contrast::Components::Config::Sources::YAML
34
- value.filename = Contrast::CONFIG.config_file_path
35
- end
36
- effective_config.values << value
37
- rescue StandardError => e
38
- log_error(e)
39
- next
40
- end
41
- end
42
- end
43
-
44
- # Converts current configuration for single value to effective config values class and appends them to
45
- # EffectiveConfig class. Must be used inside Config Components only.
46
- #
47
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
48
- # @param config_name [String] name of the config.
49
- # @param config_value [String, Boolean] value of the config.
50
- # @param canonical_prefix [String] starting of the path to config => api.proxy...
51
- # @param name_prefix [String] the name of the config prefix => contrast.api_key, contrast.url
52
- def add_single_effective_value effective_config, config_name, config_value, canonical_prefix, name_prefix
53
- Contrast::Agent::DiagnosticsConfig::EffectiveConfigValue.new.tap do |value|
54
- break if config_value.to_s.empty?
55
-
56
- value.value = config_value
57
- value.canonical_name = "#{ canonical_prefix }.#{ config_name }"
58
- value.name = "#{ name_prefix }.#{ config_name }"
59
- value.source = Contrast::CONFIG.sources.get(value.canonical_name)
60
- if value.source == Contrast::Components::Config::Sources::YAML
61
- value.filename = Contrast::CONFIG.config_file_path
62
- end
63
- effective_config.values << value
64
- rescue StandardError => e
65
- log_error(e)
66
- next
67
- end
68
- end
69
-
70
- private
71
-
72
- # Assigns a proper name for the config removing '?' out of method names.
73
- #
74
- # @param config [String] name of the configuration
75
- # @return [String]
76
- def assign_name config
77
- return Contrast::Utils::ObjectShare::EMPTY_STRING unless config
78
-
79
- name = config.dup
80
- if name.end_with?(Contrast::Utils::ObjectShare::QUESTION_MARK)
81
- # check and remove '?' : start_bundled_service? => start_bundled_service
82
- name.delete!(Contrast::Utils::ObjectShare::QUESTION_MARK)
83
- name.chop! if name.end_with?(CHECK)
84
- name
85
- end
86
- name
87
- end
88
-
89
- # Logs any caught error.
90
- #
91
- # @param error [StandardError]
92
- def log_error error
93
- Contrast::CONFIG.proto_logger.warn('Could not write effective config to file: ',
94
- error: error, backtrace: error.backtrace)
95
- end
96
- end
97
- end
98
- end
99
- end
@@ -1,131 +0,0 @@
1
- # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
- # frozen_string_literal: true
3
-
4
- require 'contrast/config/effective_config_value'
5
- require 'contrast/config/diagnostics_tools'
6
- require 'contrast/utils/object_share'
7
-
8
- module Contrast
9
- module Agent
10
- module DiagnosticsConfig
11
- # The current effective config received from all authorized configuration channels.
12
- class EffectiveConfig
13
- NON_COMMON_ENV = %w[CONTRAST_CONFIG_PATH CONTRAST_AGENT_TELEMETRY_OPTOUT].cs__freeze
14
-
15
- # Value of effective agent configurations
16
- #
17
- # @return [Array]
18
- attr_reader :values
19
-
20
- def initialize
21
- @values = []
22
- end
23
-
24
- def to_controlled_hash
25
- {
26
- effective_config: { values: @values&.map(&:to_controlled_hash) },
27
- user_configuration_file: yaml_config_settings,
28
- environment_variable: environment_settings(ENV).map(&:to_controlled_hash),
29
- command_line: command_line_settings.map(&:to_controlled_hash),
30
- contrast_ui: contrast_ui_settings.map(&:to_controlled_hash)
31
- }
32
- end
33
-
34
- private
35
-
36
- def yaml_config_settings
37
- {
38
- path: Contrast::CONFIG.config_file_path,
39
- values: value_to_s(Contrast::CONFIG.sources.for(Contrast::Components::Config::Sources::YAML))
40
- }
41
- end
42
-
43
- def command_line_settings
44
- cli = flatten_settings(Contrast::CONFIG.sources.for(Contrast::Components::Config::Sources::CLI))
45
- flat_settings(cli)
46
- end
47
-
48
- def contrast_ui_settings
49
- ui = flatten_settings(Contrast::CONFIG.sources.for(Contrast::Components::Config::Sources::CONTRASTUI))
50
- flat_settings(ui)
51
- end
52
-
53
- # @param flats [Array] of flatten configs produced by #flatten_settings
54
- # @return [Array]
55
- def flat_settings flats
56
- ui_settings = []
57
- flats.each do |entry|
58
- entry.each do |key, value|
59
- efc_value = Contrast::Agent::DiagnosticsConfig::EffectiveConfigValue.new.tap do |effective_value|
60
- effective_value.canonical_name = Contrast::Utils::ObjectShare::CONTRAST_DOT + key
61
- effective_value.name = key
62
- effective_value.value = value_to_s(value)
63
- end
64
- ui_settings << efc_value if efc_value
65
- end
66
- end
67
- ui_settings
68
- end
69
-
70
- def flatten_settings data, path = []
71
- data.each_with_object([]) do |(k, v), entries|
72
- if v.cs__is_a?(Hash)
73
- entries.concat(flatten_settings(v, path.dup.append(k.to_sym)))
74
- else
75
- entries << { "#{ path.join('.') }.#{ k }" => Contrast::CONFIG.config.loaded_config.dig(*path, k).to_s }
76
- end
77
- end.flatten # rubocop:disable Style/MethodCalledOnDoEndBlock
78
- end
79
-
80
- # This method will fill the canonical name for each env var and will check for any uncommon ones.
81
- #
82
- # @param env [Hash]
83
- # @return [Array] array of all the values needed to be written.
84
- def environment_settings env
85
- env_hash = env.select do |e|
86
- e.to_s.start_with?(Contrast::Components::Config::CONTRAST_ENV_MARKER) || NON_COMMON_ENV.include?(e.to_s)
87
- end
88
- environment_settings = []
89
- env_hash.each do |key, value|
90
- efc_value = Contrast::Agent::DiagnosticsConfig::EffectiveConfigValue.new.tap do |effective_value|
91
- next unless value
92
-
93
- effective_value.canonical_name = if NON_COMMON_ENV.include?(key)
94
- key.gsub(Contrast::Utils::ObjectShare::UNDERSCORE,
95
- Contrast::Utils::ObjectShare::PERIOD).downcase
96
- else
97
- key.gsub(Contrast::Utils::ObjectShare::DOUBLE_UNDERSCORE,
98
- Contrast::Utils::ObjectShare::PERIOD).downcase
99
- end
100
- if effective_value.canonical_name
101
- effective_value.name =
102
- effective_value.canonical_name.gsub(Contrast::Utils::ObjectShare::CONTRAST_DOT,
103
- Contrast::Utils::ObjectShare::EMPTY_STRING)
104
- end
105
- effective_value.value = value_to_s(value)
106
- end
107
- environment_settings << efc_value if efc_value
108
- end
109
- environment_settings
110
- end
111
-
112
- # Recursively converts each value to string.
113
- #
114
- # @param value [Hash]
115
- def value_to_s value
116
- return value if value.cs__is_a?(String)
117
-
118
- value.each_with_object({}) do |(k, v), m| # rubocop:disable Style/HashTransformValues
119
- m[k] = if v.cs__is_a?(Hash)
120
- value_to_s(v)
121
- elsif v.cs__is_a?(Array)
122
- v.map(&:to_s)
123
- else
124
- v.to_s
125
- end
126
- end
127
- end
128
- end
129
- end
130
- end
131
- end
@@ -1,32 +0,0 @@
1
- # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
- # frozen_string_literal: true
3
-
4
- module Contrast
5
- module Agent
6
- module DiagnosticsConfig
7
- # All In effect config values stored in a easy to write representation.
8
- class EffectiveConfigValue
9
- # @return [String] Name of the config starting form root of yaml config.
10
- attr_accessor :canonical_name
11
- # @return [String] Name of the config.
12
- attr_accessor :name
13
- # @return [String] Value set for the config.
14
- attr_accessor :value
15
- # @return [String] The source for the entry in the config.
16
- attr_accessor :source
17
- # @return [String,nil] The filename for the source of the config, if the source was "yaml".
18
- attr_accessor :filename
19
-
20
- def to_controlled_hash
21
- {
22
- canonical_name: canonical_name,
23
- name: name, # rubocop:disable Security/Module/Name
24
- value: value&.cs__is_a?(Array) ? value.map(&:to_s) : value.to_s,
25
- source: source,
26
- filename: filename
27
- }.compact
28
- end
29
- end
30
- end
31
- end
32
- end