contrast-agent 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
- 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/no_sqli/no_sqli.rb +1 -1
- data/lib/contrast/agent/reporting/reporter.rb +19 -4
- data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
- 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 +11 -7
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +15 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +2 -1
- 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/telemetry/base.rb +37 -12
- data/lib/contrast/agent/telemetry/client.rb +1 -3
- 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 +12 -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 +1 -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 +51 -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/configuration.rb +90 -57
- data/lib/contrast/utils/hash_utils.rb +43 -0
- data/lib/contrast/utils/json.rb +46 -0
- data/lib/contrast/utils/net_http_base.rb +75 -26
- metadata +16 -7
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81222798666699f86b31b925d531d2ee2229eb7934582d2a502cc61de3ca4e0b
|
4
|
+
data.tar.gz: 7dd4d41a58600b7d57b5f57cf95c42bd2f6d198f5f1906e93751e33c09efa3e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02e5d3aa6b342e8c4277ad6cefde65819aed6f6b4a1079cfe7528fcce236ec702aa8a63fc756c403c0df6e3ef38d5d25dc9f1c6e5c450d272122d699b6fd9872
|
7
|
+
data.tar.gz: 9cc83b5f69edeea949784ae766be7e02c1d589e58b2af5b5c1bd7975dcee1450d294bc7de647f60a9a3f18a1ea05a43bfe452a52d4760ed1b1cfcb0a7339a6ab
|
@@ -58,7 +58,7 @@ module Contrast
|
|
58
58
|
# can skip policy loading.
|
59
59
|
return if disabled_globally?
|
60
60
|
|
61
|
-
policy_data =
|
61
|
+
policy_data = Contrast::Utils::Json.parse(string)
|
62
62
|
|
63
63
|
policy_data[SOURCES_KEY].each do |source_hash|
|
64
64
|
source = Contrast::Agent::Assess::Policy::SourceNode.new(source_hash)
|
@@ -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 'json'
|
4
|
+
require 'contrast/utils/json'
|
5
5
|
require 'singleton'
|
6
6
|
|
7
7
|
require 'contrast'
|
@@ -71,7 +71,7 @@ module Contrast
|
|
71
71
|
# it, so in that case, we can skip policy loading.
|
72
72
|
return if disabled_globally?
|
73
73
|
|
74
|
-
policy_data =
|
74
|
+
policy_data = Contrast::Utils::Json.parse(string)
|
75
75
|
|
76
76
|
policy_data[RULES_KEY].each do |rule_hash|
|
77
77
|
rule_hash[TRIGGERS_KEY].each do |trigger_hash|
|
@@ -26,11 +26,14 @@ module Contrast
|
|
26
26
|
# Thread that will process all the InputAnalysisResults that have a score level of WORTHWATCHING and
|
27
27
|
# sends results to TeamServer
|
28
28
|
def start_thread!
|
29
|
+
return unless attempt_to_start?
|
29
30
|
return if running?
|
30
31
|
|
31
32
|
@_thread = Contrast::Agent::Thread.new do
|
32
33
|
logger.info('[WorthWatchingAnalyzer] Starting thread.')
|
33
34
|
loop do
|
35
|
+
break unless attempt_to_start?
|
36
|
+
|
34
37
|
sleep(REPORT_INTERVAL_SECOND)
|
35
38
|
next if queue.empty?
|
36
39
|
|
@@ -10,10 +10,12 @@ require 'contrast/agent/telemetry/exception'
|
|
10
10
|
module Contrast
|
11
11
|
module Agent
|
12
12
|
# This module will hold everything essential to reporting to TeamServer
|
13
|
-
class Reporter < WorkerThread
|
13
|
+
class Reporter < WorkerThread # rubocop:disable Metrics/ClassLength
|
14
14
|
include Contrast::Components::Logger::InstanceMethods
|
15
15
|
include Contrast::Utils::ObjectShare
|
16
16
|
|
17
|
+
# How many tries to reconnect the Reporter should make.
|
18
|
+
RETRY_ATTEMPTS = 10
|
17
19
|
MAX_QUEUE_SIZE = 1000
|
18
20
|
|
19
21
|
class << self
|
@@ -35,13 +37,17 @@ module Contrast
|
|
35
37
|
end
|
36
38
|
|
37
39
|
def start_thread!
|
40
|
+
return unless attempt_to_start?
|
38
41
|
return if running?
|
39
42
|
|
43
|
+
@connection_attempts = 0
|
44
|
+
|
40
45
|
client.startup!(connection)
|
41
46
|
@_thread = Contrast::Agent::Thread.new do
|
42
47
|
logger.debug('[Reporter] Starting background Reporter thread.')
|
43
48
|
loop do
|
44
49
|
next unless connected?
|
50
|
+
break unless attempt_to_start?
|
45
51
|
|
46
52
|
process_event(queue.pop)
|
47
53
|
rescue StandardError => e
|
@@ -124,10 +130,19 @@ module Contrast
|
|
124
130
|
#
|
125
131
|
# @return [Boolean]
|
126
132
|
def connected?
|
127
|
-
|
133
|
+
if client && connection
|
134
|
+
# Try to resend startup messages now with connection:
|
135
|
+
client.startup!(connection) unless client.status.startup_messages_sent?
|
136
|
+
return true
|
137
|
+
end
|
128
138
|
|
129
|
-
logger.debug('[Reporter] No client/connection; sleeping...'
|
130
|
-
|
139
|
+
logger.debug('[Reporter] No client/connection; sleeping...')
|
140
|
+
@connection_attempts += 1
|
141
|
+
if @connection_attempts >= RETRY_ATTEMPTS
|
142
|
+
logger.debug('[Reporter] shutting down..')
|
143
|
+
Contrast::AGENT.disable!
|
144
|
+
end
|
145
|
+
sleep(5) unless Contrast::AGENT.disabled?
|
131
146
|
false
|
132
147
|
end
|
133
148
|
|
@@ -0,0 +1,32 @@
|
|
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/reporting_events/reporting_event'
|
5
|
+
require 'contrast/config'
|
6
|
+
|
7
|
+
module Contrast
|
8
|
+
module Agent
|
9
|
+
module Reporting
|
10
|
+
# AgentStartup Event which sends the agent data to TeamServer on the startup of a server or process,
|
11
|
+
# used to create a new Server entity there.
|
12
|
+
class AgentEffectiveConfig < Contrast::Agent::Reporting::ReportingEvent
|
13
|
+
# @param diagnostics [Contrast::Agent::DiagnosticsConfig::Diagnostics] current diagnostics
|
14
|
+
def initialize diagnostics
|
15
|
+
@event_method = :PUT
|
16
|
+
@event_endpoint = Contrast::Agent::Reporting::Endpoints.effective_config
|
17
|
+
@event_type = :effective_config
|
18
|
+
@diagnostics = diagnostics
|
19
|
+
super()
|
20
|
+
end
|
21
|
+
|
22
|
+
def file_name
|
23
|
+
'agent-effective-config'
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_controlled_hash
|
27
|
+
@diagnostics.to_controlled_hash
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -83,6 +83,13 @@ module Contrast
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
# @return [String, nil]
|
87
|
+
def effective_config
|
88
|
+
with_rescue do
|
89
|
+
"#{ application_endpoint }/effective-config".cs__freeze
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
86
93
|
private
|
87
94
|
|
88
95
|
# Returns the URL needed to connect to endpoints in TeamServer required for application related information.
|
@@ -11,7 +11,7 @@ module Contrast
|
|
11
11
|
# This class will build the required headers for agent reporting to TS
|
12
12
|
class Headers
|
13
13
|
attr_reader :app_name, :api_key, :agent_version, :app_language, :app_path, :app_version, :authorization,
|
14
|
-
:server_name, :server_path, :server_type, :content_type, :encoding, :compression
|
14
|
+
:server_name, :server_path, :server_type, :content_type, :encoding, :compression, :session_id
|
15
15
|
|
16
16
|
include Contrast::Utils::ObjectShare
|
17
17
|
ENCODING = 'base64'
|
@@ -29,6 +29,7 @@ module Contrast
|
|
29
29
|
@server_name = Base64.strict_encode64(Contrast::APP_CONTEXT.server_name)
|
30
30
|
@server_path = Base64.strict_encode64(Contrast::APP_CONTEXT.server_path)
|
31
31
|
@server_type = Base64.strict_encode64(Contrast::APP_CONTEXT.server_type)
|
32
|
+
@session_id = Contrast::CONFIG.session_id
|
32
33
|
@content_type = CONTENT_TYPE
|
33
34
|
@encoding = ENCODING
|
34
35
|
@compression = COMPRESSION
|
@@ -46,6 +47,7 @@ module Contrast
|
|
46
47
|
server_name: @server_name,
|
47
48
|
server_path: @server_path,
|
48
49
|
server_type: @server_type,
|
50
|
+
'Session-ID': @session_id,
|
49
51
|
content_type: @content_type,
|
50
52
|
encoding: @encoding,
|
51
53
|
compression: @compression
|
@@ -5,14 +5,15 @@ require 'json'
|
|
5
5
|
require 'net/http'
|
6
6
|
require 'contrast/components/logger'
|
7
7
|
require 'contrast/utils/net_http_base'
|
8
|
+
require 'contrast/config/diagnostics/monitor'
|
8
9
|
require 'contrast/agent/reporting/connection_status'
|
9
|
-
require 'contrast/agent/reporting/reporting_utilities/response_handler'
|
10
|
-
require 'contrast/agent/reporting/reporting_utilities/reporter_client_utils'
|
11
|
-
require 'contrast/agent/reporting/reporting_utilities/endpoints'
|
12
10
|
require 'contrast/agent/reporting/reporting_utilities/headers'
|
11
|
+
require 'contrast/agent/reporting/reporting_utilities/endpoints'
|
13
12
|
require 'contrast/agent/reporting/reporting_events/server_settings'
|
13
|
+
require 'contrast/agent/reporting/reporting_utilities/response_handler'
|
14
14
|
require 'contrast/agent/reporting/reporting_events/application_settings'
|
15
|
-
require 'contrast/
|
15
|
+
require 'contrast/agent/reporting/reporting_events/agent_effective_config'
|
16
|
+
require 'contrast/agent/reporting/reporting_utilities/reporter_client_utils'
|
16
17
|
|
17
18
|
module Contrast
|
18
19
|
module Agent
|
@@ -57,6 +58,7 @@ module Contrast
|
|
57
58
|
# @param connection [Net::HTTP] open connection
|
58
59
|
def startup! connection
|
59
60
|
return if status.startup_messages_sent?
|
61
|
+
return unless connection
|
60
62
|
|
61
63
|
send_agent_startup(connection)
|
62
64
|
end
|
@@ -76,7 +78,7 @@ module Contrast
|
|
76
78
|
response = connection.request(request)
|
77
79
|
audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable
|
78
80
|
process_settings_response(response, event)
|
79
|
-
|
81
|
+
report_configuration(response, event)
|
80
82
|
process_preflight_response(event, response, connection)
|
81
83
|
response
|
82
84
|
rescue StandardError => e
|
@@ -90,7 +92,7 @@ module Contrast
|
|
90
92
|
#
|
91
93
|
# @param response [Contrast::Agent::Reporting::Response, nil]
|
92
94
|
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
93
|
-
def
|
95
|
+
def report_configuration response, event
|
94
96
|
return unless response
|
95
97
|
|
96
98
|
diagnostics.config.determine_config_status(response_handler.last_response_code || response.code)
|
@@ -99,6 +101,8 @@ module Contrast
|
|
99
101
|
|
100
102
|
logger.info('[Reporter Diagnostics] last response code:', response_code: response_handler.last_response_code)
|
101
103
|
diagnostics.write_to_file
|
104
|
+
config_event = Contrast::Agent::Reporting::AgentEffectiveConfig.new(diagnostics)
|
105
|
+
Contrast::Agent.reporter.send_event(config_event)
|
102
106
|
end
|
103
107
|
|
104
108
|
def status
|
@@ -110,7 +114,7 @@ module Contrast
|
|
110
114
|
end
|
111
115
|
|
112
116
|
def diagnostics
|
113
|
-
@_diagnostics ||= Contrast::
|
117
|
+
@_diagnostics ||= Contrast::Config::Diagnostics::Monitor.new(Contrast::LOGGER.path)
|
114
118
|
end
|
115
119
|
|
116
120
|
def sleep?
|
@@ -53,19 +53,15 @@ module Contrast
|
|
53
53
|
# @param request [Net::HTTPRequest]
|
54
54
|
# @return [Net::HTTPRequest]
|
55
55
|
def build_headers request
|
56
|
-
|
57
|
-
request
|
58
|
-
request['Application-Language'] = @headers.app_language
|
59
|
-
request['Application-Name'] = @headers.app_name
|
60
|
-
request['Application-Path'] = @headers.app_path
|
61
|
-
request['Application-Version'] = app_version if app_version
|
56
|
+
build_application_headers(request)
|
57
|
+
build_encode_and_compress_headers(request)
|
62
58
|
request['Authorization'] = @headers.authorization
|
63
59
|
request['Server-Name'] = @headers.server_name
|
64
60
|
request['Server-Path'] = @headers.server_path
|
65
61
|
request['Server-Type'] = @headers.server_type
|
66
62
|
request['X-Contrast-Agent'] = @headers.agent_version
|
67
63
|
request['X-Contrast-Header-Encoding'] = @headers.encoding
|
68
|
-
|
64
|
+
request['Session-ID'] = @headers.session_id
|
69
65
|
request
|
70
66
|
end
|
71
67
|
|
@@ -155,6 +151,18 @@ module Contrast
|
|
155
151
|
request['X-Contrast-Encoding'] = @headers.compression
|
156
152
|
request['Content-Encoding'] = @headers.compression
|
157
153
|
end
|
154
|
+
|
155
|
+
# Adds corresponding application headers to request.
|
156
|
+
#
|
157
|
+
# @param request [Net::HTTPRequest]
|
158
|
+
def build_application_headers request
|
159
|
+
app_version = @headers.app_version
|
160
|
+
request['API-Key'] = @headers.api_key
|
161
|
+
request['Application-Language'] = @headers.app_language
|
162
|
+
request['Application-Name'] = @headers.app_name
|
163
|
+
request['Application-Path'] = @headers.app_path
|
164
|
+
request['Application-Version'] = app_version if app_version
|
165
|
+
end
|
158
166
|
end
|
159
167
|
end
|
160
168
|
end
|
@@ -4,6 +4,7 @@
|
|
4
4
|
require 'contrast/agent/reporting/reporting_utilities/ng_response_extractor'
|
5
5
|
require 'contrast/agent/reporting/reporting_utilities/response_extractor'
|
6
6
|
require 'contrast/agent/reactions/disable_reaction'
|
7
|
+
require 'contrast/utils/json'
|
7
8
|
|
8
9
|
module Contrast
|
9
10
|
module Agent
|
@@ -257,7 +258,7 @@ module Contrast
|
|
257
258
|
response_body = response&.body
|
258
259
|
return unless response_body
|
259
260
|
|
260
|
-
response_data =
|
261
|
+
response_data = Contrast::Utils::Json.parse(response_body, deep_symbolize: true)
|
261
262
|
return unless response_data.cs__is_a?(Hash)
|
262
263
|
|
263
264
|
extract_response_last_modified(response, event)
|
@@ -13,11 +13,14 @@ module Contrast
|
|
13
13
|
RESEND_INTERVAL_MS = 30_000.cs__freeze
|
14
14
|
|
15
15
|
def start_thread!
|
16
|
+
return unless attempt_to_start?
|
16
17
|
return if running?
|
17
18
|
|
18
19
|
@_thread = Contrast::Agent::Thread.new do
|
19
20
|
logger.info('[ApplicationSettingsWorker] Starting thread.', sending_interval: application_server_ms)
|
20
21
|
loop do
|
22
|
+
break unless attempt_to_start?
|
23
|
+
|
21
24
|
logger.info('[ApplicationSettingsWorker] Fetching Settings', sending_interval: application_server_ms)
|
22
25
|
Contrast::Agent.reporter&.send_event(application_settings_message)
|
23
26
|
sleep(application_server_ms / 1000)
|
@@ -19,11 +19,14 @@ module Contrast
|
|
19
19
|
REFRESH_INTERVAL_SEC = 60
|
20
20
|
|
21
21
|
def start_thread!
|
22
|
+
return unless attempt_to_start?
|
22
23
|
return if running?
|
23
24
|
|
24
25
|
@_thread = Contrast::Agent::Thread.new do
|
25
26
|
logger.info('[Heartbeat] Starting thread.')
|
26
27
|
loop do
|
28
|
+
break unless attempt_to_start?
|
29
|
+
|
27
30
|
polling_events.each do |event|
|
28
31
|
Contrast::Agent.reporter&.send_event(event)
|
29
32
|
end
|
@@ -13,11 +13,14 @@ module Contrast
|
|
13
13
|
RESEND_INTERVAL_MS = 60_000.cs__freeze
|
14
14
|
|
15
15
|
def start_thread!
|
16
|
+
return unless attempt_to_start?
|
16
17
|
return if running?
|
17
18
|
|
18
19
|
@_thread = Contrast::Agent::Thread.new do
|
19
20
|
logger.info('[ServerSettingsWorker] Starting thread.', sending_interval: server_settings_resend_ms)
|
20
21
|
loop do
|
22
|
+
break unless attempt_to_start?
|
23
|
+
|
21
24
|
logger.info('[ServerSettingsWorker] Fetching Settings', sending_interval: server_settings_resend_ms)
|
22
25
|
Contrast::Agent.reporter&.send_event(settings_message)
|
23
26
|
sleep(server_settings_resend_ms / 1000)
|
@@ -46,6 +46,39 @@ module Contrast
|
|
46
46
|
@enabled
|
47
47
|
end
|
48
48
|
|
49
|
+
# In case of connection error, do not create the background thread or queue,
|
50
|
+
# as if the opt-out env var was set.
|
51
|
+
#
|
52
|
+
# @return [Boolean]
|
53
|
+
def ip_opt_out?
|
54
|
+
@_ip_opt_out ||= begin
|
55
|
+
test_conn = Contrast::Agent::Telemetry::Client.new.initialize_connection(URL)
|
56
|
+
|
57
|
+
if test_conn.nil? || Contrast::Utils::NetHttpBase.last_error
|
58
|
+
# log if error:
|
59
|
+
if defined?(Contrast) && defined?(Contrast::CONFIG) && defined?(Contrast::CONFIG)
|
60
|
+
Contrast::CONFIG.proto_logger.warn('[Telemetry] connection error disabling...',
|
61
|
+
error: Contrast::Utils::NetHttpBase.last_error)
|
62
|
+
|
63
|
+
end
|
64
|
+
# Disable telemetry:
|
65
|
+
@enabled = false
|
66
|
+
true
|
67
|
+
else
|
68
|
+
# Close the connection
|
69
|
+
test_conn.finish if test_conn.started?
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
rescue StandardError
|
74
|
+
@enabled = false
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def disable!
|
79
|
+
@enabled = false
|
80
|
+
end
|
81
|
+
|
49
82
|
private
|
50
83
|
|
51
84
|
def telemetry_enabled?
|
@@ -56,15 +89,7 @@ module Contrast
|
|
56
89
|
|
57
90
|
# In case of connection error, do not create the background thread or queue,
|
58
91
|
# 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
|
92
|
+
return false if ip_opt_out?
|
68
93
|
|
69
94
|
true
|
70
95
|
end
|
@@ -91,6 +116,7 @@ module Contrast
|
|
91
116
|
end
|
92
117
|
|
93
118
|
def start_thread!
|
119
|
+
return unless attempt_to_start?
|
94
120
|
return if running?
|
95
121
|
|
96
122
|
logger.debug('[Telemetry] Starting background telemetry thread.')
|
@@ -140,6 +166,7 @@ module Contrast
|
|
140
166
|
Contrast::Agent::Thread.new do
|
141
167
|
loop do
|
142
168
|
next unless client && connection
|
169
|
+
break unless attempt_to_start?
|
143
170
|
|
144
171
|
# Start pushing exceptions to queue for reporting.
|
145
172
|
Contrast::TELEMETRY_EXCEPTIONS.each_value { |value| queue << value }
|
@@ -155,9 +182,7 @@ module Contrast
|
|
155
182
|
sleep(retry_sleep_time) unless retry_sleep_time.nil?
|
156
183
|
end
|
157
184
|
rescue StandardError => e
|
158
|
-
|
159
|
-
# an infinite loop w/ telemetry
|
160
|
-
logger.debug('[Telemetry] Could not send message to service from telemetry queue.', e)
|
185
|
+
logger.error('[Telemetry] Could not send message to service from telemetry queue.', e)
|
161
186
|
stop!
|
162
187
|
end
|
163
188
|
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
|
@@ -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,14 @@ 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 = 'ENV'
|
15
|
+
COMMAND_LINE = 'CLI'
|
16
|
+
CONTRAST_UI = 'ContrastUI'
|
17
|
+
DEFAULT_VALUE = 'Default'
|
18
|
+
# Order matters for the Configurations files. This is read when Agent starts up and will always go
|
19
|
+
# through the YAML as priority.
|
20
|
+
# Do not change the order!
|
21
|
+
APP_CONFIGURATION_FILE = %w[YAML YML].cs__freeze
|
19
22
|
|
20
23
|
# @return [Hash]
|
21
24
|
attr_reader :data
|
@@ -30,15 +33,15 @@ module Contrast
|
|
30
33
|
# @param path [String] the canonical name for the config entry (such as api.proxy.enable)
|
31
34
|
# @return [String] the source for the entry
|
32
35
|
def get path
|
33
|
-
data.dig(*parts_for(path)) ||
|
36
|
+
data.dig(*parts_for(path)) || DEFAULT_VALUE
|
34
37
|
rescue TypeError
|
35
|
-
|
38
|
+
DEFAULT_VALUE
|
36
39
|
end
|
37
40
|
|
38
41
|
# Assigns the config source for a specified config path.
|
39
42
|
#
|
40
43
|
# @param path [String] the canonical name for the config entry (such as api.proxy.enable)
|
41
|
-
# @param [String] the source for the entry
|
44
|
+
# @param source[String] the source for the entry
|
42
45
|
# @return [String] the source type for the entry
|
43
46
|
def set path, source
|
44
47
|
assign_value(data, parts_for(path), source)
|
@@ -64,7 +67,7 @@ module Contrast
|
|
64
67
|
# @param current_level [Hash] all, or some of, the config source information
|
65
68
|
# @param parts [Array] the parts for canonical name of the config entry
|
66
69
|
# @param source [String] the source to be set for the specified entry
|
67
|
-
# @return [
|
70
|
+
# @return [String] the path split on periods, and converted to symbols
|
68
71
|
def assign_value current_level, parts, source
|
69
72
|
parts[0...-1].each do |segment|
|
70
73
|
current_level[segment] ||= {}
|