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
@@ -8,6 +8,7 @@ require 'contrast/agent/thread/worker_thread'
8
8
  require 'contrast/agent/telemetry/telemetry'
9
9
  require 'contrast/agent/telemetry/exception'
10
10
  require 'contrast/utils/job_servers_running'
11
+ require 'contrast/agent/reporting/client/interface'
11
12
 
12
13
  module Contrast
13
14
  module Agent
@@ -46,6 +47,39 @@ module Contrast
46
47
  @enabled
47
48
  end
48
49
 
50
+ # In case of connection error, do not create the background thread or queue,
51
+ # as if the opt-out env var was set.
52
+ #
53
+ # @return [Boolean]
54
+ def ip_opt_out?
55
+ @_ip_opt_out ||= begin
56
+ test_conn = Contrast::Agent::Telemetry::Client.new.initialize_connection(URL)
57
+
58
+ if test_conn.nil? || Contrast::Utils::NetHttpBase.last_error
59
+ # log if error:
60
+ if defined?(Contrast) && defined?(Contrast::CONFIG) && defined?(Contrast::CONFIG)
61
+ Contrast::CONFIG.proto_logger.warn('[Telemetry] connection error disabling...',
62
+ error: Contrast::Utils::NetHttpBase.last_error)
63
+
64
+ end
65
+ # Disable telemetry:
66
+ @enabled = false
67
+ true
68
+ else
69
+ # Close the connection
70
+ test_conn.finish if test_conn.started?
71
+ false
72
+ end
73
+ end
74
+ rescue StandardError
75
+ @enabled = false
76
+ true
77
+ end
78
+
79
+ def disable!
80
+ @enabled = false
81
+ end
82
+
49
83
  private
50
84
 
51
85
  def telemetry_enabled?
@@ -56,26 +90,14 @@ module Contrast
56
90
 
57
91
  # In case of connection error, do not create the background thread or queue,
58
92
  # as if the opt-out env var was set
59
- @_client = Contrast::Agent::Telemetry::Client.new
60
- ip_opt_out_telemetry = @_client.initialize_connection(URL)
61
- if ip_opt_out_telemetry.nil?
62
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
63
- # an infinite loop w/ telemetry
64
- logger.debug("[Telemetry] Connection was not established properly!!! \n
65
- Telemetry reporting will be disabled!")
66
- return false
67
- end
93
+ return false if ip_opt_out?
68
94
 
69
95
  true
70
96
  end
71
97
  end
72
98
 
73
99
  def client
74
- @_client ||= Contrast::Agent::Telemetry::Client.new
75
- end
76
-
77
- def connection
78
- @_connection ||= client.initialize_connection(URL)
100
+ @_client ||= Contrast::Agent::Reporting::Telemetry::Interface.new
79
101
  end
80
102
 
81
103
  def attempt_to_start?
@@ -91,6 +113,7 @@ module Contrast
91
113
  end
92
114
 
93
115
  def start_thread!
116
+ return unless attempt_to_start?
94
117
  return if running?
95
118
 
96
119
  logger.debug('[Telemetry] Starting background telemetry thread.')
@@ -122,16 +145,24 @@ module Contrast
122
145
  Contrast::TELEMETRY_EXCEPTIONS&.clear
123
146
  end
124
147
 
125
- def request_with_response event
126
- client.handle_response(client.send_request(event, connection))
127
- end
128
-
129
148
  private
130
149
 
131
150
  def queue
132
151
  @_queue ||= Queue.new
133
152
  end
134
153
 
154
+ # Starts sending Telemetry messages.
155
+ def process_event event
156
+ logger.debug('[Telemetry] This is the current processed event', event)
157
+ if (sleep_time = client.request_with_response(event))
158
+ return sleep(sleep_time)
159
+ end
160
+
161
+ logger.debug('[Telemetry] Retrying to process event', event)
162
+ retry_sleep_time = client.request_with_response(event)
163
+ sleep(retry_sleep_time) unless retry_sleep_time.nil?
164
+ end
165
+
135
166
  # It is recommended that implementations send a single payload of general metrics every 3 hours, starting from
136
167
  # implementation startup. This returns a thread configured to do so.
137
168
  #
@@ -139,25 +170,18 @@ module Contrast
139
170
  def create_thread
140
171
  Contrast::Agent::Thread.new do
141
172
  loop do
142
- next unless client && connection
173
+ next unless client.connected?
174
+ break unless attempt_to_start?
143
175
 
144
176
  # Start pushing exceptions to queue for reporting.
145
- Contrast::TELEMETRY_EXCEPTIONS.each_value { |value| queue << value }
146
- Contrast::TELEMETRY_EXCEPTIONS.clear
177
+ Contrast::TELEMETRY_EXCEPTIONS&.each_value { |value| queue << value }
178
+ Contrast::TELEMETRY_EXCEPTIONS&.clear
147
179
  until queue.empty?
148
180
  event = queue.pop
149
181
  begin
150
- logger.debug('[Telemetry] This is the current processed event', event)
151
- if (sleep_time = request_with_response(event))
152
- sleep(sleep_time)
153
- logger.debug('[Telemetry] Retrying to process event', event)
154
- retry_sleep_time = request_with_response(event)
155
- sleep(retry_sleep_time) unless retry_sleep_time.nil?
156
- end
182
+ process_event(event)
157
183
  rescue StandardError => e
158
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
159
- # an infinite loop w/ telemetry
160
- logger.debug('[Telemetry] Could not send message to service from telemetry queue.', e)
184
+ logger.error('[Telemetry] Could not send message to service from telemetry queue.', e)
161
185
  stop!
162
186
  end
163
187
  end
@@ -100,9 +100,7 @@ module Contrast
100
100
  def get_event_json event
101
101
  Array(event.to_controlled_hash).to_json
102
102
  rescue Exception => e # rubocop:disable Lint/RescueException
103
- # TODO: RUBY-2033 we cannot log the error above debug level here b/c it results in
104
- # an infinite loop w/ telemetry
105
- logger.debug('[Telemetry] Unable to convert TelemetryEvent to JSON string', e, hsh)
103
+ logger.error('[Telemetry] Unable to convert TelemetryEvent to JSON string', e, hsh)
106
104
  raise(e)
107
105
  end
108
106
  end
@@ -0,0 +1,97 @@
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/duck_utils'
5
+ require 'contrast/utils/object_share'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Telemetry
10
+ module Exception
11
+ # Obfuscate sensitive user data before building exception.
12
+ module Obfuscate
13
+ CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.cs__freeze
14
+ # This will generate different chars for each agent startup but will be constant
15
+ # for current run and will make identical obfuscation to be compared if given type
16
+ # is the same.
17
+ CYPHER = CHARS.chars.shuffle.join.cs__freeze
18
+ VERSION_MATCH = '[^0-9].-'
19
+
20
+ # List of known places after witch a user name might appear:
21
+ KNOWN_DIRS = %w[app application project projects git github users home user].cs__freeze
22
+
23
+ class << self
24
+ # Returns paths for known gems.
25
+ #
26
+ # @return [Array<Regexp>] known paths
27
+ def known_paths
28
+ @_known_paths ||= KNOWN_DIRS.map do |name|
29
+ to_regexp(name)
30
+ end
31
+ end
32
+
33
+ # Obfuscate a type and replace it with random characters.
34
+ #
35
+ # @param path [String] the StackFrame type to obfuscate
36
+ # @return [String] obfuscated type
37
+ def obfuscate_path path
38
+ return path if Contrast::Utils::DuckUtils.empty_duck?(path)
39
+
40
+ cypher(path)
41
+ end
42
+
43
+ private
44
+
45
+ # Transforms string to regexp
46
+ #
47
+ # @param string [String]
48
+ def to_regexp string
49
+ /#{ string }/
50
+ end
51
+
52
+ # Add cypher to path to make it obscure, but unique enough for
53
+ # comparisons. Mutates original or duplicate if frozen string.
54
+ #
55
+ # @param string [String] string to be transformed.
56
+ # @return [String]
57
+ def cypher string
58
+ cypher = string.cs__frozen? ? string.dup : string
59
+ dirs = cypher.split(Contrast::Utils::ObjectShare::SLASH)
60
+ return string unless dirs.cs__is_a?(Array)
61
+
62
+ dirs.each_with_index do |name, idx|
63
+ next if Contrast::Utils::DuckUtils.empty_duck?(name)
64
+ next unless match_known(known_paths,
65
+ name.tr(VERSION_MATCH, Contrast::Utils::ObjectShare::EMPTY_STRING).downcase)
66
+
67
+ obscure(name)
68
+ # obscure username (next dir in line)
69
+ obscure(dirs[idx + 1]) if dirs[idx + 1]
70
+ end
71
+ cypher = dirs.join(Contrast::Utils::ObjectShare::SLASH)
72
+ return cypher if cypher
73
+
74
+ Contrast::Utils::ObjectShare::EMPTY_STRING
75
+ rescue StandardError
76
+ Contrast::Utils::ObjectShare::EMPTY_STRING
77
+ end
78
+
79
+ # @param known [Array<Regexp>] Array of regexp to match against
80
+ # @param type [String] type to check
81
+ def match_known known, type
82
+ known.any? { |regexp| type =~ regexp }
83
+ end
84
+
85
+ # Replaces chars in name.
86
+ #
87
+ # @param [string] name
88
+ # @return [String, nil]
89
+ def obscure name
90
+ name.to_s.tr!(CHARS, CYPHER)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -17,3 +17,4 @@ require 'contrast/agent/telemetry/exception/stack_frame'
17
17
  require 'contrast/agent/telemetry/exception/message_exception'
18
18
  require 'contrast/agent/telemetry/exception/message'
19
19
  require 'contrast/agent/telemetry/exception/event'
20
+ require 'contrast/agent/telemetry/exception/obfuscate'
@@ -92,13 +92,6 @@ module Contrast
92
92
  #
93
93
  # @return [Boolean]
94
94
  def telemetry_exceptions_enabled?
95
- opts_out_telemetry = return_value(:telemetry_opt_outs).to_s
96
- return false if opts_out_telemetry.casecmp?('true') || opts_out_telemetry == '1'
97
- # Double check if telemetry is enabled, this includes a check for Agent enable setting in the
98
- # config. In case of disabled Agent the queue won't be created and the Telemetry would not
99
- # be enabled. This check is here to prevent a loop of error creations that could no be added
100
- # to a queue ( because the client cannot be initialized if the Agent is disabled or settings are
101
- # missing).
102
95
  return false unless Contrast::Agent::Telemetry::Base.enabled?
103
96
 
104
97
  true
@@ -6,7 +6,7 @@ require 'contrast/agent/reporting/report'
6
6
  require 'contrast/agent/reporting/reporting_workers/reporting_workers'
7
7
  require 'contrast/agent/telemetry/base'
8
8
  require 'contrast/agent/protect/input_analyzer/worth_watching_analyzer'
9
- require 'contrast/config/diagnostics'
9
+ require 'contrast/config/diagnostics/monitor'
10
10
  require 'contrast/utils/job_servers_running'
11
11
 
12
12
  module Contrast
@@ -114,7 +114,7 @@ module Contrast
114
114
  def check_before_start
115
115
  return if Contrast::CONFIG.send(:validate)
116
116
 
117
- @_diagnostics = Contrast::Agent::DiagnosticsConfig::Diagnostics.new(Contrast::AGENT.logger.path ||
117
+ @_diagnostics = Contrast::Config::Diagnostics::Monitor.new(Contrast::AGENT.logger.path ||
118
118
  Contrast::Components::Config::CONTRAST_LOG)
119
119
  @_diagnostics.config.populate_fail_connection
120
120
  @_diagnostics.write_to_file_logic(false, reset: false)
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '7.0.0'
6
+ VERSION = '7.2.0'
7
7
  end
8
8
  end
@@ -137,7 +137,7 @@ module Contrast
137
137
  # Converts current configuration to effective config values class and appends them to
138
138
  # EffectiveConfig class.
139
139
  #
140
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
140
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
141
141
  def to_effective_config effective_config
142
142
  super
143
143
  logger&.to_effective_config(effective_config)
@@ -127,7 +127,7 @@ module Contrast
127
127
  # Converts current configuration to effective config values class and appends them to
128
128
  # EffectiveConfig class.
129
129
  #
130
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
130
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
131
131
  def to_effective_config effective_config
132
132
  add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CONTRAST)
133
133
  effective_proxy(effective_config)
@@ -137,7 +137,7 @@ module Contrast
137
137
 
138
138
  private
139
139
 
140
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
140
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
141
141
  def effective_proxy effective_config
142
142
  add_single_effective_value(effective_config, ENABLE, proxy_enable.to_s, PROXY_NAME, "#{ CONTRAST }.proxy")
143
143
  return unless proxy_url && proxy_enable
@@ -161,7 +161,7 @@ module Contrast
161
161
  # Converts current configuration to effective config values class and appends them to
162
162
  # EffectiveConfig class.
163
163
  #
164
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
164
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
165
165
  def to_effective_config effective_config
166
166
  super
167
167
  Contrast::CONFIG.server.to_effective_config(effective_config)
@@ -218,7 +218,7 @@ module Contrast
218
218
  # Converts current configuration to effective config values class and appends them to
219
219
  # EffectiveConfig class.
220
220
  #
221
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
221
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
222
222
  def to_effective_config effective_config
223
223
  super
224
224
  sampling&.to_effective_config(effective_config)
@@ -34,7 +34,7 @@ module Contrast
34
34
  # Converts current configuration to effective config values class and appends them to
35
35
  # EffectiveConfig class.
36
36
  #
37
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
37
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
38
38
  def to_effective_config effective_config
39
39
  add_single_effective_value(effective_config, SPEC_KEY.to_s, disabled_rules, canon_name, NAME_PREFIX)
40
40
  end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'contrast/config/diagnostics_tools'
4
+ require 'contrast/config/diagnostics/tools'
5
5
  require 'contrast/utils/object_share'
6
6
 
7
7
  module Contrast
@@ -9,7 +9,7 @@ module Contrast
9
9
  # All components should inherit from this,
10
10
  # whether Interfaces, InstanceMethods or ClassMethods.
11
11
  module ComponentBase
12
- include Contrast::Agent::DiagnosticsConfig::DiagnosticsTools
12
+ include Contrast::Config::Diagnostics::Tools
13
13
 
14
14
  CONTRAST = 'contrast'
15
15
  ENABLE = 'enable'
@@ -84,7 +84,7 @@ module Contrast
84
84
  # Converts current configuration to effective config values class and appends them to
85
85
  # EffectiveConfig class.
86
86
  #
87
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
87
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
88
88
  def to_effective_config effective_config
89
89
  add_effective_config_values(effective_config, config_values, canon_name, "#{ CONTRAST }.#{ canon_name }")
90
90
  end
@@ -11,11 +11,15 @@ module Contrast
11
11
  # This component encapsulates storing the source for each entry in the config,
12
12
  # so that we can report on where the value was set from.
13
13
  class Sources
14
- ENVIRONMENT = 'ENV'
15
- CLI = 'CLI'
16
- CONTRASTUI = 'ContrastUI'
17
- DEFAULT = 'Default'
18
- YAML = 'YAML'
14
+ ENVIRONMENT_VARIABLE = 'ENVIRONMENT_VARIABLE'
15
+ COMMAND_LINE = 'COMMAND_LINE'
16
+ CONTRAST_UI = 'CONTRAST_UI'
17
+ DEFAULT_VALUE = 'DEFAULT_VALUE'
18
+ APP_CONFIGURATION_FILE = 'USER_CONFIGURATION_FILE'
19
+ # Order matters for the Configurations files. This is read when Agent starts up and will always go
20
+ # through the YAML as priority.
21
+ # Do not change the order!
22
+ APP_CONFIGURATION_EXTENSIONS = %w[yaml yml].cs__freeze
19
23
 
20
24
  # @return [Hash]
21
25
  attr_reader :data
@@ -30,15 +34,15 @@ module Contrast
30
34
  # @param path [String] the canonical name for the config entry (such as api.proxy.enable)
31
35
  # @return [String] the source for the entry
32
36
  def get path
33
- data.dig(*parts_for(path)) || DEFAULT
37
+ data.dig(*parts_for(path)) || DEFAULT_VALUE
34
38
  rescue TypeError
35
- DEFAULT
39
+ DEFAULT_VALUE
36
40
  end
37
41
 
38
42
  # Assigns the config source for a specified config path.
39
43
  #
40
44
  # @param path [String] the canonical name for the config entry (such as api.proxy.enable)
41
- # @param [String] the source for the entry
45
+ # @param source[String] the source for the entry
42
46
  # @return [String] the source type for the entry
43
47
  def set path, source
44
48
  assign_value(data, parts_for(path), source)
@@ -64,7 +68,7 @@ module Contrast
64
68
  # @param current_level [Hash] all, or some of, the config source information
65
69
  # @param parts [Array] the parts for canonical name of the config entry
66
70
  # @param source [String] the source to be set for the specified entry
67
- # @return [Array] the path split on periods, and converted to symbols
71
+ # @return [String] the path split on periods, and converted to symbols
68
72
  def assign_value current_level, parts, source
69
73
  parts[0...-1].each do |segment|
70
74
  current_level[segment] ||= {}
@@ -4,7 +4,7 @@
4
4
  require 'contrast/utils/env_configuration_item'
5
5
  require 'ougai'
6
6
  require 'contrast/configuration'
7
- require 'contrast/config/diagnostics'
7
+ require 'contrast/config/diagnostics/monitor'
8
8
 
9
9
  module Contrast
10
10
  module Components
@@ -249,7 +249,7 @@ module Contrast
249
249
  return unless current_level.nil? == false && current_level.cs__respond_to?(dot_path_array[-1])
250
250
 
251
251
  current_level.send("#{ dot_path_array[-1] }=", value)
252
- sources.set(dot_path_array.join('.'), Contrast::Components::Config::Sources::ENVIRONMENT)
252
+ sources.set(dot_path_array.join('.'), Contrast::Components::Config::Sources::ENVIRONMENT_VARIABLE)
253
253
  end
254
254
  end
255
255
  end
@@ -130,7 +130,7 @@ module Contrast
130
130
  # Converts current configuration to effective config values class and appends them to
131
131
  # EffectiveConfig class.
132
132
  #
133
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
133
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
134
134
  def to_effective_config effective_config
135
135
  super
136
136
  protect_rules_to_effective_config(effective_config)
@@ -138,7 +138,7 @@ module Contrast
138
138
 
139
139
  private
140
140
 
141
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
141
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
142
142
  def protect_rules_to_effective_config effective_config
143
143
  return unless defend_rules
144
144
 
@@ -136,7 +136,7 @@ module Contrast
136
136
  # Converts current configuration to effective config values class and appends them to
137
137
  # EffectiveConfig class.
138
138
  #
139
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
139
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
140
140
  def to_effective_config effective_config
141
141
  confirm_sources
142
142
 
@@ -161,10 +161,11 @@ module Contrast
161
161
  # back to the default values.
162
162
  def confirm_sources
163
163
  if sampling_control[:enabled] == DEFAULT_SAMPLING_ENABLED
164
- Contrast::CONFIG.sources.set('assess.sampling.enable', Contrast::Components::Config::Sources::DEFAULT)
164
+ Contrast::CONFIG.sources.set('assess.sampling.enable', Contrast::Components::Config::Sources::DEFAULT_VALUE)
165
165
  end
166
166
  if sampling_control[:window] == DEFAULT_SAMPLING_WINDOW_MS
167
- Contrast::CONFIG.sources.set('assess.sampling.window_ms', Contrast::Components::Config::Sources::DEFAULT)
167
+ Contrast::CONFIG.sources.set('assess.sampling.window_ms',
168
+ Contrast::Components::Config::Sources::DEFAULT_VALUE)
168
169
  end
169
170
  {
170
171
  'baseline' => :baseline,
@@ -172,7 +173,8 @@ module Contrast
172
173
  'response_frequency' => :response_frequency
173
174
  }.each do |k, v|
174
175
  if sampling_control[v] == cs__class.cs__const_get("DEFAULT_SAMPLING_#{ v.upcase }")
175
- Contrast::CONFIG.sources.set("assess.sampling.#{ k }", Contrast::Components::Config::Sources::DEFAULT)
176
+ Contrast::CONFIG.sources.set("assess.sampling.#{ k }",
177
+ Contrast::Components::Config::Sources::DEFAULT_VALUE)
176
178
  end
177
179
  end
178
180
  end
@@ -5,6 +5,7 @@ require 'contrast/agent/excluder/excluder'
5
5
  require 'contrast/agent/reporting/settings/sensitive_data_masking'
6
6
  require 'contrast/components/config'
7
7
  require 'contrast/components/logger'
8
+ require 'contrast/utils/duck_utils'
8
9
 
9
10
  module Contrast
10
11
  module Components
@@ -219,6 +220,14 @@ module Contrast
219
220
  exclusions.input_exclusions.each do |exclusion|
220
221
  matchers << Contrast::Agent::ExclusionMatcher.new(exclusion)
221
222
  end
223
+ # Do not populate the matchers unless we have any. There are certain checks in
224
+ # SourceMethod that will safe-guard return if there are no exclusions received.
225
+ # The matching operation is expensive, and the excluder calls are made for each
226
+ # source, and we do not want to check for exclusions if they are empty. This is
227
+ # probably redundant as all exclusions default to empty, but will save useless
228
+ # new object creation at very least.
229
+ return if Contrast::Utils::DuckUtils.empty_duck?(matchers)
230
+
222
231
  @excluder = Contrast::Agent::Excluder.new(matchers)
223
232
  end
224
233
 
@@ -283,7 +292,7 @@ module Contrast
283
292
  return unless level.cs__is_a?(Hash)
284
293
 
285
294
  level[parts[-1]] = value
286
- Contrast::CONFIG.sources.set(parts.join('.'), Contrast::Components::Config::Sources::CONTRASTUI)
295
+ Contrast::CONFIG.sources.set(parts.join('.'), Contrast::Components::Config::Sources::CONTRAST_UI)
287
296
  end
288
297
  end
289
298
  end
@@ -38,7 +38,7 @@ module Contrast
38
38
  # Converts current configuration to effective config values class and appends them to
39
39
  # EffectiveConfig class.
40
40
  #
41
- # @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
41
+ # @param effective_config [Contrast::Config::Diagnostics::EffectiveConfig]
42
42
  def to_effective_config effective_config
43
43
  add_effective_config_values(effective_config, CONFIG_VALUES, CANON_NAME, CONTRAST)
44
44
  end
@@ -0,0 +1,47 @@
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/duck_utils'
5
+ require 'contrast/utils/object_share'
6
+ require 'contrast/components/config/sources'
7
+ require 'contrast/config/diagnostics/tools'
8
+
9
+ module Contrast
10
+ module Config
11
+ # This class will hold all the references for the configuration files. It will safe read values used to
12
+ # identify the source of configuration in Configuration Diagnostics reported to TS.
13
+ class ConfigurationFiles
14
+ # @return [String] path of the main configuration file.
15
+ attr_accessor :main_file
16
+
17
+ # @return [Array<Contrast::Config::LocalSourceValue>]
18
+ def source_files
19
+ @_source_files ||= []
20
+ end
21
+
22
+ # @param path [String]
23
+ # @param values [Hash]
24
+ def add_source_file path, values
25
+ source_files << Contrast::Config::LocalSourceValue.new(path, values)
26
+ @main_file = path if source_files.length == 1
27
+ end
28
+ end
29
+
30
+ # This class will hold all the info about the read file.
31
+ class LocalSourceValue
32
+ YML_EXT = '.yml'
33
+ YAML_EXT = '.yaml'
34
+ # @return [String]
35
+ attr_reader :path
36
+ # @return [Hash]
37
+ attr_reader :values
38
+
39
+ # @param path [String]
40
+ # @param values [Hash]
41
+ def initialize path = '', values = {}
42
+ @path = path unless Contrast::Utils::DuckUtils.empty_duck?(path)
43
+ @values = values
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
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/diagnostics/effective_config_value'
5
+ require 'contrast/config/diagnostics/tools'
6
+ require 'contrast/utils/object_share'
7
+
8
+ module Contrast
9
+ module Config
10
+ module Diagnostics
11
+ # Reads All ENV variables.
12
+ module CommandLine
13
+ class << self
14
+ def command_line_settings
15
+ cli = Contrast::Config::Diagnostics::Tools.flatten_settings(Contrast::CONFIG.sources.
16
+ for(Contrast::Components::Config::Sources::COMMAND_LINE))
17
+
18
+ Contrast::Config::Diagnostics::Tools.to_config_values(cli, source: true)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end