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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_regexp/cs__assess_regexp.c +15 -2
  3. data/ext/cs__assess_regexp/cs__assess_regexp.h +2 -0
  4. data/ext/cs__assess_string/cs__assess_string.c +8 -0
  5. data/ext/cs__assess_test/cs__assess_test.h +9 -0
  6. data/ext/cs__assess_test/cs__assess_tests.c +22 -0
  7. data/ext/cs__assess_test/extconf.rb +5 -0
  8. data/ext/cs__common/cs__common.c +101 -0
  9. data/ext/cs__common/cs__common.h +29 -5
  10. data/ext/cs__contrast_patch/cs__contrast_patch.c +1 -1
  11. data/ext/cs__tests/cs__tests.c +12 -0
  12. data/ext/cs__tests/cs__tests.h +3 -0
  13. data/ext/cs__tests/extconf.rb +5 -0
  14. data/lib/contrast/agent/assess/contrast_object.rb +16 -16
  15. data/lib/contrast/agent/assess/events/source_event.rb +17 -19
  16. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -16
  17. data/lib/contrast/agent/assess/policy/propagator/split.rb +15 -19
  18. data/lib/contrast/agent/assess/policy/trigger_method.rb +3 -11
  19. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +7 -2
  20. data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -3
  21. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +60 -36
  22. data/lib/contrast/agent/at_exit_hook.rb +1 -1
  23. data/lib/contrast/agent/inventory/database_config.rb +10 -3
  24. data/lib/contrast/agent/middleware.rb +3 -3
  25. data/lib/contrast/agent/patching/policy/after_load_patch.rb +0 -2
  26. data/lib/contrast/agent/patching/policy/patch.rb +13 -12
  27. data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
  28. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +6 -2
  29. data/lib/contrast/agent/reporting/masker/masker.rb +8 -11
  30. data/lib/contrast/agent/reporting/masker/masker_utils.rb +8 -4
  31. data/lib/contrast/agent/reporting/reporter.rb +11 -16
  32. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +49 -0
  33. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +6 -2
  34. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +53 -0
  35. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +48 -0
  36. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +64 -0
  37. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +70 -0
  38. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +57 -0
  39. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +56 -0
  40. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +5 -1
  41. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +58 -0
  42. data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +27 -0
  43. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +20 -10
  44. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +7 -12
  45. data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
  46. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +2 -4
  47. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +3 -3
  48. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -2
  49. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +7 -3
  50. data/lib/contrast/agent/reporting/reporting_events/poll.rb +6 -2
  51. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +10 -8
  52. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +6 -10
  53. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +12 -20
  54. data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +27 -0
  55. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +17 -27
  56. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +38 -0
  57. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +8 -0
  58. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
  59. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +9 -4
  60. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +54 -67
  61. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +17 -7
  62. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +8 -5
  63. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +10 -10
  64. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +32 -17
  65. data/lib/contrast/agent/reporting/settings/protect.rb +1 -1
  66. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +1 -1
  67. data/lib/contrast/agent/request.rb +3 -3
  68. data/lib/contrast/agent/request_context_extend.rb +1 -1
  69. data/lib/contrast/agent/request_handler.rb +3 -3
  70. data/lib/contrast/agent/response.rb +2 -0
  71. data/lib/contrast/agent/service_heartbeat.rb +6 -48
  72. data/lib/contrast/agent/static_analysis.rb +1 -1
  73. data/lib/contrast/agent/telemetry/base.rb +151 -0
  74. data/lib/contrast/agent/telemetry/events/event.rb +35 -0
  75. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +44 -36
  76. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +29 -21
  77. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +91 -73
  78. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +62 -44
  79. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +50 -33
  80. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +20 -0
  81. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +32 -0
  82. data/lib/contrast/agent/telemetry/events/metric_event.rb +28 -0
  83. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +123 -0
  84. data/lib/contrast/agent/thread_watcher.rb +52 -68
  85. data/lib/contrast/agent/version.rb +1 -1
  86. data/lib/contrast/agent/worker_thread.rb +8 -0
  87. data/lib/contrast/agent.rb +1 -3
  88. data/lib/contrast/api/communication/messaging_queue.rb +28 -11
  89. data/lib/contrast/api/communication/response_processor.rb +7 -10
  90. data/lib/contrast/api/communication/speedracer.rb +1 -1
  91. data/lib/contrast/api/decorators/activity.rb +33 -0
  92. data/lib/contrast/api/decorators/http_request.rb +1 -1
  93. data/lib/contrast/components/config.rb +13 -22
  94. data/lib/contrast/components/contrast_service.rb +9 -0
  95. data/lib/contrast/components/settings.rb +10 -0
  96. data/lib/contrast/config/agent_configuration.rb +21 -11
  97. data/lib/contrast/config/api_configuration.rb +12 -8
  98. data/lib/contrast/config/api_proxy_configuration.rb +7 -3
  99. data/lib/contrast/config/application_configuration.rb +15 -11
  100. data/lib/contrast/config/assess_configuration.rb +13 -9
  101. data/lib/contrast/config/assess_rules_configuration.rb +5 -1
  102. data/lib/contrast/config/base_configuration.rb +3 -35
  103. data/lib/contrast/config/certification_configuration.rb +9 -5
  104. data/lib/contrast/config/exception_configuration.rb +10 -7
  105. data/lib/contrast/config/heap_dump_configuration.rb +13 -9
  106. data/lib/contrast/config/inventory_configuration.rb +9 -6
  107. data/lib/contrast/config/logger_configuration.rb +9 -6
  108. data/lib/contrast/config/protect_configuration.rb +9 -6
  109. data/lib/contrast/config/protect_rule_configuration.rb +12 -8
  110. data/lib/contrast/config/protect_rules_configuration.rb +18 -17
  111. data/lib/contrast/config/request_audit_configuration.rb +10 -7
  112. data/lib/contrast/config/root_configuration.rb +28 -11
  113. data/lib/contrast/config/ruby_configuration.rb +14 -11
  114. data/lib/contrast/config/sampling_configuration.rb +11 -8
  115. data/lib/contrast/config/server_configuration.rb +13 -9
  116. data/lib/contrast/config/service_configuration.rb +14 -11
  117. data/lib/contrast/configuration.rb +19 -10
  118. data/lib/contrast/framework/rails/patch/support.rb +13 -45
  119. data/lib/contrast/logger/aliased_logging.rb +87 -0
  120. data/lib/contrast/logger/application.rb +0 -4
  121. data/lib/contrast/tasks/config.rb +22 -13
  122. data/lib/contrast/utils/class_util.rb +2 -6
  123. data/lib/contrast/utils/invalid_configuration_util.rb +1 -1
  124. data/lib/contrast/utils/log_utils.rb +2 -0
  125. data/lib/contrast/utils/middleware_utils.rb +1 -1
  126. data/lib/contrast/utils/object_share.rb +1 -1
  127. data/lib/contrast/utils/telemetry.rb +20 -2
  128. data/lib/contrast/utils/telemetry_client.rb +22 -10
  129. data/lib/contrast/utils/telemetry_hash.rb +41 -0
  130. data/lib/contrast/utils/telemetry_identifier.rb +16 -1
  131. data/lib/contrast.rb +9 -0
  132. data/ruby-agent.gemspec +1 -1
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +39 -16
  137. data/lib/contrast/agent/telemetry/events/metric_telemetry_event.rb +0 -26
  138. data/lib/contrast/agent/telemetry/events/startup_metrics_telemetry_event.rb +0 -121
  139. data/lib/contrast/agent/telemetry/events/telemetry_event.rb +0 -33
  140. data/lib/contrast/agent/telemetry/telemetry.rb +0 -150
  141. data/lib/contrast/utils/exclude_key.rb +0 -20
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2022 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/agent/reporting/reporting_events/reporting_event'
4
+ require 'contrast/agent/reporting/reporting_events/application_reporting_event'
5
5
 
6
6
  module Contrast
7
7
  module Agent
@@ -10,12 +10,10 @@ module Contrast
10
10
  # to report a Preflight message to TeamServer. This message represents the identifying information of a
11
11
  # collection of Findings/Traces, which TeamServer will use to determine if it requires the full information of
12
12
  # any of the Findings/Traces to be reported.
13
- #
14
- # For our purposes, we'll only ever send one message per request; however, we must use an array to conform to the
15
- # specification.
16
- #
17
- # @attr_reader messages [Array<Contrast::Agent::Reporting::PreflightMessage>]
18
- class Preflight < Contrast::Agent::Reporting::ReportingEvent
13
+ class Preflight < Contrast::Agent::Reporting::ApplicationReportingEvent
14
+ # For our purposes, we'll only ever send one message per request; however,
15
+ # we must use an array to conform to the specification.
16
+ # @return messages [Array<Contrast::Agent::Reporting::PreflightMessage>]
19
17
  attr_reader :messages
20
18
 
21
19
  def initialize
@@ -25,13 +23,17 @@ module Contrast
25
23
  super
26
24
  end
27
25
 
26
+ def file_name
27
+ 'preflight'
28
+ end
29
+
28
30
  # Convert the instance variables on the class, and other information, into the identifiers required for
29
31
  # TeamServer to process the JSON form of this message.
30
32
  #
31
33
  # @return [Hash]
32
34
  # @raise [ArgumentError]
33
35
  def to_controlled_hash
34
- { messages: @messages }
36
+ { messages: @messages.map(&:to_controlled_hash) }
35
37
  end
36
38
  end
37
39
  end
@@ -12,13 +12,13 @@ module Contrast
12
12
  # system to report a single message, part of the main Preflight, to TeamServer. This message represents the
13
13
  # identifying information of a Finding/Trace, which TeamServer will use to determine if it requires the full
14
14
  # information of the Finding/Trace to be reported.
15
- #
16
- # @attr_accessor data [String] the message identifier; rule_id,hash
17
- # @attr_accessor hash_code [String]
18
- # @attr_reader routes [Array<Contrast::Agent::Reporting::RouteDiscovery] the route that triggered the finding
19
- # to which this preflight applies.
20
15
  class PreflightMessage
21
- attr_accessor :data, :hash_code
16
+ # @return [String] the message identifier; rule_id,hash
17
+ attr_accessor :data
18
+ # @return [String] CRC checksum of the finding to which this message pertains
19
+ attr_accessor :hash_code
20
+ # @return [Array<Contrast::Agent::Reporting::RouteDiscovery] the route that triggered the finding to which this
21
+ # preflight applies.
22
22
  attr_reader :routes
23
23
 
24
24
  # The type of this event, as understood by TeamServer. While TRACE and APPUPDATE are both technically valid, we
@@ -54,16 +54,12 @@ module Contrast
54
54
 
55
55
  def validate
56
56
  raise(ArgumentError, "#{ cs__class } did not have a proper data. Unable to continue.") unless data
57
- raise(ArgumentError, "#{ cs__class } did not have a proper routes. Unable to continue.") if routes.empty?
58
57
  unless @app_name
59
58
  raise(ArgumentError, "#{ cs__class } did not have a proper application name. Unable to continue.")
60
59
  end
61
60
  unless @app_language
62
61
  raise(ArgumentError, "#{ cs__class } did not have a proper application language. Unable to continue.")
63
62
  end
64
- unless @app_version
65
- raise(ArgumentError, "#{ cs__class } did not have a proper application version. Unable to continue.")
66
- end
67
63
  unless @agent_session_id_value
68
64
  raise(ArgumentError, "#{ cs__class } did not have a proper session id. Unable to continue.")
69
65
  end
@@ -1,18 +1,17 @@
1
1
  # Copyright (c) 2022 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/agent/reporting/reporting_events/reporting_event'
4
+ require 'contrast/agent/reporting/reporting_events/server_reporting_event'
5
5
 
6
6
  module Contrast
7
7
  module Agent
8
8
  module Reporting
9
- # This class will initialize empty ServerActivity body to be send to TS.
10
- # The server activity endpoint records actions taken on the serveror process as a whole.
11
- # It currently only reports the number of times a defensive action was taken and is most
12
- # likely not populated by most agents. The main purpose of sending this message is for its
13
- # response, which contains any updated server feature settings from TeamServer.
14
- # The new Server Settings endpoint should let us remove this.
15
- class ServerActivity < Contrast::Agent::Reporting::ReportingEvent
9
+ # This class will initialize empty ServerActivity body to be send to TS. The server activity endpoint records
10
+ # actions taken on the server or process as a whole. It currently only reports the number of times a defensive
11
+ # action was taken and is most likely not populated by most agents. The main purpose of sending this message is
12
+ # for its response, which contains any updated server feature settings from TeamServer. The new Server Settings
13
+ # endpoint should let us remove this.
14
+ class ServerActivity < Contrast::Agent::Reporting::ServerReportingEvent
16
15
  class << self
17
16
  # @param _server_activity_dtm [Contrast::Api::Dtm::ServerActivity]
18
17
  # @return [Contrast::Agent::Reporting::ServerActivity]
@@ -27,24 +26,17 @@ module Contrast
27
26
  super
28
27
  end
29
28
 
29
+ def file_name
30
+ 'server-activity'
31
+ end
32
+
30
33
  # Convert the instance variables on the class, and other information, into the identifiers required for
31
34
  # TeamServer to process the JSON form of this message.
32
35
  #
33
36
  # @return [Hash]
34
37
  # @raise [ArgumentError]
35
38
  def to_controlled_hash
36
- { lastUpdate: timestamp }
37
- end
38
-
39
- private
40
-
41
- # The timestamp field is a bit of a misnomer. It's really the time, in ms, since the settings for this
42
- # server have been updated.
43
- #
44
- # @return [Integer]
45
- def timestamp
46
- Contrast::Utils::Timer.now_ms -
47
- (Contrast::Agent.reporter&.client&.response_handler&.last_server_update_ms || 0)
39
+ { lastUpdate: since_last_update }
48
40
  end
49
41
  end
50
42
  end
@@ -0,0 +1,27 @@
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/agent/reporting/reporting_events/reporting_event'
5
+ require 'contrast/utils/timer'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Reporting
10
+ # This is the new ServerReportingEvent class which will include all the needed and mutual information for those
11
+ # events which correspond to Servers, such as Servers Activity.
12
+ #
13
+ # @abstract
14
+ class ServerReportingEvent < Contrast::Agent::Reporting::ReportingEvent
15
+ protected
16
+
17
+ # The timestamp field is a bit of a misnomer. It's really the time, in ms, since the settings for this
18
+ # application have been updated. If I've never updated, then it's been 0ms since then.
19
+ #
20
+ # @return [Integer]
21
+ def since_last_update
22
+ (update_time = Contrast::SETTINGS.last_server_update_ms) ? Contrast::Utils::Timer.now_ms - update_time : 0
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -22,61 +22,51 @@ module Contrast
22
22
  # This method will be handling the auditing of the requests and responses we send to SpeedRacer. If the audit
23
23
  # feature is enabled, we'll log to file the request and/or response protobuf objects.
24
24
  #
25
- # @param event [Contrast::Api::Dtm|Contrast::Agent::Reporting::ReportingEvent] One of the DTMs valid for the
26
- # event field of Contrast::Api::Dtm::Message|Contrast::Agent::Reporting::ReportingEvent
27
- # @param response_data [Contrast::Api::Settings::AgentSettings,nil]
25
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] One of the DTMs valid for the
26
+ # event field of Contrast::Agent::Reporting::ReportingEvent
27
+ # @param response_data [Net::HTTP::Response]
28
28
  def audit_event event, response_data = nil
29
29
  return unless ::Contrast::API.request_audit_requests? || ::Contrast::API.request_audit_responses?
30
30
 
31
- type = event.cs__respond_to?(:file_name) ? event.file_name : event.cs__class.cs__name.to_s.downcase
32
- if ::Contrast::API.request_audit_requests?
33
- data = if event.cs__class < Contrast::Agent::Reporting::ReportingEvent
34
- event.to_controlled_hash.to_json
35
- else # TODO: RUBY-1438 -- remove
36
- event.to_s
37
- end
38
- log_data :request, type, data if data
39
- end
31
+ file_name = event.cs__respond_to?(:file_name) ? event.file_name : event.cs__class.cs__name.to_s.downcase
32
+ data = event.to_controlled_hash.to_json
33
+ log_data(:request, file_name, data) if data
40
34
  return unless ::Contrast::API.request_audit_responses?
41
35
 
42
- data = response_data.to_s || event.http_response.try(:body) || 'There is no available response'
43
- log_data :response, type, data
36
+ data = response_data&.body || 'There is no available response'
37
+ log_data(:response, file_name, data)
44
38
  end
45
39
 
46
40
  private
47
41
 
48
42
  # This method will proceed with passing the data with to the writing method
49
43
  # @param type [Symbol] This is the type of the file /:request, :response/
50
- # @param data_type[String] DTM type String representation
44
+ # @param file_name[String] file_name to log
51
45
  # @param data[String] String representation if the logged data
52
- def log_data type, data_type, data = nil
46
+ def log_data type, file_name, data = nil
53
47
  return unless enabled?
54
48
  return unless Contrast::CONTRAST_SERVICE.use_agent_communication?
55
49
 
56
- write_to_file type, data_type, data
50
+ logger.debug('logging to file', file_name: file_name) # TODO: RUBY-99999 DO NOT COMMIT THIS
51
+ write_to_file(type, file_name, data)
57
52
  end
58
53
 
59
54
  # This method will be actually writing to the file
60
55
  # @param type [Symbol] This is the type of the file /:request, :response/
61
- # @param data_type [String] Data type /Activity/Finding../
56
+ # @param event_name [String] the type portion of the file to which to write
62
57
  # @param data [any] The data to be written to the file
63
- def write_to_file type, data_type, data = nil
58
+ def write_to_file type, event_name, data = nil
64
59
  time = Time.now.to_i
65
60
  destination = type == :request ? path_for_requests : path_for_responses
66
61
  # If the feature is disabled or we have yet to create the directory structure, then we could have a nil
67
62
  # destination. In that case, take no action
68
63
  return unless destination
69
64
 
70
- filename = "#{ time }-#{ Thread.current.object_id }-#{ data_type.gsub('::', '_') }-teamserver.json"
65
+ filename = "#{ time }_#{ Thread.current.object_id }_#{ event_name.gsub('::', '-') }_teamserver_#{ type }.json"
71
66
  filepath = File.join(destination, filename)
67
+ logger.debug('Writing to file', eventname: event_name, filename: filename, filepath: filepath)
72
68
  # Here is use append mode, because of a slightly possibility of overwriting an existing file
73
- File.open(filepath, 'a') do |f|
74
- if data_type.include?('reporting')
75
- f.write(Contrast::Utils::StringUtils.force_utf8(data))
76
- else
77
- f.write({ data_type: Contrast::Utils::StringUtils.force_utf8(data) }.to_json)
78
- end
79
- end
69
+ File.open(filepath, 'a') { |f| f.write(Contrast::Utils::StringUtils.force_utf8(data)) }
80
70
  rescue StandardError => e
81
71
  logger.warn('Saving audit failed', e: e)
82
72
  end
@@ -0,0 +1,38 @@
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/agent/reporting/reporting_events/preflight_message'
5
+ require 'contrast/agent/reporting/reporting_events/preflight'
6
+ require 'contrast/agent/reporting/reporting_events/route_discovery'
7
+ require 'contrast/agent/reporting/reporting_utilities/reporting_storage'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Reporting
12
+ # This module will handle the building of new preflights prior to
13
+ # sending them.
14
+ module BuildPreflight
15
+ class << self
16
+ # @param finding [Contrast::Agent::Reporting::Finding]
17
+ # @param request [Contrast::Agent::Request] current request
18
+ def build finding, request
19
+ return unless finding
20
+
21
+ # save the current finding
22
+ Contrast::Agent::Reporting::ReportingStorage[finding.hash_code] = finding
23
+
24
+ new_preflight = Contrast::Agent::Reporting::Preflight.new
25
+ new_preflight_message = Contrast::Agent::Reporting::PreflightMessage.new
26
+ if request&.route
27
+ new_preflight_message.routes << Contrast::Agent::Reporting::RouteDiscovery.convert(request.route)
28
+ end
29
+ new_preflight_message.hash_code = finding.hash_code
30
+ new_preflight_message.data = "#{ finding.rule_id },#{ finding.hash_code }"
31
+ new_preflight.messages << new_preflight_message
32
+ new_preflight
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/agent/reporting/reporting_events/server_activity'
5
+ require 'contrast/agent/reporting/reporting_events/application_activity'
5
6
  require 'contrast/api/dtm.pb'
6
7
 
7
8
  module Contrast
@@ -43,6 +44,12 @@ module Contrast
43
44
  dtm.cs__is_a?(Contrast::Api::Dtm::Finding)
44
45
  end
45
46
 
47
+ # @param dtm [Contrast::Api::Dtm::Finding,Object]
48
+ # @return [Boolean]
49
+ def activity? dtm
50
+ dtm.cs__is_a?(Contrast::Api::Dtm::Activity)
51
+ end
52
+
46
53
  # Converts DTM message to Reporting Event for those messages that have conversion methods crated. We use this
47
54
  # as we work to move away from requiring the Service.
48
55
  #
@@ -57,6 +64,7 @@ module Contrast
57
64
  return Contrast::Agent::Reporting::ObservedLibraryUsage.convert(dtm) if library_usage?(dtm)
58
65
  return Contrast::Agent::Reporting::ApplicationUpdate.convert(dtm) if application_update?(dtm)
59
66
  return Contrast::Agent::Reporting::Finding.convert(dtm) if finding?(dtm)
67
+ return Contrast::Agent::Reporting::ApplicationActivity.convert(dtm) if activity?(dtm)
60
68
 
61
69
  nil
62
70
  end
@@ -43,6 +43,12 @@ module Contrast
43
43
  end
44
44
  end
45
45
 
46
+ def application_activity
47
+ with_rescue do
48
+ NG_ENDPOINTS[:application_activity].cs__freeze
49
+ end
50
+ end
51
+
46
52
  # @return [String,nil]
47
53
  def library_usage
48
54
  with_rescue do
@@ -50,8 +50,8 @@ module Contrast
50
50
 
51
51
  # Check event type and send it to appropriate TS endpoint
52
52
  #
53
- # @param event [Contrast::Api::Dtm,Contrast::Agent::Reporting::ReportingEvent] One of the DTMs valid
54
- # for the event field of Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
53
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
54
+ # child of the ReportingEvent rather than a literal one.
55
55
  # @param connection [Net::HTTP] open connection
56
56
  # @param send_immediately [Boolean] flag for the logger
57
57
  # @return response [Net::HTTP::Response, nil] response from TS if no response
@@ -60,9 +60,14 @@ module Contrast
60
60
  return unless connection
61
61
 
62
62
  log_send_event(event) if send_immediately
63
- send_events(event, connection)
63
+ request = build_request(event)
64
+ response = connection.request(request)
65
+ audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable?
66
+ process_settings_response(response)
67
+ process_preflight_response(event, response, connection)
68
+ response
64
69
  rescue StandardError => e
65
- handle_error event, e
70
+ handle_error(event, e)
66
71
  end
67
72
 
68
73
  def status
@@ -16,39 +16,34 @@ module Contrast
16
16
  include Contrast::Components::Scope::InstanceMethods
17
17
  include Contrast::Agent::Reporting::Endpoints
18
18
 
19
- # List the events that need to be sent when agent starts up
19
+ # List the events that need to be sent when agent starts up.
20
+ # The order here matters -- DO NOT CHANGE IT!!! >_< - HM
21
+ #
22
+ # If you add more, update the test in reporter_client_spec.rb
20
23
  STARTUP_EVENTS = [
21
- Contrast::Agent::Reporting::ApplicationStartup,
22
- Contrast::Agent::Reporting::AgentStartup
24
+ Contrast::Agent::Reporting::AgentStartup,
25
+ Contrast::Agent::Reporting::ApplicationStartup
23
26
  ].cs__freeze
24
27
 
25
- # @param event [Contrast::Agent::Reporting::Preflight] the preflight we handle here
26
- # @param response [Net::HTTP::Response,nil] The response we handle and read from
27
- # @param connection [Net::HTTP] open connection
28
- def handle_response event, response, connection
29
- return unless event && response && connection
30
- return unless event.cs__is_a?(Contrast::Agent::Reporting::Preflight)
31
-
32
- preflight_message = event.messages[0]
33
- # for handling multiple findings
34
- # we'll only extract the indexes without *
35
- # findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
36
- # after that we'll do some magic and return them the same way we do for corresponding_finding
37
- corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.hash_code)
38
- return unless corresponding_finding
39
-
40
- audit&.audit_event(corresponding_finding, response) if ::Contrast::API.request_audit_enable?
41
- send_event(corresponding_finding, connection, send_immediately: true)
42
- nil
43
- rescue StandardError => e
44
- logger.error('Unable to handle response', e)
28
+ def audit
29
+ @_audit ||= Contrast::Agent::Reporting::Audit.new
45
30
  end
46
31
 
47
32
  private
48
33
 
49
- # TODO: RUBY-1466 find better home for this?
50
- def audit
51
- @_audit ||= Contrast::Agent::Reporting::Audit.new
34
+ # Send Agent Startup event
35
+ #
36
+ # @param connection [Net::HTTP] open connection
37
+ def send_agent_startup connection
38
+ logger.debug('Preparing to send startup messages')
39
+
40
+ STARTUP_EVENTS.each do |event|
41
+ startup_event = event.new
42
+ send_event(startup_event, connection, send_immediately: true)
43
+ rescue StandardError => e
44
+ handle_error(startup_event, e)
45
+ end
46
+ logger.debug('Startup messages sent')
52
47
  end
53
48
 
54
49
  # This method will build headers of the request required for TS communication
@@ -73,8 +68,8 @@ module Contrast
73
68
 
74
69
  # log the event sent immediately
75
70
  #
76
- # @param event [Contrast::Api::Dtm,Contrast::Agent::Reporting::ReportingEvent] One of the DTMs valid for the
77
- # event field of Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
71
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
72
+ # child of the ReportingEvent rather than a literal one.
78
73
  def log_send_event event
79
74
  logger.debug("#{ Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME } immediately sending event.",
80
75
  event_id: event.__id__, event_type: event.cs__class.cs__name)
@@ -82,7 +77,7 @@ module Contrast
82
77
 
83
78
  # Handles standard error case, logs and set status for failure
84
79
  #
85
- # @param event [Contrast::Api::Dtm, Contrast::Agent::Reporting::ReportingEvent]
80
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
86
81
  # One of the DTMs valid for the event field of Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
87
82
  # @param error_msg [StandardError]
88
83
  # @return nil [NilClass] to be passed as response
@@ -99,16 +94,41 @@ module Contrast
99
94
  # Handles response processing and sets status
100
95
  #
101
96
  # @param response [Net::HTTP::Response]
102
- def process_response response
97
+ def process_settings_response response
103
98
  response_handler.process(response)
104
- logger.debug('Successfully sent startup messages to service.')
99
+ logger.debug('Successfully sent startup messages to TeamServer.')
105
100
  status.success!
106
101
  end
107
102
 
108
- # build the request headers and assign endpoint
103
+ # Given a response from preflght, when the finding hash is desired, then send the finding to which it pertains.
104
+ # The method accepts any Contrast::Agent::Reporting::ReportingEvent, but will short circuit if it is not a
105
+ # Contrast::Agent::Reporting::Preflight.
109
106
  #
110
- # @param event event [Contrast::Agent::Reporting::ReportingEvent]
111
- # One of the DTMs valid for the event field of Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
107
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
108
+ # child of the ReportingEvent rather than a literal one.
109
+ # @param response [Net::HTTPResponse,nil] The response we handle and read from
110
+ # @param connection [Net::HTTP] open connection
111
+ def process_preflight_response event, response, connection
112
+ return unless event.cs__is_a?(Contrast::Agent::Reporting::Preflight)
113
+ return unless response && connection
114
+
115
+ findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
116
+ findings_to_return.each do |index|
117
+ preflight_message = event.messages[index.to_i]
118
+ corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.hash_code)
119
+ next unless corresponding_finding
120
+
121
+ send_event(corresponding_finding, connection)
122
+ end
123
+ rescue StandardError => e
124
+ logger.error('Unable to handle response', e)
125
+ end
126
+
127
+ # Convert the given event into an appropriate Net::HTTPRequest object, setting the request headers and
128
+ # assigning endpoint the endpoint appropriate for the event and casting its hash to a JSON body.
129
+ #
130
+ # @param event event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
131
+ # child of the ReportingEvent rather than a literal one.
112
132
  # @return [Net::HTTP::Post,Net::HTTP::Put]
113
133
  def build_request event
114
134
  with_contrast_scope do
@@ -124,39 +144,6 @@ module Contrast
124
144
  request
125
145
  end
126
146
  end
127
-
128
- # Send Agent Startup event
129
- #
130
- # @param connection [Net::HTTP] open connection
131
- def send_agent_startup connection
132
- logger.debug('Preparing to send startup messages')
133
-
134
- STARTUP_EVENTS.each do |event|
135
- startup_event = event.new
136
- request = build_request(startup_event)
137
- response = connection.request(request)
138
- process_response(response)
139
- rescue StandardError => e
140
- handle_error(startup_event, e)
141
- end
142
- end
143
-
144
- # Sent different events to different endpoints
145
- #
146
- # @param event [Contrast::Api::Dtm,Contrast::Agent::Reporting::ReportingEvent] Main reporting event, all events
147
- # inherit it
148
- # @param connection [Net::HTTP] open connection
149
- # @return [Net::HTTP::Response]
150
- def send_events event, connection
151
- request = build_request(event)
152
- response = connection.request(request)
153
- process_response(response)
154
- response
155
- rescue StandardError => e
156
- handle_error(event, e)
157
- end
158
-
159
- # Eventually here we'll handle more response types and etc
160
147
  end
161
148
  end
162
149
  end
@@ -13,16 +13,26 @@ module Contrast
13
13
  # At least one, but not necessarily all, setting will differ from the agent's current set.
14
14
  # Agents are able to replace all application settings with those in this message.
15
15
  #
16
- # @return application_settings [Contrast::Agent::Reporting::Settings::ApplicationSettings]
17
- def application_settings
18
- @_application_settings ||= Contrast::Agent::Reporting::Settings::ApplicationSettings.new
19
- end
16
+ # @return [Contrast::Agent::Reporting::Settings::ApplicationSettings, nil]
17
+ attr_accessor :application_settings
20
18
 
21
19
  # All of the feature server_features
22
20
  #
23
- # @return server_features [Contrast::Agent::Reporting::Settings::FeatureSettings]
24
- def server_features
25
- @_server_features ||= Contrast::Agent::Reporting::Settings::ServerFeatures.new
21
+ # @return server_features [Contrast::Agent::Reporting::Settings::FeatureSettings, nil]
22
+ attr_accessor :server_features
23
+
24
+ class << self
25
+ def application_response
26
+ res = new
27
+ res.application_settings = Contrast::Agent::Reporting::Settings::ApplicationSettings.new
28
+ res
29
+ end
30
+
31
+ def server_response
32
+ res = new
33
+ res.server_features = Contrast::Agent::Reporting::Settings::ServerFeatures.new
34
+ res
35
+ end
26
36
  end
27
37
  end
28
38
  end
@@ -15,7 +15,7 @@ module Contrast
15
15
  return unless assessments
16
16
 
17
17
  res.application_settings.assess.disabled_rules = assessments[:disabledRules]
18
- res.application_settings.assess.session_id = assessments[:sessionId]
18
+ res.application_settings.assess.session_id = assessments[:session_id]
19
19
  end
20
20
 
21
21
  # @param response_data [Hash]
@@ -24,6 +24,7 @@ module Contrast
24
24
  protect = response_data[:settings][:defend]
25
25
  return unless protect
26
26
 
27
+ # TODO: RUBY-1636 should this be `:rules` or `:protectionRules`
27
28
  res.application_settings.protect.protection_rules = protect[:protectionRules]
28
29
  res.application_settings.protect.virtual_patches = protect[:virtualPatches]
29
30
  end
@@ -48,7 +49,7 @@ module Contrast
48
49
  # @param response_data [Hash]
49
50
  # @param res [Contrast::Agent::Reporting::Response]
50
51
  def extract_assess_server_features response_data, res
51
- assess = response_data[:assessment]
52
+ assess = response_data[:features][:assessment]
52
53
  return unless assess
53
54
 
54
55
  res.server_features.assess.enabled = assess[:enabled]
@@ -60,18 +61,20 @@ module Contrast
60
61
  # @param response_data [Hash]
61
62
  # @param res [Contrast::Agent::Reporting::Response]
62
63
  def extract_protect_server_features response_data, res
63
- protect = response_data[:defend]
64
+ protect = response_data[:features][:defend]
64
65
  return unless protect
65
66
 
66
67
  res.server_features.protect.enabled = protect[:enabled]
67
- res.server_features.protect.bot_blocker = protect[:bot_blocker]
68
+ res.server_features.protect.bot_blocker = protect[:'bot-blocker']
69
+ # TODO: RUBY-1636 should this be `:rules` or `:protectionRules`
70
+ # process the botBlockers field
68
71
  res.server_features.protect.syslog = protect[:syslog]
69
72
  end
70
73
 
71
74
  # @param response_data [Hash]
72
75
  # @param res [Contrast::Agent::Reporting::Response]
73
76
  def extract_protect_lists response_data, res
74
- protect = response_data[:defend]
77
+ protect = response_data[:features][:defend]
75
78
  return unless protect
76
79
 
77
80
  res.server_features.protect.ip_allowlist = protect[:ipAllowlist]
@@ -14,7 +14,7 @@ module Contrast
14
14
  module Agent
15
15
  module Reporting
16
16
  # This class will facilitate the Response capture and analysis functionality.
17
- class ResponseHandler < Contrast::Api::Communication::ResponseProcessor
17
+ class ResponseHandler
18
18
  include Contrast::Components::Logger::InstanceMethods
19
19
  include Contrast::Agent::Reporting::ResponseHandlerUtils
20
20
  # 15 min
@@ -26,19 +26,19 @@ module Contrast
26
26
  # @return response [Net::HTTP::Response, nil]
27
27
  def process response
28
28
  logger.debug('Reporter Received a response')
29
- return unless analyze_response? response
29
+ return unless analyze_response?(response)
30
30
 
31
31
  # Handle the response body and obtain server_features or app_settings
32
- report_response = convert_response response
33
-
32
+ report_response = convert_response(response)
34
33
  return unless report_response
35
34
 
36
- update_agent_settings report_response
37
- update_reaction report_response
38
- # This one is called from super needs to be placed here after protobuf end of life.
39
- update_features(report_response.server_features, report_response.application_settings)
40
- logger.trace('Agent settings updated in response to Service', protect_on: ::Contrast::PROTECT.enabled?,
41
- assess_on: ::Contrast::ASSESS.enabled?)
35
+ # Update Server Features and Application Settings to provide current agent settings
36
+ update_agent_settings(report_response)
37
+ # Process any reactions, including message logging and shutting down
38
+ update_reaction(report_response)
39
+ update_ruleset(report_response)
40
+ logger.trace('Agent settings updated in response to TeamServer', protect_on: ::Contrast::PROTECT.enabled?,
41
+ assess_on: ::Contrast::ASSESS.enabled?)
42
42
  response
43
43
  rescue StandardError => e
44
44
  logger.error('Unable to process response from TeamServer', e)