contrast-agent 6.0.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/cs__assess_regexp/cs__assess_regexp.c +15 -2
- data/ext/cs__assess_regexp/cs__assess_regexp.h +2 -0
- data/ext/cs__assess_string/cs__assess_string.c +8 -0
- data/ext/cs__assess_test/cs__assess_test.h +9 -0
- data/ext/cs__assess_test/cs__assess_tests.c +22 -0
- data/ext/cs__assess_test/extconf.rb +5 -0
- data/ext/cs__common/cs__common.c +101 -0
- data/ext/cs__common/cs__common.h +29 -5
- data/ext/cs__contrast_patch/cs__contrast_patch.c +1 -1
- data/ext/cs__tests/cs__tests.c +12 -0
- data/ext/cs__tests/cs__tests.h +3 -0
- data/ext/cs__tests/extconf.rb +5 -0
- data/lib/contrast/agent/assess/contrast_object.rb +16 -16
- data/lib/contrast/agent/assess/events/source_event.rb +17 -19
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -16
- data/lib/contrast/agent/assess/policy/propagator/split.rb +15 -19
- data/lib/contrast/agent/assess/policy/trigger_method.rb +3 -11
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +7 -2
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -3
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +60 -36
- data/lib/contrast/agent/at_exit_hook.rb +1 -1
- data/lib/contrast/agent/inventory/database_config.rb +10 -3
- data/lib/contrast/agent/middleware.rb +3 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +0 -2
- data/lib/contrast/agent/patching/policy/patch.rb +13 -12
- data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +6 -2
- data/lib/contrast/agent/reporting/masker/masker.rb +8 -11
- data/lib/contrast/agent/reporting/masker/masker_utils.rb +8 -4
- data/lib/contrast/agent/reporting/reporter.rb +11 -16
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +49 -0
- data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +6 -2
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +53 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +48 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +64 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +70 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +57 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +56 -0
- data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +5 -1
- data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +58 -0
- data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +27 -0
- data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +20 -10
- data/lib/contrast/agent/reporting/reporting_events/application_update.rb +7 -12
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +2 -4
- data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +3 -3
- data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -2
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +7 -3
- data/lib/contrast/agent/reporting/reporting_events/poll.rb +6 -2
- data/lib/contrast/agent/reporting/reporting_events/preflight.rb +10 -8
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +6 -10
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +12 -20
- data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +27 -0
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +17 -27
- data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +38 -0
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +8 -0
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +9 -4
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +54 -67
- data/lib/contrast/agent/reporting/reporting_utilities/response.rb +17 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +8 -5
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +10 -10
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +32 -17
- data/lib/contrast/agent/reporting/settings/protect.rb +1 -1
- data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +1 -1
- data/lib/contrast/agent/request.rb +3 -3
- data/lib/contrast/agent/request_context_extend.rb +1 -1
- data/lib/contrast/agent/request_handler.rb +3 -3
- data/lib/contrast/agent/response.rb +2 -0
- data/lib/contrast/agent/service_heartbeat.rb +6 -48
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/telemetry/base.rb +151 -0
- data/lib/contrast/agent/telemetry/events/event.rb +35 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +44 -36
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +29 -21
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +91 -73
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +62 -44
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +50 -33
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +20 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +32 -0
- data/lib/contrast/agent/telemetry/events/metric_event.rb +28 -0
- data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +123 -0
- data/lib/contrast/agent/thread_watcher.rb +52 -68
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent/worker_thread.rb +8 -0
- data/lib/contrast/agent.rb +1 -3
- data/lib/contrast/api/communication/messaging_queue.rb +28 -11
- data/lib/contrast/api/communication/response_processor.rb +7 -10
- data/lib/contrast/api/communication/speedracer.rb +1 -1
- data/lib/contrast/api/decorators/activity.rb +33 -0
- data/lib/contrast/api/decorators/http_request.rb +1 -1
- data/lib/contrast/components/config.rb +13 -22
- data/lib/contrast/components/contrast_service.rb +9 -0
- data/lib/contrast/components/settings.rb +10 -0
- data/lib/contrast/config/agent_configuration.rb +21 -11
- data/lib/contrast/config/api_configuration.rb +12 -8
- data/lib/contrast/config/api_proxy_configuration.rb +7 -3
- data/lib/contrast/config/application_configuration.rb +15 -11
- data/lib/contrast/config/assess_configuration.rb +13 -9
- data/lib/contrast/config/assess_rules_configuration.rb +5 -1
- data/lib/contrast/config/base_configuration.rb +3 -35
- data/lib/contrast/config/certification_configuration.rb +9 -5
- data/lib/contrast/config/exception_configuration.rb +10 -7
- data/lib/contrast/config/heap_dump_configuration.rb +13 -9
- data/lib/contrast/config/inventory_configuration.rb +9 -6
- data/lib/contrast/config/logger_configuration.rb +9 -6
- data/lib/contrast/config/protect_configuration.rb +9 -6
- data/lib/contrast/config/protect_rule_configuration.rb +12 -8
- data/lib/contrast/config/protect_rules_configuration.rb +18 -17
- data/lib/contrast/config/request_audit_configuration.rb +10 -7
- data/lib/contrast/config/root_configuration.rb +28 -11
- data/lib/contrast/config/ruby_configuration.rb +14 -11
- data/lib/contrast/config/sampling_configuration.rb +11 -8
- data/lib/contrast/config/server_configuration.rb +13 -9
- data/lib/contrast/config/service_configuration.rb +14 -11
- data/lib/contrast/configuration.rb +19 -10
- data/lib/contrast/framework/rails/patch/support.rb +13 -45
- data/lib/contrast/logger/aliased_logging.rb +87 -0
- data/lib/contrast/logger/application.rb +0 -4
- data/lib/contrast/tasks/config.rb +22 -13
- data/lib/contrast/utils/class_util.rb +2 -6
- data/lib/contrast/utils/invalid_configuration_util.rb +1 -1
- data/lib/contrast/utils/log_utils.rb +2 -0
- data/lib/contrast/utils/middleware_utils.rb +1 -1
- data/lib/contrast/utils/object_share.rb +1 -1
- data/lib/contrast/utils/telemetry.rb +20 -2
- data/lib/contrast/utils/telemetry_client.rb +22 -10
- data/lib/contrast/utils/telemetry_hash.rb +41 -0
- data/lib/contrast/utils/telemetry_identifier.rb +16 -1
- data/lib/contrast.rb +9 -0
- data/ruby-agent.gemspec +1 -1
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +39 -16
- data/lib/contrast/agent/telemetry/events/metric_telemetry_event.rb +0 -26
- data/lib/contrast/agent/telemetry/events/startup_metrics_telemetry_event.rb +0 -121
- data/lib/contrast/agent/telemetry/events/telemetry_event.rb +0 -33
- data/lib/contrast/agent/telemetry/telemetry.rb +0 -150
- data/lib/contrast/utils/exclude_key.rb +0 -20
@@ -5,46 +5,58 @@ require 'contrast/components/logger'
|
|
5
5
|
require 'contrast/agent/service_heartbeat'
|
6
6
|
require 'contrast/api/communication/messaging_queue'
|
7
7
|
require 'contrast/agent/reporting/report'
|
8
|
-
require 'contrast/agent/
|
8
|
+
require 'contrast/agent/reporting/reporter_heartbeat'
|
9
|
+
require 'contrast/agent/telemetry/base'
|
9
10
|
|
10
11
|
module Contrast
|
11
12
|
module Agent
|
12
13
|
# This class used to ensure that our worker threads are running in multi-process environments
|
13
|
-
#
|
14
|
-
# @attr_reader heapdump_util [Contrast::Utils::HeapDumpUtil]
|
15
|
-
# @attr_reader heartbeat [Contrast::Agent::ServiceHeartbeat]
|
16
|
-
# @attr_reader messaging_queue [Contrast::Api::Communication::MessagingQueue]
|
17
14
|
class ThreadWatcher
|
18
15
|
include Contrast::Components::Logger::InstanceMethods
|
19
16
|
|
20
|
-
|
17
|
+
# @return [Contrast::Utils::HeapDumpUtil]
|
18
|
+
attr_reader :heapdump_util
|
19
|
+
# @return [Contrast::Agent::ServiceHeartbeat, nil]
|
20
|
+
attr_reader :heartbeat
|
21
|
+
# @return [Contrast::Api::Communication::MessagingQueue, nil]
|
22
|
+
attr_reader :messaging_queue
|
23
|
+
# @return [Contrast::Agent::Reporter]
|
24
|
+
attr_reader :reporter
|
25
|
+
# @return [Contrast::Agent::ReporterHeartbeat]
|
26
|
+
attr_reader :reporter_heartbeat
|
21
27
|
|
22
28
|
def initialize
|
23
29
|
@pids = {}
|
24
30
|
@heapdump_util = Contrast::Utils::HeapDumpUtil.new
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
unless ::Contrast::CONTRAST_SERVICE.unnecessary?
|
32
|
+
@heartbeat = Contrast::Agent::ServiceHeartbeat.new
|
33
|
+
@messaging_queue = Contrast::Api::Communication::MessagingQueue.new
|
34
|
+
end
|
35
|
+
if Contrast::Agent::Reporter.enabled?
|
36
|
+
@reporter = Contrast::Agent::Reporter.new
|
37
|
+
@reporter_heartbeat = Contrast::Agent::ReporterHeartbeat.new
|
38
|
+
end
|
39
|
+
@telemetry = Contrast::Agent::Telemetry::Base.new if Contrast::Agent::Telemetry::Base.enabled?
|
29
40
|
end
|
30
41
|
|
42
|
+
# @return [Hash, nil] map of process to thread startup status
|
31
43
|
def startup!
|
32
44
|
return unless ::Contrast::AGENT.enabled?
|
33
45
|
|
34
|
-
telemetry_status = telemetry_thread_init
|
35
|
-
heartbeat_status = heartbeat_thread_init
|
36
|
-
messaging_status = messaging_thread_init
|
37
|
-
reporter_status = reporter_thread_init
|
38
|
-
|
39
46
|
logger.debug('ThreadWatcher started threads')
|
40
|
-
|
47
|
+
heartbeat_status = init_thread(heartbeat)
|
48
|
+
messaging_status = init_thread(messaging_queue)
|
41
49
|
@pids[Process.pid] = messaging_status && heartbeat_status
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
if Contrast::Agent::Telemetry::Base.enabled?
|
51
|
+
telemetry_status = init_thread(telemetry_queue)
|
52
|
+
@pids[Process.pid] = @pids[Process.pid] && telemetry_status
|
53
|
+
end
|
45
54
|
return @pids unless Contrast::Agent::Reporter.enabled?
|
46
55
|
|
47
|
-
|
56
|
+
reporter_status = init_thread(reporter)
|
57
|
+
reporter_heartbeat_status = init_thread(reporter_heartbeat)
|
58
|
+
@pids[Process.pid] = @pids[Process.pid] && reporter_status && reporter_heartbeat_status
|
59
|
+
@pids
|
48
60
|
end
|
49
61
|
|
50
62
|
def ensure_running?
|
@@ -55,63 +67,35 @@ module Contrast
|
|
55
67
|
end
|
56
68
|
|
57
69
|
def shutdown!
|
58
|
-
heartbeat
|
59
|
-
messaging_queue
|
60
|
-
heapdump_util
|
70
|
+
heartbeat&.stop!
|
71
|
+
messaging_queue&.stop!
|
72
|
+
heapdump_util&.stop!
|
61
73
|
telemetry_queue&.stop!
|
62
74
|
reporter&.stop!
|
75
|
+
reporter_heartbeat&.stop!
|
63
76
|
end
|
64
77
|
|
65
|
-
|
66
|
-
unless heartbeat.running?
|
67
|
-
logger.debug('Attempting to start heartbeat thread')
|
68
|
-
heartbeat.start_thread!
|
69
|
-
end
|
70
|
-
heartbeat_result = heartbeat.running?
|
71
|
-
logger.debug('Heartbeat thread status', alive: heartbeat_result)
|
72
|
-
heartbeat_result
|
73
|
-
end
|
74
|
-
|
75
|
-
def telemetry_thread_init
|
76
|
-
@telemetry.start_thread! if @telemetry&.attempt_to_start?
|
77
|
-
telemetry_result = @telemetry&.running?
|
78
|
-
logger.debug('Telemetry thread status', alive: telemetry_result)
|
79
|
-
telemetry_result
|
80
|
-
end
|
81
|
-
|
82
|
-
def messaging_thread_init
|
83
|
-
unless messaging_queue.running?
|
84
|
-
logger.debug('Attempting to start messaging queue thread')
|
85
|
-
messaging_queue.start_thread!
|
86
|
-
end
|
87
|
-
messaging_result = messaging_queue.running?
|
88
|
-
logger.debug('Messaging thread status', alive: messaging_result)
|
89
|
-
messaging_result
|
90
|
-
end
|
91
|
-
|
92
|
-
def reporter_thread_init
|
93
|
-
@reporter.start_thread! if @reporter&.attempt_to_start?
|
94
|
-
unless @reporter&.running?
|
95
|
-
logger.debug('Attempting to start reporter thread')
|
96
|
-
@reporter&.start_thread!
|
97
|
-
end
|
98
|
-
reporter_result = @reporter&.running?
|
99
|
-
logger.debug('Reporter thread status', alive: reporter_result)
|
100
|
-
reporter_result
|
101
|
-
end
|
102
|
-
|
103
|
-
# @return [Contrast::Agent::Telemetry]
|
78
|
+
# @return [Contrast::Agent::Telemetry::Base]
|
104
79
|
def telemetry_queue
|
105
|
-
return if @telemetry.nil?
|
106
|
-
|
107
80
|
@telemetry
|
108
81
|
end
|
109
82
|
|
110
|
-
|
111
|
-
def reporter
|
112
|
-
return if @reporter.nil?
|
83
|
+
private
|
113
84
|
|
114
|
-
|
85
|
+
# Start the thread governed by the given watcher
|
86
|
+
#
|
87
|
+
# @param watcher [Contrast::Agent::ThreadWatcher]
|
88
|
+
# @return [Boolean] if the watched thread started successfully
|
89
|
+
def init_thread watcher
|
90
|
+
return unless watcher&.attempt_to_start?
|
91
|
+
|
92
|
+
unless watcher.running?
|
93
|
+
logger.debug('Attempting to start thread', type: watcher.to_s)
|
94
|
+
watcher.start_thread!
|
95
|
+
end
|
96
|
+
result = watcher.running?
|
97
|
+
logger.debug('Thread status', type: watcher.to_s, alive: result)
|
98
|
+
result
|
115
99
|
end
|
116
100
|
end
|
117
101
|
end
|
@@ -15,10 +15,18 @@ module Contrast
|
|
15
15
|
|
16
16
|
def stop!
|
17
17
|
return unless running?
|
18
|
+
return unless @_thread
|
18
19
|
|
19
20
|
Thread.kill(@_thread)
|
20
21
|
@_thread = nil
|
21
22
|
end
|
23
|
+
|
24
|
+
# Most threads, we always want to start. Some may be controlled by feature guards though, so we need to check.
|
25
|
+
#
|
26
|
+
# @return [Boolean]
|
27
|
+
def attempt_to_start?
|
28
|
+
true
|
29
|
+
end
|
22
30
|
end
|
23
31
|
end
|
24
32
|
end
|
data/lib/contrast/agent.rb
CHANGED
@@ -71,10 +71,8 @@ module Contrast
|
|
71
71
|
thread_watcher.messaging_queue
|
72
72
|
end
|
73
73
|
|
74
|
-
# @return [nil, Contrast::Agent::Telemetry]
|
74
|
+
# @return [nil, Contrast::Agent::Telemetry::Base]
|
75
75
|
def self.telemetry_queue
|
76
|
-
return unless thread_watcher.telemetry_queue
|
77
|
-
|
78
76
|
thread_watcher.telemetry_queue
|
79
77
|
end
|
80
78
|
|
@@ -2,8 +2,10 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/components/logger'
|
5
|
+
require 'contrast/agent/assess/policy/trigger_method'
|
5
6
|
require 'contrast/agent/worker_thread'
|
6
7
|
require 'contrast/agent/reporting/reporting_utilities/audit'
|
8
|
+
require 'contrast/api/dtm.pb'
|
7
9
|
|
8
10
|
module Contrast
|
9
11
|
module Api
|
@@ -12,11 +14,13 @@ module Contrast
|
|
12
14
|
class MessagingQueue < Contrast::Agent::WorkerThread
|
13
15
|
include Contrast::Components::Logger::InstanceMethods
|
14
16
|
|
17
|
+
# @return [Contrast::Api::Communication::Speedracer, nil]
|
15
18
|
attr_reader :speedracer
|
16
19
|
|
17
20
|
def initialize
|
21
|
+
return if ::Contrast::CONTRAST_SERVICE.unnecessary?
|
22
|
+
|
18
23
|
@speedracer = Contrast::Api::Communication::Speedracer.new
|
19
|
-
@audit = Contrast::Agent::Reporting::Audit.new if ::Contrast::API.request_audit_enable?
|
20
24
|
super
|
21
25
|
end
|
22
26
|
|
@@ -33,18 +37,18 @@ module Contrast
|
|
33
37
|
logger.warn('Attempted to send event immediately with Agent disabled', caller: caller, event: event)
|
34
38
|
return
|
35
39
|
end
|
36
|
-
|
37
|
-
return response_data unless ::Contrast::API.request_audit_enable?
|
40
|
+
return if ::Contrast::CONTRAST_SERVICE.unnecessary?
|
38
41
|
|
39
|
-
|
40
|
-
response_data
|
42
|
+
speedracer.return_response(event)
|
41
43
|
end
|
42
44
|
|
43
45
|
# A simple Queue used to hold messages that are ready to be sent to SpeedRacer but for which we do not need an
|
44
46
|
# immediate response
|
45
47
|
#
|
46
|
-
# @return [Queue]
|
48
|
+
# @return [Queue, nil]
|
47
49
|
def queue
|
50
|
+
return if ::Contrast::CONTRAST_SERVICE.unnecessary?
|
51
|
+
|
48
52
|
@_queue ||= Queue.new
|
49
53
|
end
|
50
54
|
|
@@ -56,29 +60,42 @@ module Contrast
|
|
56
60
|
#
|
57
61
|
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
58
62
|
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
59
|
-
|
63
|
+
# @param force [Boolean] if we should always queue this event, even if the service isn't running, in case the
|
64
|
+
# message may be ready before the service has initiated. usually for those events which happen in a separate
|
65
|
+
# thread or which may occur during initialization.
|
66
|
+
def send_event_eventually event, force: false
|
60
67
|
if ::Contrast::AGENT.disabled?
|
61
68
|
logger.warn('Attempted to queue event with Agent disabled', caller: caller, event: event)
|
62
69
|
return
|
63
70
|
end
|
71
|
+
return if ::Contrast::CONTRAST_SERVICE.unnecessary?
|
72
|
+
# If we're unable to start the Service, then we cannot afford to queue messages as this creates the potential
|
73
|
+
# for a memory leak, especially if the thread responsible for de-queueing the messages is dead.
|
74
|
+
return if !force && !(speedracer.status.connected? && running?)
|
75
|
+
|
76
|
+
# If we're in direct communication mode, the only message we should queue is the heartbeat to keep the
|
77
|
+
# service alive during Protect activities. All other messages should go through direct reporting.
|
78
|
+
if ::Contrast::CONTRAST_SERVICE.use_agent_communication?
|
79
|
+
return unless ::Contrast::PROTECT.enabled?
|
80
|
+
return unless event.cs__is_a?(Contrast::Api::Dtm::Poll)
|
81
|
+
end
|
82
|
+
|
64
83
|
logger.debug('Enqueued event for sending', event_type: event.cs__class)
|
65
84
|
queue << event if event
|
66
|
-
return unless ::Contrast::API.request_audit_enable?
|
67
|
-
|
68
|
-
@audit&.audit_event(event)
|
69
85
|
end
|
70
86
|
|
71
87
|
# Create the reporting thread, which will pull from the queue in order to send messages to SpeedRacer. If
|
72
88
|
# SpeedRacer is not running and should be, meaning the Agent is configured to control it, then we will also
|
73
89
|
# try to start that process.
|
74
90
|
def start_thread!
|
91
|
+
return if ::Contrast::CONTRAST_SERVICE.unnecessary?
|
92
|
+
|
75
93
|
speedracer.ensure_startup!
|
76
94
|
return if running?
|
77
95
|
|
78
96
|
@_thread = Contrast::Agent::Thread.new do
|
79
97
|
loop do
|
80
98
|
event = queue.pop
|
81
|
-
|
82
99
|
begin
|
83
100
|
logger.debug('Dequeued event for sending', event_type: event.cs__class)
|
84
101
|
speedracer.process_internally(event)
|
@@ -8,12 +8,8 @@ module Contrast
|
|
8
8
|
module Api
|
9
9
|
module Communication
|
10
10
|
# Handles processing deferred messages sent to SpeedRacer.
|
11
|
-
#
|
12
|
-
# @attr_reader last_app_update_ms [Integer] the time, in ms, that application settings last changed
|
13
|
-
# @attr_reader last_server_update_ms [Integer] the time, in ms, that server settings last changed
|
14
11
|
class ResponseProcessor
|
15
12
|
include Contrast::Components::Logger::InstanceMethods
|
16
|
-
attr_reader :last_app_update_ms, :last_server_update_ms
|
17
13
|
|
18
14
|
# Use the given response to update the Agent's server features and application settings, allowing it to reflect
|
19
15
|
# the latest options configured by the user in TeamServer
|
@@ -48,7 +44,6 @@ module Contrast
|
|
48
44
|
logger.trace('Agent: Received updated server features')
|
49
45
|
|
50
46
|
::Contrast::SETTINGS.update_from_server_features(server_features)
|
51
|
-
@last_server_update_ms = Contrast::Utils::Timer.now_ms
|
52
47
|
server_features
|
53
48
|
end
|
54
49
|
|
@@ -58,22 +53,24 @@ module Contrast
|
|
58
53
|
# @param response [Contrast::Api::Settings::AgentSettings]
|
59
54
|
# @return [Contrast::Api::Settings::ApplicationSettings]
|
60
55
|
def process_application_response response
|
56
|
+
logger.debug('[!] process_application_response', response: response)
|
61
57
|
app_settings = response&.application_settings
|
62
58
|
return unless app_settings
|
63
59
|
|
64
|
-
logger.debug('Agent: Received updated application settings')
|
65
|
-
|
60
|
+
logger.debug('[!] Agent: Received updated application settings', settings: app_settings)
|
66
61
|
::Contrast::SETTINGS.update_from_application_settings(app_settings)
|
67
|
-
@last_app_update_ms = Contrast::Utils::Timer.now_ms
|
68
62
|
app_settings
|
69
63
|
end
|
70
64
|
|
71
65
|
# This can't go in the Settings component because protect and assess depend on settings
|
72
66
|
# I don't think it should go into contrast_service because that only handles connection specific data.
|
73
67
|
#
|
74
|
-
# @param server_features
|
75
|
-
#
|
68
|
+
# @param server_features
|
69
|
+
# [Contrast::Api::Settings::AgentSettings, Contrast::Agent::Reporting::Settings::FeatureSettings]
|
70
|
+
# @param app_settings
|
71
|
+
# [Contrast::Api::Settings::ApplicationSettings, Contrast::Agent::Reporting::Settings::ApplicationSettings]
|
76
72
|
def update_features server_features, app_settings
|
73
|
+
logger.info('Updating features')
|
77
74
|
return unless !!(server_features || app_settings)
|
78
75
|
return unless ::Contrast::AGENT.enabled?
|
79
76
|
|
@@ -42,7 +42,7 @@ module Contrast
|
|
42
42
|
return
|
43
43
|
end
|
44
44
|
end
|
45
|
-
unless status.startup_messages_sent? || Contrast::
|
45
|
+
unless status.startup_messages_sent? || Contrast::CONTRAST_SERVICE.unnecessary?
|
46
46
|
startup_responses = send_initialization_messages
|
47
47
|
return false unless startup_responses
|
48
48
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'contrast/utils/string_utils'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Api
|
8
|
+
module Decorators
|
9
|
+
# Used to decorate the {Contrast::Api::Dtm::Activity} protobuf model
|
10
|
+
# to handle conversion between framework route classes and the dtm.
|
11
|
+
module Activity
|
12
|
+
def self.included klass
|
13
|
+
klass.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Class methods for Activity
|
17
|
+
module ClassMethods
|
18
|
+
def source_or_string obj
|
19
|
+
if obj.cs__is_a?(Regexp)
|
20
|
+
obj.source
|
21
|
+
elsif obj.cs__respond_to?(:safe_string)
|
22
|
+
obj.safe_string
|
23
|
+
else
|
24
|
+
obj.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Contrast::Api::Dtm::Activity.include(Contrast::Api::Decorators::Activity)
|
@@ -94,7 +94,7 @@ module Contrast
|
|
94
94
|
return true if ::Contrast::AGENT.omit_body?
|
95
95
|
return false if request.document_type != :NORMAL
|
96
96
|
|
97
|
-
request.
|
97
|
+
request.media_type&.include?('multipart/form-data')
|
98
98
|
end
|
99
99
|
|
100
100
|
def append_pair map, key, value
|
@@ -72,6 +72,19 @@ module Contrast
|
|
72
72
|
@config.loggable
|
73
73
|
end
|
74
74
|
|
75
|
+
# Typically, this would be accessed through Contrast::SETTINGS, but we're specifically checking for the user
|
76
|
+
# provided value here rather than that echoed back by TeamServer.
|
77
|
+
#
|
78
|
+
# @return [String,nil] the value of the session id set in the configuration, or nil if unset
|
79
|
+
def session_id
|
80
|
+
root.application.session_id
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [String,nil] the value of the session metadata set in the configuration, or nil if unset
|
84
|
+
def session_metadata
|
85
|
+
root.application.session_metadata
|
86
|
+
end
|
87
|
+
|
75
88
|
private
|
76
89
|
|
77
90
|
SESSION_VARIABLES = 'Invalid configuration. '\
|
@@ -127,28 +140,6 @@ module Contrast
|
|
127
140
|
end
|
128
141
|
end
|
129
142
|
|
130
|
-
# Typically, this would be accessed through
|
131
|
-
# Contrast::Components::AppContext, but we're too early in the
|
132
|
-
# initialization of the Agent to use that mechanism, so we look it up
|
133
|
-
# directly for ourselves
|
134
|
-
#
|
135
|
-
# @return [String,nil] the value of the session id set in the
|
136
|
-
# configuration, or nil if unset
|
137
|
-
def session_id
|
138
|
-
root.application.session_id
|
139
|
-
end
|
140
|
-
|
141
|
-
# Typically, this would be accessed through
|
142
|
-
# Contrast::Components::AppContext, but we're too early in the
|
143
|
-
# initialization of the Agent to use that mechanism, so we look it up
|
144
|
-
# directly for ourselves
|
145
|
-
#
|
146
|
-
# @return [String,nil] the value of the session metadata set in the
|
147
|
-
# configuration, or nil if unset
|
148
|
-
def session_metadata
|
149
|
-
root.application.session_metadata
|
150
|
-
end
|
151
|
-
|
152
143
|
# Typically, the following values would be accessed through Contrast::Components::AppContext
|
153
144
|
# and Contrast::Components::API, but we're too early in the initialization of the Agent to use
|
154
145
|
# that mechanism, so we look it up directly for ourselves.
|
@@ -38,6 +38,15 @@ module Contrast
|
|
38
38
|
@_use_agent_communication = true?(::Contrast::CONFIG.root.agent.service.bypass)
|
39
39
|
end
|
40
40
|
|
41
|
+
# If we're using the agent directly and not using protect, then there is no need to start the service. Because
|
42
|
+
# we only know this at startup when hardcoded as such (b/c TS could turn protect on otherwise), we can only do
|
43
|
+
# so when bypass is on and protect is off in local config
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
def unnecessary?
|
47
|
+
::Contrast::CONTRAST_SERVICE.use_agent_communication? && ::Contrast::PROTECT.forcibly_disabled?
|
48
|
+
end
|
49
|
+
|
41
50
|
def host
|
42
51
|
@_host ||=
|
43
52
|
(::Contrast::CONFIG.root.agent.service.host || Contrast::Config::ServiceConfiguration::DEFAULT_HOST).to_s
|
@@ -86,6 +86,10 @@ module Contrast
|
|
86
86
|
# Rules to follow when using the masking. Each rules contains Id [String]
|
87
87
|
# and Keywords [Array<String>].
|
88
88
|
attr_reader :sensitive_data_masking
|
89
|
+
# @return [Integer] the time, in ms, that application settings last changed
|
90
|
+
attr_reader :last_app_update_ms
|
91
|
+
# @return [Integer] the time, in ms, that server settings last changed
|
92
|
+
attr_reader :last_server_update_ms
|
89
93
|
|
90
94
|
def initialize
|
91
95
|
reset_state
|
@@ -99,6 +103,8 @@ module Contrast
|
|
99
103
|
def update_from_server_features features
|
100
104
|
if features.cs__is_a?(Contrast::Agent::Reporting::Response)
|
101
105
|
server_features = features.server_features
|
106
|
+
return unless server_features
|
107
|
+
|
102
108
|
log_file = server_features.log_file
|
103
109
|
log_level = server_features.log_level
|
104
110
|
Contrast::Logger::Log.instance.update(log_file, log_level) if log_file || log_level
|
@@ -110,12 +116,15 @@ module Contrast
|
|
110
116
|
@assess_state.enabled = features.assess_enabled?
|
111
117
|
@assess_state.sampling_settings = features.assess.sampling
|
112
118
|
end
|
119
|
+
@last_server_update_ms = Contrast::Utils::Timer.now_ms
|
113
120
|
end
|
114
121
|
|
115
122
|
# @param features [Contrast::Api::Settings::ApplicationSettings, Contrast::Agent::Reporting::Response]
|
116
123
|
def update_from_application_settings features
|
117
124
|
if features&.class == Contrast::Agent::Reporting::Response
|
118
125
|
settings = features.application_settings
|
126
|
+
return unless settings
|
127
|
+
|
119
128
|
@application_state.modes_by_id = settings.protect.protection_rules_to_settings_hash
|
120
129
|
# TODO: RUBY-1438 this needs to be translated
|
121
130
|
# @application_state.exclusion_matchers = new_vals[:exclusion_matchers]
|
@@ -128,6 +137,7 @@ module Contrast
|
|
128
137
|
@application_state.exclusion_matchers = new_vals[:exclusion_matchers]
|
129
138
|
@assess_state.disabled_assess_rules = new_vals[:disabled_assess_rules]
|
130
139
|
end
|
140
|
+
@last_app_update_ms = Contrast::Utils::Timer.now_ms
|
131
141
|
end
|
132
142
|
|
133
143
|
# Wipe state to zero.
|
@@ -9,23 +9,33 @@ require 'contrast/config/api_configuration'
|
|
9
9
|
|
10
10
|
module Contrast
|
11
11
|
module Config
|
12
|
-
# Common Configuration settings. Those in this section pertain to the
|
13
|
-
|
14
|
-
|
12
|
+
# Common Configuration settings. Those in this section pertain to the core functionality of the Agent.
|
13
|
+
class AgentConfiguration
|
14
|
+
include Contrast::Config::BaseConfiguration
|
15
|
+
|
15
16
|
# @return [Boolean, nil]
|
16
17
|
attr_accessor :enable
|
17
18
|
# @return [Boolean, nil]
|
18
19
|
attr_accessor :omit_body
|
19
|
-
|
20
|
+
# @return [Contrast::Config::RubyConfiguration]
|
21
|
+
attr_writer :ruby
|
22
|
+
# @return [Contrast::Config::ServiceConfiguration]
|
23
|
+
attr_writer :service
|
24
|
+
# @return [ Contrast::Config::LoggerConfiguration]
|
25
|
+
attr_writer :logger
|
26
|
+
# @return [Contrast::Config::HeapDumpConfiguration]
|
27
|
+
attr_writer :heap_dump
|
20
28
|
|
21
29
|
def initialize hsh = {}
|
22
|
-
|
23
|
-
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
30
|
+
return unless hsh
|
31
|
+
|
32
|
+
@enable = hsh[:enable]
|
33
|
+
@start_bundled_service = hsh[:start_bundled_service]
|
34
|
+
@omit_body = hsh[:omit_body]
|
35
|
+
@service = Contrast::Config::ServiceConfiguration.new(hsh[:service])
|
36
|
+
@logger = Contrast::Config::LoggerConfiguration.new(hsh[:logger])
|
37
|
+
@ruby = Contrast::Config::RubyConfiguration.new(hsh[:ruby])
|
38
|
+
@heap_dump = Contrast::Config::HeapDumpConfiguration.new(hsh[:heap_dump])
|
29
39
|
end
|
30
40
|
|
31
41
|
# @return [Boolean, true]
|
@@ -8,7 +8,9 @@ require 'contrast/config/request_audit_configuration'
|
|
8
8
|
module Contrast
|
9
9
|
module Config
|
10
10
|
# Api keys configuration
|
11
|
-
class ApiConfiguration
|
11
|
+
class ApiConfiguration
|
12
|
+
include Contrast::Config::BaseConfiguration
|
13
|
+
|
12
14
|
# @return [String]
|
13
15
|
attr_accessor :api_key
|
14
16
|
# @return [String]
|
@@ -20,13 +22,15 @@ module Contrast
|
|
20
22
|
DEFAULT_URL = 'https://app.contrastsecurity.com/Contrast'
|
21
23
|
|
22
24
|
def initialize hsh = {}
|
23
|
-
|
24
|
-
|
25
|
-
@
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
25
|
+
return unless hsh
|
26
|
+
|
27
|
+
@api_key = hsh[:api_key]
|
28
|
+
@url = hsh[:url]
|
29
|
+
@user_name = hsh[:user_name]
|
30
|
+
@service_key = hsh[:service_key]
|
31
|
+
@proxy = Contrast::Config::ApiProxyConfiguration.new(hsh[:proxy])
|
32
|
+
@request_audit = Contrast::Config::RequestAuditConfiguration.new(hsh[:request_audit])
|
33
|
+
@certificate = Contrast::Config::CertificationConfiguration.new(hsh[:certificate])
|
30
34
|
end
|
31
35
|
|
32
36
|
def url
|
@@ -4,14 +4,18 @@
|
|
4
4
|
module Contrast
|
5
5
|
module Config
|
6
6
|
# Api Proxy keys configuration
|
7
|
-
class ApiProxyConfiguration
|
7
|
+
class ApiProxyConfiguration
|
8
|
+
include Contrast::Config::BaseConfiguration
|
9
|
+
|
8
10
|
# @return [String] proxy url
|
9
11
|
attr_accessor :url
|
10
12
|
attr_writer :enable
|
11
13
|
|
12
14
|
def initialize hsh = {}
|
13
|
-
|
14
|
-
|
15
|
+
return unless hsh
|
16
|
+
|
17
|
+
@enable = hsh[:enable]
|
18
|
+
@url = hsh[:url]
|
15
19
|
end
|
16
20
|
|
17
21
|
# @return [Boolean, false]
|
@@ -7,7 +7,9 @@ module Contrast
|
|
7
7
|
module Config
|
8
8
|
# Common Configuration settings. Those in this section pertain to the
|
9
9
|
# application identification functionality of the Agent.
|
10
|
-
class ApplicationConfiguration
|
10
|
+
class ApplicationConfiguration
|
11
|
+
include Contrast::Config::BaseConfiguration
|
12
|
+
|
11
13
|
# @return [String]
|
12
14
|
attr_accessor :name
|
13
15
|
# @return [String]
|
@@ -27,16 +29,18 @@ module Contrast
|
|
27
29
|
attr_writer :session_id, :session_metadata
|
28
30
|
|
29
31
|
def initialize hsh = {}
|
30
|
-
|
31
|
-
|
32
|
-
@
|
33
|
-
@
|
34
|
-
@
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@
|
32
|
+
return unless hsh
|
33
|
+
|
34
|
+
@name = hsh[:name]
|
35
|
+
@version = hsh[:version]
|
36
|
+
@language = hsh[:language]
|
37
|
+
@path = hsh[:path]
|
38
|
+
@group = hsh[:group]
|
39
|
+
@tags = hsh[:tags]
|
40
|
+
@code = hsh[:code]
|
41
|
+
@metadata = hsh[:metadata]
|
42
|
+
@session_id = hsh[:session_id]
|
43
|
+
@session_metadata = hsh[:session_metadata]
|
40
44
|
end
|
41
45
|
|
42
46
|
# @return [String, Contrast::Utils::ObjectShare::EMPTY_STRING]
|