contrast-agent 6.2.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
  3. data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
  4. data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
  5. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
  6. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
  7. data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
  8. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
  9. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
  10. data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
  11. data/ext/cs__common/cs__common.c +5 -4
  12. data/ext/cs__contrast_patch/cs__contrast_patch.c +3 -10
  13. data/lib/contrast/agent/assess/events/source_event.rb +16 -12
  14. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
  15. data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -39
  16. data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
  17. data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
  18. data/lib/contrast/agent/assess/policy/source_method.rb +2 -47
  19. data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
  20. data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
  21. data/lib/contrast/agent/assess/property/evented.rb +4 -18
  22. data/lib/contrast/agent/assess/tag.rb +19 -0
  23. data/lib/contrast/agent/at_exit_hook.rb +8 -8
  24. data/lib/contrast/agent/inventory/database_config.rb +6 -3
  25. data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
  26. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +10 -10
  27. data/lib/contrast/agent/middleware.rb +4 -0
  28. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
  29. data/lib/contrast/agent/patching/policy/policy.rb +5 -0
  30. data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
  31. data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
  32. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
  33. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
  34. data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
  35. data/lib/contrast/agent/protect/rule/base.rb +1 -0
  36. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
  37. data/lib/contrast/agent/reporting/reporter.rb +32 -7
  38. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
  39. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  40. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  41. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +8 -1
  42. data/lib/contrast/agent/reporting/reporting_events/finding.rb +7 -1
  43. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  44. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  45. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  46. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  47. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  48. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  49. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  50. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  51. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  52. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  53. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +13 -1
  54. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -8
  55. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -5
  56. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -1
  57. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +9 -1
  58. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  59. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  60. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  61. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -4
  62. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -22
  63. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -3
  64. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  65. data/lib/contrast/agent/request.rb +5 -7
  66. data/lib/contrast/agent/request_context.rb +8 -17
  67. data/lib/contrast/agent/request_context_extend.rb +8 -9
  68. data/lib/contrast/agent/request_handler.rb +9 -38
  69. data/lib/contrast/agent/rule_set.rb +4 -0
  70. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  71. data/lib/contrast/agent/static_analysis.rb +6 -11
  72. data/lib/contrast/agent/telemetry/base.rb +35 -35
  73. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  74. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  75. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  76. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  77. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  78. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  79. data/lib/contrast/agent/thread_watcher.rb +1 -4
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/api/communication/socket.rb +1 -0
  82. data/lib/contrast/api/decorators/message.rb +0 -6
  83. data/lib/contrast/api/decorators.rb +0 -2
  84. data/lib/contrast/components/assess.rb +0 -6
  85. data/lib/contrast/components/config.rb +18 -2
  86. data/lib/contrast/config/base_configuration.rb +0 -13
  87. data/lib/contrast/config/root_configuration.rb +1 -0
  88. data/lib/contrast/config/ruby_configuration.rb +2 -9
  89. data/lib/contrast/configuration.rb +0 -2
  90. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  91. data/lib/contrast/extension/assess/hash.rb +3 -2
  92. data/lib/contrast/extension/assess/kernel.rb +22 -0
  93. data/lib/contrast/extension/assess/marshal.rb +16 -0
  94. data/lib/contrast/extension/assess/string.rb +21 -20
  95. data/lib/contrast/framework/base_support.rb +8 -0
  96. data/lib/contrast/framework/manager.rb +6 -20
  97. data/lib/contrast/framework/manager_extend.rb +0 -1
  98. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -16
  99. data/lib/contrast/logger/aliased_logging.rb +2 -0
  100. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  101. data/lib/contrast/utils/lru_cache.rb +3 -0
  102. data/lib/contrast/utils/middleware_utils.rb +2 -0
  103. data/lib/contrast/utils/telemetry_client.rb +7 -7
  104. data/resources/assess/policy.json +2 -11
  105. data/ruby-agent.gemspec +1 -1
  106. metadata +22 -20
  107. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  108. data/lib/contrast/api/decorators/application_update.rb +0 -44
  109. data/lib/contrast/api/decorators/library.rb +0 -56
  110. data/lib/contrast/framework/platform_version.rb +0 -22
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'contrast/api/dtm.pb'
5
5
  require 'contrast/utils/string_utils'
6
+ require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
8
9
  module Agent
@@ -16,6 +17,8 @@ module Contrast
16
17
  # @attr_reader verb [String] the HTTP Method requested to his this endpoint. Empty means all, so is allowed.
17
18
  # for reporting.
18
19
  class RouteDiscoveryObservation
20
+ include Contrast::Components::Logger::InstanceMethods
21
+
19
22
  # required attributes
20
23
  attr_reader :url
21
24
  # optional attributes
@@ -47,10 +50,14 @@ module Contrast
47
50
  # @return [Hash]
48
51
  # @raise [ArgumentError]
49
52
  def to_controlled_hash
50
- validate
51
- hash = { url: url }
52
- hash[:verb] = verb if verb
53
- hash
53
+ begin
54
+ validate
55
+ rescue ArgumentError => e
56
+ logger.error('RouteDiscoveryObservation validation failed with: ', e)
57
+ return
58
+ end
59
+
60
+ { url: url, verb: verb }.compact
54
61
  end
55
62
 
56
63
  # Ensure the required fields are present.
@@ -12,14 +12,6 @@ module Contrast
12
12
  # for its response, which contains any updated server feature settings from TeamServer. The new Server Settings
13
13
  # endpoint should let us remove this.
14
14
  class ServerActivity < Contrast::Agent::Reporting::ServerReportingEvent
15
- class << self
16
- # @param _server_activity_dtm [Contrast::Api::Dtm::ServerActivity]
17
- # @return [Contrast::Agent::Reporting::ServerActivity]
18
- def convert _server_activity_dtm
19
- new
20
- end
21
- end
22
-
23
15
  def initialize
24
16
  @event_method = :PUT
25
17
  @event_endpoint = "#{ Contrast::API.api_url }/api/ng/activity/server"
@@ -44,10 +44,7 @@ module Contrast
44
44
  # @param file_name[String] file_name to log
45
45
  # @param data[String] String representation if the logged data
46
46
  def log_data type, file_name, data = nil
47
- return unless enabled?
48
-
49
- logger.debug('logging to file', file_name: file_name) # TODO: RUBY-99999 DO NOT COMMIT THIS
50
- write_to_file(type, file_name, data)
47
+ write_to_file(type, file_name, data) if enabled?
51
48
  end
52
49
 
53
50
  # This method will be actually writing to the file
@@ -1,7 +1,6 @@
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/server_activity'
5
4
  require 'contrast/agent/reporting/reporting_events/application_activity'
6
5
  require 'contrast/api/dtm.pb'
7
6
 
@@ -13,22 +12,6 @@ module Contrast
13
12
  # TODO: RUBY-1438 -- remove
14
13
  module DtmMessage
15
14
  class << self
16
- # Checks if the message is of Contrast::Api::Dtm::ServerActivity class
17
- #
18
- # @param dtm [Contrast::Api::Dtm::ServerActivity, Object]
19
- # @return [Boolean]
20
- def server_activity? dtm
21
- dtm.cs__is_a?(Contrast::Api::Dtm::ServerActivity)
22
- end
23
-
24
- # Checks if the message is of Contrast::Api::Dtm::ApplicationUpdate class
25
- #
26
- # @param dtm [Contrast::Api::Dtm::ApplicationUpdate,Object]
27
- # @return [Boolean]
28
- def application_update? dtm
29
- dtm.cs__is_a?(Contrast::Api::Dtm::ApplicationUpdate)
30
- end
31
-
32
15
  # @param dtm [Contrast::Api::Dtm::Finding,Object]
33
16
  # @return [Boolean]
34
17
  def finding? dtm
@@ -47,12 +30,7 @@ module Contrast
47
30
  # @param dtm [Contrast::Api::Dtm]
48
31
  # @return event [Contrast::Agent::Reporting::ReportingEvent, nil]
49
32
  def dtm_to_event dtm
50
- # For the ServerActivity we need to create and send empty body only. This is done because we need the
51
- # response from TS.
52
- return Contrast::Agent::Reporting::ServerActivity.new if server_activity?(dtm)
53
-
54
33
  # For the others, we convert them.
55
- return Contrast::Agent::Reporting::ApplicationUpdate.convert(dtm) if application_update?(dtm)
56
34
  return Contrast::Agent::Reporting::Finding.convert(dtm) if finding?(dtm)
57
35
  return Contrast::Agent::Reporting::ApplicationActivity.convert(dtm) if activity?(dtm)
58
36
 
@@ -53,12 +53,10 @@ module Contrast
53
53
  # @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
54
54
  # child of the ReportingEvent rather than a literal one.
55
55
  # @param connection [Net::HTTP] open connection
56
- # @param send_immediately [Boolean] flag for the logger
57
56
  # @return response [Net::HTTP::Response, nil] response from TS if no response
58
- def send_event event, connection, send_immediately: false
57
+ def send_event event, connection
59
58
  return unless connection
60
59
 
61
- log_send_event(event) if send_immediately
62
60
  request = build_request(event)
63
61
  response = connection.request(request)
64
62
  audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable?
@@ -39,7 +39,7 @@ module Contrast
39
39
 
40
40
  STARTUP_EVENTS.each do |event|
41
41
  startup_event = event.new
42
- send_event(startup_event, connection, send_immediately: true)
42
+ send_event(startup_event, connection)
43
43
  rescue StandardError => e
44
44
  handle_error(startup_event, e)
45
45
  end
@@ -66,15 +66,6 @@ module Contrast
66
66
  request
67
67
  end
68
68
 
69
- # log the event sent immediately
70
- #
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.
73
- def log_send_event event
74
- logger.debug("#{ Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME } immediately sending event.",
75
- event_id: event.__id__, event_type: event.cs__class.cs__name)
76
- end
77
-
78
69
  # Handles standard error case, logs and set status for failure
79
70
  #
80
71
  # @param event [Contrast::Agent::Reporting::ReportingEvent]
@@ -96,7 +87,6 @@ module Contrast
96
87
  # @param response [Net::HTTP::Response]
97
88
  def process_settings_response response
98
89
  response_handler.process(response)
99
- logger.debug('Successfully sent startup messages to TeamServer.')
100
90
  status.success!
101
91
  end
102
92
 
@@ -17,12 +17,6 @@ module Contrast
17
17
  # provides access to the original Rack::Request object as well as extracts
18
18
  # data in a format that the Agent expects, caching those transformations in
19
19
  # order to avoid repeatedly creating Strings & thrashing GC.
20
- #
21
- # @attr_reader rack_request [Rack::Request] The passed to the Agent RackRequest to be wrapped.
22
- # @attr_accessor route [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
23
- # @attr_accessor observed_route [Contrast::Api::Dtm::ObservedRoute] the route, used for coverage of this request
24
- # @attr_accessor new_observed_route [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of
25
- # this request
26
20
  class Request
27
21
  include Contrast::Utils::RequestUtils
28
22
  include Contrast::Components::Logger::InstanceMethods
@@ -37,8 +31,12 @@ module Contrast
37
31
  STATIC_SUFFIXES = /\.(?:js|css|jpeg|jpg|gif|png|ico|woff|svg|pdf|eot|ttf|jar)$/i.cs__freeze
38
32
  MEDIA_TYPE_MARKERS = %w[image/ text/css text/javascript].cs__freeze
39
33
 
34
+ # @return [Rack::Request] The passed to the Agent RackRequest to be wrapped.
40
35
  attr_reader :rack_request
41
- attr_accessor :route, :observed_route, :new_observed_route
36
+ # @return [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
37
+ attr_accessor :route
38
+ # @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
39
+ attr_accessor :observed_route
42
40
 
43
41
  # Delegate calls to the following methods to the attribute @rack_request
44
42
  def_delegators :@rack_request, :base_url, :cookies, :env, :ip, :media_type, :path, :port, :query_string,
@@ -30,8 +30,6 @@ module Contrast
30
30
  # @return [Hash] context used to log the request
31
31
  attr_reader :logging_hash
32
32
  # @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
33
- attr_reader :new_observed_route
34
- # @return [Contrast::Api::Dtm::ObservedRoute] the route, used for coverage, of this request
35
33
  attr_reader :observed_route
36
34
  # @return [Contrast::Agent::Request] our wrapper around the Rack::Request for this context
37
35
  attr_reader :request
@@ -40,15 +38,10 @@ module Contrast
40
38
  attr_reader :response
41
39
  # @return [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
42
40
  attr_reader :route
43
- # @return [Contrast::Api::Dtm::ServerActivity] the server activity found in this request
44
- attr_reader :server_activity
45
41
  # @return [Contrast::Api::Settings::InputAnalysis] the protect input analysis of sources on this request
46
42
  attr_reader :speedracer_input_analysis
47
43
  # @return [Contrast::Utils::Timer] when the context was created
48
44
  attr_reader :timer
49
- # @return [Contrast::Agent::Reporting::ObservedLibraryUsage] List of the libraries that have been observed to be
50
- # executed or to have something loaded. This here replaces part of the Activity Dtm
51
- attr_reader :observed_library_usage
52
45
 
53
46
  def initialize rack_request, app_loaded: true
54
47
  with_contrast_scope do
@@ -62,9 +55,6 @@ module Contrast
62
55
  @activity = Contrast::Api::Dtm::Activity.new
63
56
  @activity.http_request = request.dtm
64
57
 
65
- @server_activity = Contrast::Api::Dtm::ServerActivity.new
66
- @observed_library_usage = Contrast::Agent::Reporting::ObservedLibraryUsage.new
67
-
68
58
  # build analyzer
69
59
  @do_not_track = false
70
60
  @speedracer_input_analysis = EMPTY_INPUT_ANALYSIS_PB
@@ -128,20 +118,21 @@ module Contrast
128
118
 
129
119
  def reset_activity
130
120
  @activity = Contrast::Api::Dtm::Activity.new(http_request: request.dtm)
131
- @server_activity = Contrast::Api::Dtm::ServerActivity.new
132
- @observed_route = Contrast::Api::Dtm::ObservedRoute.new # TODO: RUBY-1438 -- remove
133
- @new_observed_route = Contrast::Agent::Reporting::ObservedRoute.new
121
+ @observed_route = Contrast::Agent::Reporting::ObservedRoute.new
134
122
  end
135
123
 
136
124
  private
137
125
 
138
126
  def handle_routes
139
- @observed_route = Contrast::Api::Dtm::ObservedRoute.new # TODO: RUBY-1438 -- remove
140
- @new_observed_route = Contrast::Agent::Reporting::ObservedRoute.new
127
+ @observed_route = Contrast::Agent::Reporting::ObservedRoute.new
128
+ # TODO: RUBY-1705 when we no longer need the DTM style, delete this method and use the get_route_information
129
+ # instead.
141
130
  route_dtm = Contrast::Agent.framework_manager.get_route_dtm(@request)
142
- new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
131
+ # new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
132
+ # TODO: RUBY-1705 -- delete append_route_coverage
143
133
  append_route_coverage(route_dtm)
144
- append_to_new_observed_route(new_route_coverage_dtm)
134
+ # TODO: RUBY-1705 -- change to take [Contrast::Agent::Reporting::ObservedRoute]
135
+ append_to_observed_route(route_dtm)
145
136
  end
146
137
  end
147
138
  end
@@ -38,23 +38,20 @@ module Contrast
38
38
  @activity.routes << route
39
39
 
40
40
  # For TS routes
41
- @observed_route.signature = route.route
42
- @observed_route.verb = route.verb
43
- @observed_route.url = route.url if route.url
44
41
  @request.route = route
45
- @request.observed_route = @observed_route
46
42
  end
47
43
 
48
44
  # Convert the discovered route for this request to appropriate forms and disseminate it to those locations
49
45
  # where it is necessary for our route coverage and finding vulnerability discovery features to function.
50
46
  #
51
- def append_to_new_observed_route route
47
+ # @param route [Contrast::Api::Dtm::RouteCoverage]
48
+ def append_to_observed_route route
52
49
  return unless route
53
50
 
54
- @new_observed_route.signature = route.route
55
- @new_observed_route.verb = route.verb
56
- @new_observed_route.url = route.url if route.url
57
- @request.new_observed_route = @new_observed_route
51
+ @observed_route.signature = route.route
52
+ @observed_route.verb = route.verb
53
+ @observed_route.url = route.url if route.url
54
+ @request.observed_route = @observed_route
58
55
  end
59
56
 
60
57
  # Collect the results for the given rule with the given action
@@ -71,6 +68,7 @@ module Contrast
71
68
  end
72
69
  end
73
70
 
71
+ # @raise [Contrast::SecurityException]
74
72
  def service_extract_request
75
73
  return false unless ::Contrast::AGENT.enabled?
76
74
  return false unless ::Contrast::PROTECT.enabled?
@@ -105,6 +103,7 @@ module Contrast
105
103
  # Normally these should be generated on Speedracer for any attacks detected during prefilter.
106
104
  #
107
105
  # @param agent_settings [Contrast::Api::Settings::AgentSettings]
106
+ # @raise[Contrast::SecurityException]
108
107
  def handle_protect_state agent_settings
109
108
  return unless agent_settings&.protect_state
110
109
 
@@ -22,56 +22,27 @@ module Contrast
22
22
  @ruleset = ::Contrast::AGENT.ruleset
23
23
  end
24
24
 
25
- # Send Activities messages to TS [Contrast::Agent::Reporting::ServerActivity,
26
- # Contrast::Api::Dtm::ServerActivity,
27
- # Contrast::Api::Dtm::Activity,
28
- # Contrast::Api::Dtm::ObservedRoute]
29
- # If bypass is enabled use the reporting service if not than the messages are
30
- # send with speedracer
31
- # TODO: RUBY-1355
32
- # TODO: RUBY-1358
33
- # TODO: RUBY-1438 -- remove
25
+ # Send Activities messages to TS [Contrast::Api::Dtm::Activity]
26
+ # TODO: RUBY-1704
27
+ # TODO: RUBY-1438
34
28
  def send_activity_messages
35
- events = [context.activity]
36
- unless Contrast::Agent::Reporter.enabled?
37
- events << context.server_activity
38
- events << context.observed_route
39
- end
40
- events.each do |message|
41
- Contrast::Agent.messaging_queue&.send_event_eventually(message)
42
- end
29
+ Contrast::Agent.messaging_queue&.send_event_eventually(context.activity)
43
30
  end
44
31
 
45
32
  # reports events[Contrast::Agent::Reporting::ReporterEvent] to TS
46
33
  # This method is used to send our JSON messages directly to TeamServer at the end of each request. As we move
47
34
  # more endpoints over, this method will take the messages originally sent by #send_actiivty_messages. At the end,
48
35
  # that method should be removed.
49
- def report_activity # rubocop:disable Metrics/AbcSize
50
- Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.
51
- generate_library_usage(context.observed_library_usage)
36
+ def report_activity
37
+ return unless (reporter = Contrast::Agent.reporter)
52
38
 
53
- Contrast::Agent.reporter.send_event(context.observed_library_usage)
39
+ reporter.send_event(context.observed_route)
54
40
  return unless Contrast::Agent::Reporter.enabled?
55
41
 
56
- reporter = Contrast::Agent.reporter
57
- return unless reporter
58
-
59
42
  # Mask Sensitive Data
60
43
  Contrast::Agent::Reporting::Masker.mask(context.activity)
61
-
62
- Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.
63
- generate_library_usage(context.observed_library_usage)
64
- [
65
- context.new_observed_route,
66
- context.observed_library_usage,
67
- Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.server_activity),
68
- Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
69
- ].each do |event|
70
- reporter.send_event(event)
71
- rescue StandardError => e
72
- logger.warn('Unable to send Event Activity', e)
73
- end
74
- context.observed_library_usage.clear # TODO: RUBY-1355 remove when no longer using activity
44
+ event = Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
45
+ reporter.send_event(event)
75
46
  end
76
47
 
77
48
  # If the response is streaming, we should only perform filtering on our stream safe rules
@@ -14,6 +14,8 @@ module Contrast
14
14
  # The main action here is snapshotting the request as provided to the application from the
15
15
  # user before any application code has acted upon it. Additionally, this is where Protect will
16
16
  # terminate requests on attack detection if set to block at perimeter
17
+ #
18
+ # @raise [Contrast::SecurityException] raises error if security exception is thrown in prefilter
17
19
  def prefilter
18
20
  context = Contrast::Agent::REQUEST_TRACKER.current
19
21
  return unless context&.analyze_request?
@@ -30,6 +32,8 @@ module Contrast
30
32
 
31
33
  # The filtering that needs occur after the application has acted on the request and the response
32
34
  # has been created. The main actions here are analyzing the response for unsafe state or actions.
35
+ #
36
+ # @raise [Contrast::SecurityException] raises error if security exception is thrown in postfilter
33
37
  def postfilter
34
38
  context = Contrast::Agent::REQUEST_TRACKER.current
35
39
  return unless context&.analyze_response?
@@ -22,7 +22,7 @@ module Contrast
22
22
  @_thread = Contrast::Agent::Thread.new do
23
23
  logger.info('Starting heartbeat thread.')
24
24
  loop do
25
- Contrast::Agent.messaging_queue.send_event_eventually(poll_message)
25
+ Contrast::Agent.messaging_queue&.send_event_eventually(poll_message)
26
26
  sleep(REFRESH_INTERVAL_SEC)
27
27
  end
28
28
  end
@@ -4,7 +4,6 @@
4
4
  require 'contrast/components/logger'
5
5
  require 'contrast/components/scope'
6
6
  require 'contrast/agent/reporting/reporting_events/application_update'
7
- require 'contrast/api/decorators/application_update'
8
7
 
9
8
  module Contrast
10
9
  module Agent
@@ -24,20 +23,16 @@ module Contrast
24
23
  end
25
24
  end
26
25
 
27
- # TODO: RUBY-1703
28
26
  def send_inventory_message
29
27
  return unless ::Contrast::INVENTORY.enabled?
30
28
 
31
- app_update_msg = Contrast::Api::Dtm::ApplicationUpdate.build
32
- Contrast::Agent::Inventory::DatabaseConfig.append_db_config(app_update_msg)
33
- # TODO: RUBY-1703 -- remove and build ReportingEvent directly
34
- if Contrast::Agent::Reporter.enabled?
35
- report = Contrast::Agent::Reporting::DtmMessage.dtm_to_event(app_update_msg)
36
- Contrast::Agent.reporter.send_event(report)
37
- else
38
- Contrast::Agent.messaging_queue.send_event_eventually(app_update_msg, force: true)
29
+ report = Contrast::Agent::Reporting::ApplicationUpdate.new
30
+ # This convert here is left as it'll be easier to be replaced when the Library is being changed
31
+ report.libraries = Contrast::Agent::Inventory::DependencyAnalysis.instance.library_pb_list
32
+ Contrast::Agent::Inventory::DatabaseConfig.append_db_config(report)
33
+ [report, Contrast::Agent::Reporting::ApplicationInventory.new].each do |e|
34
+ Contrast::Agent.reporter.send_event(e)
39
35
  end
40
- Contrast::Agent.reporter.send_event(Contrast::Agent::Reporting::ApplicationInventory.new)
41
36
  end
42
37
 
43
38
  private
@@ -7,7 +7,6 @@ require 'contrast/utils/telemetry_client'
7
7
  require 'contrast/agent/worker_thread'
8
8
  require 'contrast/utils/telemetry'
9
9
  require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions'
10
- require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report'
11
10
 
12
11
  module Contrast
13
12
  module Agent
@@ -15,7 +14,6 @@ module Contrast
15
14
  # This class will initialize and hold everything needed for the telemetry
16
15
  class Base < WorkerThread
17
16
  include Contrast::Components::Logger::InstanceMethods
18
- include Contrast::Agent::Telemetry::TelemetryExceptionReport
19
17
 
20
18
  # this is where we will send the data from the agents
21
19
  URL = 'https://telemetry.ruby.contrastsecurity.com/'
@@ -66,10 +64,6 @@ module Contrast
66
64
  @_connection ||= client.initialize_connection(URL)
67
65
  end
68
66
 
69
- def error_messages
70
- @_error_messages ||= []
71
- end
72
-
73
67
  def attempt_to_start?
74
68
  unless cs__class.enabled?
75
69
  logger.warn('Telemetry service is disabled!')
@@ -83,34 +77,8 @@ module Contrast
83
77
  def start_thread!
84
78
  return if running?
85
79
 
86
- # It is recommended that implementations send a single payload of
87
- # general metrics every 3 hours, starting from implementation startup.
88
- @_thread = Contrast::Agent::Thread.new do
89
- logger.debug('Starting background telemetry thread.')
90
- loop do
91
- next unless client && connection
92
-
93
- # Start pushing exceptions to queue for reporting.
94
- push_exceptions
95
- until queue.empty?
96
- event = queue.pop
97
- begin
98
- logger.debug('This is the current processed event', event)
99
- sleep_time = request_with_response(event)
100
- if sleep_time
101
- sleep(sleep_time)
102
- logger.debug('Retrying to process event', event)
103
- retry_sleep_time = request_with_response(event)
104
- sleep(retry_sleep_time) unless retry_sleep_time.nil?
105
- end
106
- rescue StandardError => e
107
- logger.error('Could not send message to service from telemetry queue.', e)
108
- stop!
109
- end
110
- end
111
- sleep(SUGGESTED_TIMEOUT)
112
- end
113
- end
80
+ logger.debug('Starting background telemetry thread.')
81
+ @_thread = create_thread
114
82
  end
115
83
 
116
84
  def send_event event
@@ -126,7 +94,6 @@ module Contrast
126
94
  end
127
95
 
128
96
  def delete_queue!
129
- @_queue&.clear
130
97
  @_queue&.close
131
98
  @_queue = nil
132
99
  end
@@ -149,6 +116,39 @@ module Contrast
149
116
  def queue
150
117
  @_queue ||= Queue.new
151
118
  end
119
+
120
+ # It is recommended that implementations send a single payload of general metrics every 3 hours, starting from
121
+ # implementation startup. This returns a thread configured to do so.
122
+ #
123
+ # @return [Contrast::Agent::Thread]
124
+ def create_thread
125
+ Contrast::Agent::Thread.new do
126
+ loop do
127
+ next unless client && connection
128
+
129
+ # Start pushing exceptions to queue for reporting.
130
+ Contrast::TELEMETRY_EXCEPTIONS.each_value { |value| queue << value }
131
+ Contrast::TELEMETRY_EXCEPTIONS.clear
132
+ until queue.empty?
133
+ event = queue.pop
134
+ begin
135
+ logger.debug('This is the current processed event', event)
136
+ sleep_time = request_with_response(event)
137
+ if sleep_time
138
+ sleep(sleep_time)
139
+ logger.debug('Retrying to process event', event)
140
+ retry_sleep_time = request_with_response(event)
141
+ sleep(retry_sleep_time) unless retry_sleep_time.nil?
142
+ end
143
+ rescue StandardError => e
144
+ logger.error('Could not send message to service from telemetry queue.', e)
145
+ stop!
146
+ end
147
+ end
148
+ sleep(SUGGESTED_TIMEOUT)
149
+ end
150
+ end
151
+ end
152
152
  end
153
153
  end
154
154
  end
@@ -28,6 +28,7 @@ module Contrast
28
28
  #
29
29
  # @param validation_pair [Hash] Validation hash to use
30
30
  # @param key[String] The key to check in VALIDATIONS
31
+ # @raise [ArgumentError]
31
32
  def validate_field validation_pair, key
32
33
  value_to_validate = send(key.to_sym)
33
34
  validate_class(value_to_validate, validation_pair[:class], key) if validation_pair.key?(:class)
@@ -48,6 +49,7 @@ module Contrast
48
49
  # @param message [Object] The message we want to check the class of
49
50
  # @param klass [Class] The klass we want to check the message with
50
51
  # @param field [Object] The field with the error
52
+ # @raise [ArgumentError]
51
53
  def validate_class message, klass, field
52
54
  message = message[0] if message.cs__is_a?(Array)
53
55
  raise(ArgumentError, "The provided value for #{ field } is of wrong class") unless message.cs__is_a?(klass)
@@ -18,6 +18,7 @@ module Contrast
18
18
  # to be created
19
19
  #
20
20
  # @param message [Contrast::Agent::Telemetry::TelemetryException::Message]
21
+ # @raise[ArgumentError]
21
22
  def initialize message
22
23
  super()
23
24
  validate_class(message, Contrast::Agent::Telemetry::TelemetryException::Message, 'exception_message')
@@ -25,6 +26,7 @@ module Contrast
25
26
  end
26
27
 
27
28
  # @param message [Contrast::Agent::Telemetry::TelemetryException::Message]
29
+ # @raise[ArgumentError]
28
30
  def push message
29
31
  validate_class(message, Contrast::Agent::Telemetry::TelemetryException::Message, 'exception_message')
30
32
  @exceptions << message
@@ -50,6 +50,7 @@ module Contrast
50
50
  # @return [String | nil] A string message to provide additional context to the errors.
51
51
  attr_reader :message
52
52
 
53
+ # @raise[ArgumentError]
53
54
  def initialize instance, tags, exceptions
54
55
  super()
55
56
  @tags = tags
@@ -63,17 +64,19 @@ module Contrast
63
64
  # Optional parameters will be set separately from the required
64
65
  #
65
66
  # @param logger[String]
67
+ # @raise[ArgumentError]
66
68
  def logger= logger
67
- validate_field(VALIDATIONS[:logger], 'logger')
68
69
  @logger = logger
70
+ validate_field(VALIDATIONS[:logger], 'logger')
69
71
  end
70
72
 
71
73
  # Optional parameters will be set separately from the required
72
74
  #
73
75
  # @param message[String]
76
+ # @raise[ArgumentError]
74
77
  def message= message
75
- validate_field(VALIDATIONS[:message], 'message')
76
78
  @message = message
79
+ validate_field(VALIDATIONS[:message], 'message')
77
80
  end
78
81
 
79
82
  # Optional parameters will be set separately from the required
@@ -43,16 +43,19 @@ module Contrast
43
43
  end
44
44
 
45
45
  # @param stack_frame [Contrast::Agent::Telemetry::TelemetryException::StackFrame]
46
+ # @raise[ArgumentError]
46
47
  def push stack_frame
47
48
  validate_class(stack_frame, Contrast::Agent::Telemetry::TelemetryException::StackFrame, 'stack_frame')
48
49
  @stack_frames << stack_frame
49
50
  end
50
51
 
52
+ # @raise[ArgumentError]
51
53
  def module_name= module_name
52
54
  @module_name = module_name
53
55
  validate_field(VALIDATIONS[:module_name], 'module_name')
54
56
  end
55
57
 
58
+ # @raise[ArgumentError]
56
59
  def value= value
57
60
  @value = value
58
61
  validate_field(VALIDATIONS[:value], 'value')
@@ -28,6 +28,7 @@ module Contrast
28
28
  # @return [String]
29
29
  attr_reader :module_name
30
30
 
31
+ # @raise [ArgumentError]
31
32
  def initialize function, type
32
33
  super()
33
34
  @function = function
@@ -36,11 +37,13 @@ module Contrast
36
37
  validate(VALIDATIONS)
37
38
  end
38
39
 
40
+ # @raise [ArgumentError]
39
41
  def module_name= module_name
40
42
  @module_name = module_name
41
43
  validate_field(VALIDATIONS[:module_name], 'module_name')
42
44
  end
43
45
 
46
+ # @raise [ArgumentError]
44
47
  def to_controlled_hash
45
48
  super
46
49
  { function: function, type: type, module: module_name, inContrast: in_contrast }.compact
@@ -17,4 +17,3 @@ require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_fr
17
17
  require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception'
18
18
  require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_message'
19
19
  require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
20
- require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report'