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.
- checksums.yaml +4 -4
- data/ext/extconf_common.rb +88 -14
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
- data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
- data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
- data/lib/contrast/agent/excluder/excluder.rb +64 -31
- data/lib/contrast/agent/patching/policy/policy.rb +2 -2
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
- data/lib/contrast/agent/protect/rule/base.rb +4 -6
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
- data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
- data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
- data/lib/contrast/agent/reporting/client/interface.rb +132 -0
- data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
- data/lib/contrast/agent/reporting/connection_status.rb +0 -1
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
- data/lib/contrast/agent/reporting/reporter.rb +23 -23
- data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +57 -12
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +55 -38
- data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -12
- data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
- data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
- data/lib/contrast/agent/request/request.rb +27 -12
- data/lib/contrast/agent/telemetry/base.rb +55 -31
- data/lib/contrast/agent/telemetry/client.rb +1 -3
- data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
- data/lib/contrast/agent/telemetry/exception.rb +1 -0
- data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
- data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/agent.rb +1 -1
- data/lib/contrast/components/api.rb +2 -2
- data/lib/contrast/components/app_context.rb +1 -1
- data/lib/contrast/components/assess.rb +1 -1
- data/lib/contrast/components/assess_rules.rb +1 -1
- data/lib/contrast/components/base.rb +3 -3
- data/lib/contrast/components/config/sources.rb +13 -9
- data/lib/contrast/components/config.rb +2 -2
- data/lib/contrast/components/protect.rb +2 -2
- data/lib/contrast/components/sampling.rb +6 -4
- data/lib/contrast/components/settings.rb +10 -1
- data/lib/contrast/config/certification_configuration.rb +1 -1
- data/lib/contrast/config/configuration_files.rb +47 -0
- data/lib/contrast/config/diagnostics/command_line.rb +24 -0
- data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
- data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
- data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
- data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
- data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
- data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
- data/lib/contrast/config/diagnostics/source_config_value.rb +55 -0
- data/lib/contrast/config/diagnostics/tools.rb +188 -0
- data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
- data/lib/contrast/config/request_audit_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/config/validate.rb +2 -2
- data/lib/contrast/configuration.rb +82 -57
- data/lib/contrast/framework/grape/support.rb +1 -2
- data/lib/contrast/framework/manager.rb +17 -8
- data/lib/contrast/framework/rack/support.rb +99 -1
- data/lib/contrast/framework/rails/support.rb +1 -2
- data/lib/contrast/framework/sinatra/support.rb +1 -2
- data/lib/contrast/logger/aliased_logging.rb +18 -9
- data/lib/contrast/utils/hash_utils.rb +62 -0
- data/lib/contrast/utils/json.rb +46 -0
- data/lib/contrast/utils/net_http_base.rb +75 -26
- data/lib/contrast/utils/request_utils.rb +14 -0
- data/resources/assess/policy.json +11 -0
- metadata +20 -8
- data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
- data/lib/contrast/config/diagnostics_tools.rb +0 -99
- data/lib/contrast/config/effective_config.rb +0 -131
- 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
|
-
|
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::
|
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
|
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
|
146
|
-
Contrast::TELEMETRY_EXCEPTIONS
|
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
|
-
|
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
|
-
|
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
|
-
|
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::
|
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)
|
@@ -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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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/
|
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::
|
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::
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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)) ||
|
37
|
+
data.dig(*parts_for(path)) || DEFAULT_VALUE
|
34
38
|
rescue TypeError
|
35
|
-
|
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 [
|
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::
|
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::
|
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::
|
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::
|
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::
|
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',
|
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 }",
|
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::
|
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::
|
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
|