contrast-agent 6.2.0 → 6.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.simplecov +1 -0
  4. data/Rakefile +0 -27
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
  6. data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
  7. data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
  8. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
  9. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
  10. data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
  11. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
  12. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
  13. data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
  14. data/ext/cs__common/cs__common.c +5 -4
  15. data/ext/cs__contrast_patch/cs__contrast_patch.c +17 -11
  16. data/lib/contrast/agent/assess/events/source_event.rb +16 -12
  17. data/lib/contrast/agent/assess/finalizers/hash.rb +1 -0
  18. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
  19. data/lib/contrast/agent/assess/policy/propagation_method.rb +8 -42
  20. data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
  21. data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
  22. data/lib/contrast/agent/assess/policy/propagator/custom.rb +4 -0
  23. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -0
  24. data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -0
  25. data/lib/contrast/agent/assess/policy/source_method.rb +7 -47
  26. data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
  27. data/lib/contrast/agent/assess/policy/trigger_method.rb +9 -3
  28. data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
  29. data/lib/contrast/agent/assess/property/evented.rb +4 -18
  30. data/lib/contrast/agent/assess/tag.rb +19 -0
  31. data/lib/contrast/agent/assess/tracker.rb +12 -0
  32. data/lib/contrast/agent/at_exit_hook.rb +8 -8
  33. data/lib/contrast/agent/inventory/database_config.rb +6 -3
  34. data/lib/contrast/agent/inventory/dependency_analysis.rb +5 -4
  35. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +11 -11
  36. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
  37. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  38. data/lib/contrast/agent/middleware.rb +4 -0
  39. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
  40. data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
  41. data/lib/contrast/agent/patching/policy/policy.rb +5 -0
  42. data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
  43. data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
  44. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
  45. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
  46. data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
  47. data/lib/contrast/agent/protect/rule/base.rb +1 -0
  48. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
  49. data/lib/contrast/agent/reporting/reporter.rb +32 -7
  50. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +22 -18
  51. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +17 -21
  52. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -1
  53. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +26 -3
  54. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  55. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  56. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +8 -1
  57. data/lib/contrast/agent/reporting/reporting_events/finding.rb +7 -1
  58. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  59. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  60. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  61. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  62. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  63. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  64. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  65. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  66. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  67. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  68. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +13 -1
  69. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -8
  70. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -5
  71. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -1
  72. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +9 -1
  73. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  74. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  75. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  76. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -4
  77. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -22
  78. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -3
  79. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  80. data/lib/contrast/agent/request.rb +5 -7
  81. data/lib/contrast/agent/request_context.rb +16 -17
  82. data/lib/contrast/agent/request_context_extend.rb +8 -9
  83. data/lib/contrast/agent/request_handler.rb +9 -38
  84. data/lib/contrast/agent/rule_set.rb +4 -0
  85. data/lib/contrast/agent/service_heartbeat.rb +3 -4
  86. data/lib/contrast/agent/static_analysis.rb +7 -12
  87. data/lib/contrast/agent/telemetry/base.rb +35 -35
  88. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  89. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  90. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  91. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  92. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  93. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  94. data/lib/contrast/agent/thread_watcher.rb +1 -4
  95. data/lib/contrast/agent/version.rb +1 -1
  96. data/lib/contrast/agent/worker_thread.rb +10 -0
  97. data/lib/contrast/api/communication/socket.rb +1 -0
  98. data/lib/contrast/api/decorators/message.rb +0 -6
  99. data/lib/contrast/api/decorators.rb +0 -2
  100. data/lib/contrast/api/dtm.pb.rb +1 -1
  101. data/lib/contrast/api/settings.pb.rb +1 -1
  102. data/lib/contrast/components/agent.rb +51 -13
  103. data/lib/contrast/components/assess.rb +16 -6
  104. data/lib/contrast/components/config.rb +18 -2
  105. data/lib/contrast/components/contrast_service.rb +1 -1
  106. data/lib/contrast/components/heap_dump.rb +51 -1
  107. data/lib/contrast/components/inventory.rb +19 -13
  108. data/lib/contrast/components/logger.rb +18 -0
  109. data/lib/contrast/config/assess_configuration.rb +28 -0
  110. data/lib/contrast/config/base_configuration.rb +8 -15
  111. data/lib/contrast/config/root_configuration.rb +12 -8
  112. data/lib/contrast/config/ruby_configuration.rb +2 -9
  113. data/lib/contrast/config/service_configuration.rb +4 -4
  114. data/lib/contrast/config.rb +0 -6
  115. data/lib/contrast/configuration.rb +0 -2
  116. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  117. data/lib/contrast/extension/assess/hash.rb +3 -2
  118. data/lib/contrast/extension/assess/kernel.rb +22 -0
  119. data/lib/contrast/extension/assess/marshal.rb +16 -0
  120. data/lib/contrast/extension/assess/string.rb +21 -20
  121. data/lib/contrast/extension/object.rb +19 -0
  122. data/lib/contrast/framework/base_support.rb +8 -0
  123. data/lib/contrast/framework/manager.rb +6 -20
  124. data/lib/contrast/framework/manager_extend.rb +0 -1
  125. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -16
  126. data/lib/contrast/framework/rails/support.rb +4 -1
  127. data/lib/contrast/logger/aliased_logging.rb +2 -0
  128. data/lib/contrast/logger/log.rb +2 -1
  129. data/lib/contrast/utils/assess/event_limit_utils.rb +96 -0
  130. data/lib/contrast/utils/assess/propagation_method_utils.rb +27 -7
  131. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  132. data/lib/contrast/utils/log_utils.rb +2 -2
  133. data/lib/contrast/utils/lru_cache.rb +3 -0
  134. data/lib/contrast/utils/middleware_utils.rb +2 -0
  135. data/lib/contrast/utils/patching/policy/patch_utils.rb +6 -23
  136. data/lib/contrast/utils/telemetry_client.rb +7 -7
  137. data/lib/contrast.rb +37 -18
  138. data/lib/protobuf/code_generator.rb +129 -0
  139. data/lib/protobuf/decoder.rb +28 -0
  140. data/lib/protobuf/deprecation.rb +117 -0
  141. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +79 -0
  142. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +360 -0
  143. data/lib/protobuf/descriptors.rb +3 -0
  144. data/lib/protobuf/encoder.rb +11 -0
  145. data/lib/protobuf/enum.rb +365 -0
  146. data/lib/protobuf/exceptions.rb +9 -0
  147. data/lib/protobuf/field/base_field.rb +380 -0
  148. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  149. data/lib/protobuf/field/bool_field.rb +64 -0
  150. data/lib/protobuf/field/bytes_field.rb +67 -0
  151. data/lib/protobuf/field/double_field.rb +25 -0
  152. data/lib/protobuf/field/enum_field.rb +56 -0
  153. data/lib/protobuf/field/field_array.rb +102 -0
  154. data/lib/protobuf/field/field_hash.rb +122 -0
  155. data/lib/protobuf/field/fixed32_field.rb +25 -0
  156. data/lib/protobuf/field/fixed64_field.rb +28 -0
  157. data/lib/protobuf/field/float_field.rb +43 -0
  158. data/lib/protobuf/field/int32_field.rb +21 -0
  159. data/lib/protobuf/field/int64_field.rb +34 -0
  160. data/lib/protobuf/field/integer_field.rb +23 -0
  161. data/lib/protobuf/field/message_field.rb +51 -0
  162. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  163. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  164. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  165. data/lib/protobuf/field/sint32_field.rb +21 -0
  166. data/lib/protobuf/field/sint64_field.rb +21 -0
  167. data/lib/protobuf/field/string_field.rb +51 -0
  168. data/lib/protobuf/field/uint32_field.rb +21 -0
  169. data/lib/protobuf/field/uint64_field.rb +21 -0
  170. data/lib/protobuf/field/varint_field.rb +77 -0
  171. data/lib/protobuf/field.rb +74 -0
  172. data/lib/protobuf/generators/base.rb +85 -0
  173. data/lib/protobuf/generators/enum_generator.rb +39 -0
  174. data/lib/protobuf/generators/extension_generator.rb +27 -0
  175. data/lib/protobuf/generators/field_generator.rb +193 -0
  176. data/lib/protobuf/generators/file_generator.rb +262 -0
  177. data/lib/protobuf/generators/group_generator.rb +122 -0
  178. data/lib/protobuf/generators/message_generator.rb +104 -0
  179. data/lib/protobuf/generators/option_generator.rb +17 -0
  180. data/lib/protobuf/generators/printable.rb +160 -0
  181. data/lib/protobuf/generators/service_generator.rb +50 -0
  182. data/lib/protobuf/lifecycle.rb +33 -0
  183. data/lib/protobuf/logging.rb +39 -0
  184. data/lib/protobuf/message/fields.rb +233 -0
  185. data/lib/protobuf/message/serialization.rb +85 -0
  186. data/lib/protobuf/message.rb +241 -0
  187. data/lib/protobuf/optionable.rb +72 -0
  188. data/lib/protobuf/tasks/compile.rake +80 -0
  189. data/lib/protobuf/tasks.rb +1 -0
  190. data/lib/protobuf/varint.rb +20 -0
  191. data/lib/protobuf/varint_pure.rb +31 -0
  192. data/lib/protobuf/version.rb +3 -0
  193. data/lib/protobuf/wire_type.rb +10 -0
  194. data/lib/protobuf.rb +91 -0
  195. data/proto/dynamic_discovery.proto +46 -0
  196. data/proto/google/protobuf/compiler/plugin.proto +183 -0
  197. data/proto/google/protobuf/descriptor.proto +911 -0
  198. data/proto/rpc.proto +71 -0
  199. data/resources/assess/policy.json +6 -23
  200. data/ruby-agent.gemspec +4 -2
  201. metadata +122 -33
  202. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  203. data/lib/contrast/api/decorators/application_update.rb +0 -44
  204. data/lib/contrast/api/decorators/library.rb +0 -56
  205. data/lib/contrast/config/agent_configuration.rb +0 -63
  206. data/lib/contrast/config/heap_dump_configuration.rb +0 -59
  207. data/lib/contrast/config/inventory_configuration.rb +0 -33
  208. data/lib/contrast/config/logger_configuration.rb +0 -26
  209. data/lib/contrast/framework/platform_version.rb +0 -22
@@ -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,12 @@ 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
45
+
46
+ attr_accessor :propagation_event_count, :source_event_count
52
47
 
53
48
  def initialize rack_request, app_loaded: true
54
49
  with_contrast_scope do
@@ -62,9 +57,6 @@ module Contrast
62
57
  @activity = Contrast::Api::Dtm::Activity.new
63
58
  @activity.http_request = request.dtm
64
59
 
65
- @server_activity = Contrast::Api::Dtm::ServerActivity.new
66
- @observed_library_usage = Contrast::Agent::Reporting::ObservedLibraryUsage.new
67
-
68
60
  # build analyzer
69
61
  @do_not_track = false
70
62
  @speedracer_input_analysis = EMPTY_INPUT_ANALYSIS_PB
@@ -78,6 +70,12 @@ module Contrast
78
70
  # generic holder for properties that can be set throughout this request
79
71
  @_properties = {}
80
72
 
73
+ # count of propagation events
74
+ @propagation_event_count = 0
75
+
76
+ # count of source events
77
+ @source_event_count = 0
78
+
81
79
  if ::Contrast::ASSESS.enabled?
82
80
  @sample_req, @sample_res = Contrast::Utils::Assess::SamplingUtil.instance.sample?(@request)
83
81
  end
@@ -128,20 +126,21 @@ module Contrast
128
126
 
129
127
  def reset_activity
130
128
  @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
129
+ @observed_route = Contrast::Agent::Reporting::ObservedRoute.new
134
130
  end
135
131
 
136
132
  private
137
133
 
138
134
  def handle_routes
139
- @observed_route = Contrast::Api::Dtm::ObservedRoute.new # TODO: RUBY-1438 -- remove
140
- @new_observed_route = Contrast::Agent::Reporting::ObservedRoute.new
135
+ @observed_route = Contrast::Agent::Reporting::ObservedRoute.new
136
+ # TODO: RUBY-1705 when we no longer need the DTM style, delete this method and use the get_route_information
137
+ # instead.
141
138
  route_dtm = Contrast::Agent.framework_manager.get_route_dtm(@request)
142
- new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
139
+ # new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
140
+ # TODO: RUBY-1705 -- delete append_route_coverage
143
141
  append_route_coverage(route_dtm)
144
- append_to_new_observed_route(new_route_coverage_dtm)
142
+ # TODO: RUBY-1705 -- change to take [Contrast::Agent::Reporting::ObservedRoute]
143
+ append_to_observed_route(route_dtm)
145
144
  end
146
145
  end
147
146
  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?
@@ -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/components/logger'
5
4
  require 'contrast/agent/worker_thread'
6
5
  require 'contrast/agent/reporting/report'
7
6
 
@@ -10,8 +9,6 @@ module Contrast
10
9
  # The ServiceHeartbeat functions to keep the Contrast Service alive and ensure that it maintains this Agent's
11
10
  # ApplicationContext.
12
11
  class ServiceHeartbeat < WorkerThread
13
- include Contrast::Components::Logger::InstanceMethods
14
-
15
12
  # Spec recommends 30 seconds, we're going with 15.
16
13
  REFRESH_INTERVAL_SEC = 15
17
14
 
@@ -22,7 +19,9 @@ module Contrast
22
19
  @_thread = Contrast::Agent::Thread.new do
23
20
  logger.info('Starting heartbeat thread.')
24
21
  loop do
25
- Contrast::Agent.messaging_queue.send_event_eventually(poll_message)
22
+ logger.info("Queue Size: #{ Contrast::Agent.messaging_queue.queue&.length }")
23
+ Contrast::Agent.messaging_queue&.send_event_eventually(poll_message)
24
+ clean_properties
26
25
  sleep(REFRESH_INTERVAL_SEC)
27
26
  end
28
27
  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
- return unless ::Contrast::INVENTORY.enabled?
27
+ return unless ::Contrast::INVENTORY.enable
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'
@@ -33,7 +33,7 @@ module Contrast
33
33
  @messaging_queue = Contrast::Api::Communication::MessagingQueue.new
34
34
  end
35
35
  @reporter = Contrast::Agent::Reporter.new
36
- @reporter_heartbeat = Contrast::Agent::ReporterHeartbeat.new if Contrast::Agent::Reporter.enabled?
36
+ @reporter_heartbeat = Contrast::Agent::ReporterHeartbeat.new
37
37
  @telemetry = Contrast::Agent::Telemetry::Base.new if Contrast::Agent::Telemetry::Base.enabled?
38
38
  end
39
39
 
@@ -50,9 +50,6 @@ module Contrast
50
50
  @pids[Process.pid] = @pids[Process.pid] && telemetry_status
51
51
  end
52
52
  reporter_status = init_thread(reporter)
53
-
54
- return @pids unless Contrast::Agent::Reporter.enabled?
55
-
56
53
  reporter_heartbeat_status = init_thread(reporter_heartbeat)
57
54
  @pids[Process.pid] = @pids[Process.pid] && reporter_status && reporter_heartbeat_status
58
55
  @pids
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '6.2.0'
6
+ VERSION = '6.5.0'
7
7
  end
8
8
  end
@@ -1,10 +1,14 @@
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/components/logger'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  # Base class for threads that do async processing
7
9
  class WorkerThread
10
+ include Contrast::Components::Logger::InstanceMethods
11
+
8
12
  def initialize
9
13
  @_thread = nil
10
14
  end
@@ -27,6 +31,12 @@ module Contrast
27
31
  def attempt_to_start?
28
32
  true
29
33
  end
34
+
35
+ def clean_properties
36
+ logger.debug("Cleaning PROPERTIES_HASH size: #{ Contrast::Agent::Assess::Tracker::PROPERTIES_HASH.size }")
37
+ Contrast::Agent::Assess::Tracker.cleanup!
38
+ logger.debug("Cleaned PROPERTIES_HASH size: #{ Contrast::Agent::Assess::Tracker::PROPERTIES_HASH.size }")
39
+ end
30
40
  end
31
41
  end
32
42
  end
@@ -34,6 +34,7 @@ module Contrast
34
34
  end
35
35
 
36
36
  # Override this method to return a socket. Should be interface compatible with TCPSocket, UNIXSocket, etc.
37
+ # @raise[NoMethodError] abstract method, needs to be implemented
37
38
  def new_socket
38
39
  raise(NoMethodError, 'This is abstract, override it.')
39
40
  end
@@ -19,14 +19,10 @@ module Contrast
19
19
 
20
20
  def append_event event
21
21
  case event
22
- when Contrast::Api::Dtm::ServerActivity
23
- self.server_activity = event
24
22
  when Contrast::Api::Dtm::AgentStartup
25
23
  self.agent_startup = event
26
24
  when Contrast::Api::Dtm::ApplicationCreate
27
25
  self.application_create = event
28
- when Contrast::Api::Dtm::ApplicationUpdate
29
- self.application_update = event
30
26
  when Contrast::Api::Dtm::Activity
31
27
  self.activity = event
32
28
  when Contrast::Api::Dtm::HttpRequest
@@ -35,8 +31,6 @@ module Contrast
35
31
  self.postfilter = event
36
32
  when Contrast::Api::Dtm::Poll
37
33
  self.poll = event
38
- when Contrast::Api::Dtm::ObservedRoute
39
- self.observed_route = event
40
34
  else
41
35
  logger.error('Unknown event type received. Unsure how to send.', event_type: event.cs__class.cs__name)
42
36
  return
@@ -12,12 +12,10 @@ end
12
12
  require 'contrast/api/decorators/message'
13
13
  require 'contrast/api/decorators/agent_startup'
14
14
  require 'contrast/api/decorators/application_startup'
15
- require 'contrast/api/decorators/application_update'
16
15
  require 'contrast/api/decorators/architecture_component'
17
16
  require 'contrast/api/decorators/input_analysis'
18
17
  require 'contrast/api/decorators/application_settings'
19
18
  require 'contrast/api/decorators/server_features'
20
- require 'contrast/api/decorators/library'
21
19
  require 'contrast/api/decorators/route_coverage'
22
20
  require 'contrast/api/decorators/trace_event_object'
23
21
  require 'contrast/api/decorators/trace_event_signature'
@@ -8,7 +8,7 @@ require 'protobuf'
8
8
  module Contrast
9
9
  module Api
10
10
  module Dtm
11
- ::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
11
+ ::Protobuf::Optionable.inject(self) { ::CSGoogle::Protobuf::FileOptions }
12
12
 
13
13
  ##
14
14
  # Message Classes
@@ -8,7 +8,7 @@ require 'protobuf'
8
8
  module Contrast
9
9
  module Api
10
10
  module Settings
11
- ::Protobuf::Optionable.inject(self) { ::Google::Protobuf::FileOptions }
11
+ ::Protobuf::Optionable.inject(self) { ::CSGoogle::Protobuf::FileOptions }
12
12
 
13
13
  ##
14
14
  # Enum Classes