contrast-agent 7.0.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/ext/extconf_common.rb +88 -14
  3. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  4. data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
  5. data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
  6. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  7. data/lib/contrast/agent/excluder/excluder.rb +64 -31
  8. data/lib/contrast/agent/patching/policy/policy.rb +2 -2
  9. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
  10. data/lib/contrast/agent/protect/rule/base.rb +4 -6
  11. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
  12. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
  13. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
  14. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
  15. data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
  16. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
  17. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
  19. data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
  20. data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
  21. data/lib/contrast/agent/reporting/client/interface.rb +132 -0
  22. data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
  23. data/lib/contrast/agent/reporting/connection_status.rb +0 -1
  24. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
  25. data/lib/contrast/agent/reporting/reporter.rb +23 -23
  26. data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
  27. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  28. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
  29. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
  30. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
  31. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +57 -12
  32. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +55 -38
  33. data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
  34. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
  35. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
  36. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -12
  37. data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
  38. data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
  39. data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
  40. data/lib/contrast/agent/request/request.rb +27 -12
  41. data/lib/contrast/agent/telemetry/base.rb +55 -31
  42. data/lib/contrast/agent/telemetry/client.rb +1 -3
  43. data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
  44. data/lib/contrast/agent/telemetry/exception.rb +1 -0
  45. data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
  46. data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
  47. data/lib/contrast/agent/version.rb +1 -1
  48. data/lib/contrast/components/agent.rb +1 -1
  49. data/lib/contrast/components/api.rb +2 -2
  50. data/lib/contrast/components/app_context.rb +1 -1
  51. data/lib/contrast/components/assess.rb +1 -1
  52. data/lib/contrast/components/assess_rules.rb +1 -1
  53. data/lib/contrast/components/base.rb +3 -3
  54. data/lib/contrast/components/config/sources.rb +13 -9
  55. data/lib/contrast/components/config.rb +2 -2
  56. data/lib/contrast/components/protect.rb +2 -2
  57. data/lib/contrast/components/sampling.rb +6 -4
  58. data/lib/contrast/components/settings.rb +10 -1
  59. data/lib/contrast/config/certification_configuration.rb +1 -1
  60. data/lib/contrast/config/configuration_files.rb +47 -0
  61. data/lib/contrast/config/diagnostics/command_line.rb +24 -0
  62. data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
  63. data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
  64. data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
  65. data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
  66. data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
  67. data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
  68. data/lib/contrast/config/diagnostics/source_config_value.rb +55 -0
  69. data/lib/contrast/config/diagnostics/tools.rb +188 -0
  70. data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
  71. data/lib/contrast/config/request_audit_configuration.rb +1 -1
  72. data/lib/contrast/config/server_configuration.rb +1 -1
  73. data/lib/contrast/config/validate.rb +2 -2
  74. data/lib/contrast/configuration.rb +82 -57
  75. data/lib/contrast/framework/grape/support.rb +1 -2
  76. data/lib/contrast/framework/manager.rb +17 -8
  77. data/lib/contrast/framework/rack/support.rb +99 -1
  78. data/lib/contrast/framework/rails/support.rb +1 -2
  79. data/lib/contrast/framework/sinatra/support.rb +1 -2
  80. data/lib/contrast/logger/aliased_logging.rb +18 -9
  81. data/lib/contrast/utils/hash_utils.rb +62 -0
  82. data/lib/contrast/utils/json.rb +46 -0
  83. data/lib/contrast/utils/net_http_base.rb +75 -26
  84. data/lib/contrast/utils/request_utils.rb +14 -0
  85. data/resources/assess/policy.json +11 -0
  86. metadata +20 -8
  87. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
  88. data/lib/contrast/config/diagnostics_tools.rb +0 -99
  89. data/lib/contrast/config/effective_config.rb +0 -131
  90. data/lib/contrast/config/effective_config_value.rb +0 -32
@@ -37,7 +37,7 @@ module Contrast
37
37
  # @raise [Contrast::SecurityException] Security exception if an XXE
38
38
  # attack is found and the rule is in block mode.
39
39
  def infilter context, framework, xml
40
- return if protect_excluded_by_url?(rule_name, context.request.path)
40
+ return if protect_excluded_by_url?(rule_name)
41
41
 
42
42
  result = find_attacker(context, xml, framework: framework)
43
43
  return unless result
@@ -0,0 +1,132 @@
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/client/interface_base'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Reporting
9
+ module Client
10
+ # Interface to safely manage connections across threads.
11
+ class Interface < Contrast::Agent::Reporting::Client::InterfaceBase
12
+ # Execute startup routine and
13
+ def startup
14
+ with_monitor { reporter_client.startup!(reporting_connection) }
15
+ end
16
+
17
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
18
+ # @return [Net::HTTPResponse]
19
+ def send_event event
20
+ with_monitor { reporter_client.send_event(event, reporting_connection) }
21
+ end
22
+
23
+ # return [Boolean]
24
+ def sleep?
25
+ with_monitor { reporter_client.sleep? }
26
+ end
27
+
28
+ # Retry once than discard the event. This is trigger on too many events of
29
+ # same kind error.
30
+ #
31
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
32
+ def handle_resend event
33
+ with_monitor do
34
+ reporter_client.handle_resend(event, reporting_connection)
35
+ end
36
+ end
37
+
38
+ # Check to see if client exists and there is connection
39
+ #
40
+ # @return [Boolean
41
+ def connected?
42
+ with_monitor do
43
+ return true if reporter_client && reporting_connection
44
+
45
+ false
46
+ end
47
+ end
48
+
49
+ # Check to see if statup connections are sent or not
50
+ def startup_messages_sent?
51
+ with_monitor { reporter_client.status.startup_messages_sent? }
52
+ end
53
+
54
+ # Check to see if event need to be resend
55
+ #
56
+ # @return [Boolean, nil]
57
+ def resending?
58
+ with_monitor { reporter_client.mode.status == reporter_client.mode.resending }
59
+ end
60
+
61
+ # Return timeout in ms
62
+ def timeout
63
+ with_monitor { reporter_client.timeout } || Contrast::Agent::Reporting::ResponseHandler::TIMEOUT
64
+ end
65
+
66
+ # @return headers [Contrast::Agent::Reporting::Headers]
67
+ def headers
68
+ with_monitor { reporter_client.headers }
69
+ end
70
+
71
+ # Response_handler
72
+ #
73
+ # @return [Contrast::Agent::Reporting::ResponseHandler]
74
+ def response_handler
75
+ with_monitor { reporter_client.response_handler }
76
+ end
77
+
78
+ def status
79
+ with_monitor { reporter_client.status }
80
+ end
81
+
82
+ private
83
+
84
+ # @return [Contrast::Agent::Reporting::ReporterClient]
85
+ def reporter_client
86
+ @_reporter_client ||= Contrast::Agent::Reporting::ReporterClient.new
87
+ end
88
+
89
+ # @return [Net::HTTP, nil] Return open connection or nil
90
+ def reporting_connection
91
+ @_reporting_connection ||= reporter_client.initialize_connection
92
+ end
93
+ end
94
+ end
95
+
96
+ module Telemetry
97
+ # Interface to safely manage connections across threads.
98
+ class Interface < Contrast::Agent::Reporting::Client::InterfaceBase
99
+ URL = 'https://telemetry.ruby.contrastsecurity.com/'
100
+
101
+ # Check to see if client exists and there is connection
102
+ #
103
+ # @return [Boolean
104
+ def connected?
105
+ with_monitor do
106
+ return true if telemetry_client && telemetry_connection
107
+
108
+ false
109
+ end
110
+ end
111
+
112
+ # Starts telemetry request.
113
+ def request_with_response event
114
+ with_monitor do
115
+ telemetry_client.handle_response(telemetry_client.send_request(event, telemetry_connection))
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def telemetry_client
122
+ @_telemetry_client ||= Contrast::Agent::Telemetry::Client.new
123
+ end
124
+
125
+ def telemetry_connection
126
+ @_telemetry_connection ||= telemetry_client.initialize_connection(URL)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,27 @@
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 'monitor'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Reporting
9
+ module Client
10
+ # Common methods for Client interface.
11
+ class InterfaceBase
12
+ # Execute calls to connection with thread safety.
13
+ def with_monitor &block
14
+ monitor.synchronize(&block)
15
+ end
16
+
17
+ private
18
+
19
+ # @return [Monitor]
20
+ def monitor
21
+ @_monitor ||= Monitor.new
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -10,7 +10,6 @@ module Contrast
10
10
  @last_success = nil
11
11
  @last_failure = nil
12
12
  @startup_messages_sent = false
13
- @_startup_server_message_sent = false
14
13
  end
15
14
 
16
15
  # Whether we have sent startup message to TeamServer. True after successfully sending startup messages to
@@ -4,7 +4,7 @@
4
4
  require 'contrast/utils/object_share'
5
5
  require 'contrast/agent/reporting/input_analysis/input_type'
6
6
  require 'contrast/agent/reporting/input_analysis/score_level'
7
- require 'contrast/agent/reporting/input_analysis/details/protect_rule_details'
7
+ require 'contrast/agent/reporting/details/protect_rule_details'
8
8
 
9
9
  module Contrast
10
10
  module Agent
@@ -112,14 +112,16 @@ module Contrast
112
112
 
113
113
  # Additional per rule details containing more specific info.
114
114
  #
115
- # @param protect_rule_details [Contrast::Agent::Reporting::ProtectRuleDetails]
115
+ # @param protect_rule_details [Contrast::Agent::Reporting::Details::ProtectRuleDetails]
116
116
  def details= protect_rule_details
117
- @_details = protect_rule_details if protect_rule_details.is_a?(Contrast::Agent::Reporting::ProtectRuleDetails)
117
+ return unless protect_rule_details.is_a?(Contrast::Agent::Reporting::Details::ProtectRuleDetails)
118
+
119
+ @_details = protect_rule_details
118
120
  end
119
121
 
120
122
  # Additional per rule details containing more specific info.
121
123
  #
122
- # @return [Contrast::Agent::Reporting::ProtectRuleDetails, nil]
124
+ # @return [Contrast::Agent::Reporting::Details::ProtectRuleDetails, nil]
123
125
  def details
124
126
  @_details
125
127
  end
@@ -6,14 +6,17 @@ require 'contrast/agent/reporting/report'
6
6
  require 'contrast/components/logger'
7
7
  require 'contrast/agent/reporting/reporting_events/agent_startup'
8
8
  require 'contrast/agent/telemetry/exception'
9
+ require 'contrast/agent/reporting/client/interface'
9
10
 
10
11
  module Contrast
11
12
  module Agent
12
13
  # This module will hold everything essential to reporting to TeamServer
13
- class Reporter < WorkerThread
14
+ class Reporter < WorkerThread # rubocop:disable Metrics/ClassLength
14
15
  include Contrast::Components::Logger::InstanceMethods
15
16
  include Contrast::Utils::ObjectShare
16
17
 
18
+ # How many tries to reconnect the Reporter should make.
19
+ RETRY_ATTEMPTS = 10
17
20
  MAX_QUEUE_SIZE = 1000
18
21
 
19
22
  class << self
@@ -27,20 +30,19 @@ module Contrast
27
30
  end
28
31
 
29
32
  def client
30
- @_client ||= Contrast::Agent::Reporting::ReporterClient.new
31
- end
32
-
33
- def connection
34
- @_connection ||= client.initialize_connection
33
+ @_client ||= Contrast::Agent::Reporting::Client::Interface.new
35
34
  end
36
35
 
37
36
  def start_thread!
37
+ return unless attempt_to_start?
38
38
  return if running?
39
39
 
40
- client.startup!(connection)
40
+ @connection_attempts = 0
41
41
  @_thread = Contrast::Agent::Thread.new do
42
42
  logger.debug('[Reporter] Starting background Reporter thread.')
43
+ client.startup
43
44
  loop do
45
+ break unless attempt_to_start?
44
46
  next unless connected?
45
47
 
46
48
  process_event(queue.pop)
@@ -55,12 +57,7 @@ module Contrast
55
57
  #
56
58
  # @param event [Contrast::Agent::Reporting::ReportingEvent] Freshly pop-ed event.
57
59
  def handle_resend event
58
- sleep(client.timeout) if client.sleep?
59
- # Retry once than discard the event. This is trigger on too many events of
60
- # same kind error.
61
- client.send_event(event, connection) if client.mode.status == client.mode.resending
62
- client.mode.reset_mode
63
- client.wake_up
60
+ client.handle_resend(event)
64
61
  end
65
62
 
66
63
  # @param event [Contrast::Agent::Reporting::ReportingEvent]
@@ -93,8 +90,9 @@ module Contrast
93
90
  return
94
91
  end
95
92
  return unless event
93
+ return unless connected?
96
94
 
97
- client.send_event(event, connection)
95
+ client.send_event(event)
98
96
  rescue StandardError => e
99
97
  logger.error('[Reporter] Could not send message to TeamServer from reporting queue.', e)
100
98
  end
@@ -118,23 +116,24 @@ module Contrast
118
116
  @_queue ||= Queue.new
119
117
  end
120
118
 
121
- # TODO: RUBY-99999
122
- # The client and connection are being used in multiple threads/ concurrently, and that's not okay. We need
123
- # to figure out why that is and lock it so that it isn't.
124
- #
125
119
  # @return [Boolean]
126
120
  def connected?
127
- return true if client && connection
121
+ return true if client.connected?
128
122
 
129
- logger.debug('[Reporter] No client/connection; sleeping...', client: client, connection: connection)
130
- sleep(5)
123
+ logger.debug('[Reporter] No client/connection; sleeping...')
124
+ @connection_attempts += 1
125
+ if @connection_attempts >= RETRY_ATTEMPTS
126
+ logger.debug('[Reporter] shutting down..')
127
+ Contrast::AGENT.disable!
128
+ end
129
+ sleep(5) unless Contrast::AGENT.disabled?
131
130
  false
132
131
  end
133
132
 
134
133
  # @param event [Contrast::Agent::Reporting::ReportingEvent]
135
134
  def process_event event
136
- client.send_event(event, connection)
137
- handle_resend(event) if client.mode.status == client.mode.resending
135
+ client.send_event(event)
136
+ handle_resend(event) if client.resending?
138
137
  rescue StandardError => e
139
138
  logger.error('[Reporter] Could not send message to TeamServer from reporting queue.', e)
140
139
  end
@@ -156,6 +155,7 @@ module Contrast
156
155
  stack_trace[1].path.delete_prefix(Dir.pwd)
157
156
  end
158
157
  stack_frame_function = stack_trace.nil? || stack_trace[1].nil? ? 'none' : stack_trace[1].label
158
+ stack_frame_type = Contrast::Agent::Telemetry::Exception::Obfuscate.obfuscate_path(stack_frame_type)
159
159
  Contrast::Agent::Telemetry::Exception::StackFrame.build(stack_frame_function, stack_frame_type, nil)
160
160
  end
161
161
  end
@@ -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
@@ -81,7 +81,7 @@ module Contrast
81
81
  safe_url = source_or_string(url || pattern)
82
82
 
83
83
  msg = new
84
- msg.signature = "#{ controller }##{ method } #{ safe_pattern }"
84
+ msg.signature = "#{ controller }##{ method } #{ safe_pattern }" # rubocop:disable [Security/Object/Method]
85
85
  msg.verb = Contrast::Utils::StringUtils.force_utf8(method)
86
86
  msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url)
87
87
  msg
@@ -55,17 +55,24 @@ module Contrast
55
55
  # @param event_name [String] the type portion of the file to which to write
56
56
  # @param data [any] The data to be written to the file
57
57
  def write_to_file type, event_name, data = nil
58
- time = Time.now.to_i
58
+ time = Contrast::Utils::Timer.now_ms
59
59
  destination = type == :request ? path_for_requests : path_for_responses
60
60
  # If the feature is disabled or we have yet to create the directory structure, then we could have a nil
61
61
  # destination. In that case, take no action
62
62
  return unless destination
63
63
 
64
- filename = "#{ time }_#{ Thread.current.object_id }_#{ event_name.gsub('::', '-') }_teamserver_#{ type }.json"
64
+ # Get process id and thread id to make sure we don't overwrite files
65
+ process_id = Process.pid
66
+ thread_id = Thread.current.object_id
67
+ event_title = event_name.gsub('::', '-')
68
+ filename = "#{ time }_#{ thread_id }_#{ process_id }_#{ event_title }_teamserver_#{ type }.json"
65
69
  filepath = File.join(destination, filename)
66
70
  logger.debug('Writing to file', eventname: event_name, filename: filename, filepath: filepath)
67
71
  # Here is use append mode, because of a slightly possibility of overwriting an existing file
68
- File.open(filepath, 'a') { |f| f.write(Contrast::Utils::StringUtils.force_utf8(data)) }
72
+ File.open(filepath, 'a') do |f|
73
+ f.write(Contrast::Utils::StringUtils.force_utf8(data))
74
+ f.close
75
+ end
69
76
  rescue StandardError => e
70
77
  logger.warn('Saving audit failed', e: e)
71
78
  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,16 @@ 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/config/diagnostics'
15
+ require 'contrast/agent/reporting/reporting_events/agent_effective_config'
16
+ require 'contrast/agent/reporting/reporting_utilities/reporter_client_utils'
17
+ require 'contrast/agent/reporting/reporting_utilities/resend'
16
18
 
17
19
  module Contrast
18
20
  module Agent
@@ -57,6 +59,7 @@ module Contrast
57
59
  # @param connection [Net::HTTP] open connection
58
60
  def startup! connection
59
61
  return if status.startup_messages_sent?
62
+ return unless connection
60
63
 
61
64
  send_agent_startup(connection)
62
65
  end
@@ -70,17 +73,17 @@ module Contrast
70
73
  def send_event event, connection
71
74
  return unless connection
72
75
 
76
+ response = nil
73
77
  logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
74
-
75
78
  request = build_request(event)
76
79
  response = connection.request(request)
77
- audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable
80
+ audit.audit_event(event, response) if ::Contrast::API.request_audit_enable
78
81
  process_settings_response(response, event)
79
- record_configuration(response, event)
80
82
  process_preflight_response(event, response, connection)
83
+ report_configuration(response, event)
81
84
  response
82
85
  rescue StandardError => e
83
- handle_error(event, e)
86
+ handle_response_error(event, connection, e)
84
87
  end
85
88
 
86
89
  # Write effective config to file:
@@ -90,7 +93,7 @@ module Contrast
90
93
  #
91
94
  # @param response [Contrast::Agent::Reporting::Response, nil]
92
95
  # @param event [Contrast::Agent::Reporting::ReportingEvent]
93
- def record_configuration response, event
96
+ def report_configuration response, event
94
97
  return unless response
95
98
 
96
99
  diagnostics.config.determine_config_status(response_handler.last_response_code || response.code)
@@ -99,6 +102,11 @@ module Contrast
99
102
 
100
103
  logger.info('[Reporter Diagnostics] last response code:', response_code: response_handler.last_response_code)
101
104
  diagnostics.write_to_file
105
+ config_event = Contrast::Agent::Reporting::AgentEffectiveConfig.new(diagnostics)
106
+ Contrast::Agent.reporter.send_event(config_event)
107
+ rescue StandardError => e
108
+ # Don't let this error bubble up and stop the agent reporting, with resending triggered.
109
+ logger.error('[Reporter] Error while reporting configuration', error: e, event_type: event&.cs__class)
102
110
  end
103
111
 
104
112
  def status
@@ -110,13 +118,50 @@ module Contrast
110
118
  end
111
119
 
112
120
  def diagnostics
113
- @_diagnostics ||= Contrast::Agent::DiagnosticsConfig::Diagnostics.new(Contrast::LOGGER.path)
121
+ @_diagnostics ||= Contrast::Config::Diagnostics::Monitor.new(Contrast::LOGGER.path)
114
122
  end
115
123
 
124
+ # Compress data with Zlib
125
+ #
126
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
127
+ # @param level [Integer] compression level
128
+ # @param strategy [Integer] compression strategy
129
+ # @return [String] compressed data
130
+ def compress_event event, level = Zlib::DEFAULT_COMPRESSION, strategy = Zlib::DEFAULT_STRATEGY
131
+ compressed_data = StringIO.new.set_encoding(STRING_ENCODING)
132
+ gzip = Zlib::GzipWriter.new(compressed_data, level, strategy)
133
+ gzip.write(event.event_json)
134
+ gzip.close
135
+ gzip = nil
136
+ compressed_event = compressed_data.string.dup
137
+ compressed_data.close
138
+ compressed_data = nil
139
+ compressed_event
140
+ ensure
141
+ gzip&.close
142
+ compressed_data&.close
143
+ compressed_event
144
+ end
145
+
146
+ # Reads compressed data
147
+ #
148
+ # @param compresed_data [String]
149
+ def decompress compresed_data
150
+ Zlib::GzipReader.wrap(StringIO.new(compresed_data), &:read)
151
+ end
152
+
153
+ ##############
154
+ # Forwarders #
155
+ ##############
156
+
116
157
  def sleep?
117
158
  response_handler.sleep?
118
159
  end
119
160
 
161
+ def put_to_sleep
162
+ response_handler.put_to_sleep
163
+ end
164
+
120
165
  def timeout
121
166
  response_handler.timeout
122
167
  end
@@ -125,8 +170,8 @@ module Contrast
125
170
  response_handler.mode
126
171
  end
127
172
 
128
- def reset_mode
129
- response_handler.reset_mode
173
+ def enter_run_mode
174
+ response_handler.enter_run_mode
130
175
  end
131
176
 
132
177
  def wake_up