contrast-agent 6.2.0 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
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'