contrast-agent 6.1.1 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) 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 +9 -8
  24. data/lib/contrast/agent/inventory/database_config.rb +18 -7
  25. data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
  26. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +13 -9
  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/protect/rule/xss.rb +4 -0
  38. data/lib/contrast/agent/reporting/reporter.rb +33 -17
  39. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
  40. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +3 -18
  41. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  42. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  43. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +83 -16
  44. data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
  45. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  46. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  47. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  48. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  49. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  50. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  51. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  52. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  53. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  54. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  55. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +18 -20
  56. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -24
  57. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +13 -6
  58. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -4
  59. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +10 -4
  60. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +9 -0
  61. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  62. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  63. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  64. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -6
  65. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -32
  66. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -4
  67. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  68. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +60 -2
  69. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +32 -10
  70. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
  71. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +58 -26
  72. data/lib/contrast/agent/reporting/settings/application_settings.rb +8 -23
  73. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +27 -33
  74. data/lib/contrast/agent/reporting/settings/bot_blocker.rb +68 -0
  75. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +27 -0
  76. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +33 -0
  77. data/lib/contrast/agent/reporting/settings/exclusions.rb +39 -57
  78. data/lib/contrast/agent/reporting/settings/helpers.rb +56 -0
  79. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +37 -0
  80. data/lib/contrast/agent/reporting/settings/ip_filter.rb +35 -0
  81. data/lib/contrast/agent/reporting/settings/keyword.rb +74 -0
  82. data/lib/contrast/agent/reporting/settings/log_enhancer.rb +65 -0
  83. data/lib/contrast/agent/reporting/settings/protect.rb +4 -2
  84. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +62 -115
  85. data/lib/contrast/agent/reporting/settings/reaction.rb +11 -2
  86. data/lib/contrast/agent/reporting/settings/rule_definition.rb +63 -0
  87. data/lib/contrast/agent/reporting/settings/sampling.rb +10 -0
  88. data/lib/contrast/agent/reporting/settings/sanitizer.rb +38 -0
  89. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +9 -1
  90. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +7 -0
  91. data/lib/contrast/agent/reporting/settings/server_features.rb +8 -0
  92. data/lib/contrast/agent/reporting/settings/syslog.rb +176 -0
  93. data/lib/contrast/agent/reporting/settings/url_exclusion.rb +42 -0
  94. data/lib/contrast/agent/reporting/settings/validator.rb +17 -0
  95. data/lib/contrast/agent/request.rb +5 -7
  96. data/lib/contrast/agent/request_context.rb +8 -13
  97. data/lib/contrast/agent/request_context_extend.rb +8 -9
  98. data/lib/contrast/agent/request_handler.rb +10 -35
  99. data/lib/contrast/agent/rule_set.rb +4 -0
  100. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  101. data/lib/contrast/agent/static_analysis.rb +6 -15
  102. data/lib/contrast/agent/telemetry/base.rb +35 -35
  103. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  104. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  105. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  106. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  107. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  108. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  109. data/lib/contrast/agent/thread_watcher.rb +2 -6
  110. data/lib/contrast/agent/version.rb +1 -1
  111. data/lib/contrast/agent.rb +1 -3
  112. data/lib/contrast/api/communication/socket.rb +1 -0
  113. data/lib/contrast/api/decorators/message.rb +0 -6
  114. data/lib/contrast/api/decorators.rb +0 -3
  115. data/lib/contrast/components/assess.rb +0 -6
  116. data/lib/contrast/components/config.rb +18 -2
  117. data/lib/contrast/config/base_configuration.rb +0 -13
  118. data/lib/contrast/config/root_configuration.rb +1 -0
  119. data/lib/contrast/config/ruby_configuration.rb +2 -9
  120. data/lib/contrast/configuration.rb +0 -2
  121. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  122. data/lib/contrast/extension/assess/hash.rb +3 -2
  123. data/lib/contrast/extension/assess/kernel.rb +22 -0
  124. data/lib/contrast/extension/assess/marshal.rb +16 -0
  125. data/lib/contrast/extension/assess/string.rb +21 -20
  126. data/lib/contrast/framework/base_support.rb +13 -4
  127. data/lib/contrast/framework/grape/support.rb +6 -6
  128. data/lib/contrast/framework/manager.rb +7 -23
  129. data/lib/contrast/framework/manager_extend.rb +1 -1
  130. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -15
  131. data/lib/contrast/framework/rails/support.rb +9 -2
  132. data/lib/contrast/framework/sinatra/support.rb +3 -2
  133. data/lib/contrast/logger/aliased_logging.rb +33 -26
  134. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  135. data/lib/contrast/utils/lru_cache.rb +3 -0
  136. data/lib/contrast/utils/middleware_utils.rb +2 -0
  137. data/lib/contrast/utils/response_utils.rb +14 -1
  138. data/lib/contrast/utils/telemetry.rb +9 -0
  139. data/lib/contrast/utils/telemetry_client.rb +7 -7
  140. data/lib/contrast/utils/telemetry_hash.rb +36 -12
  141. data/lib/contrast/utils/telemetry_identifier.rb +8 -0
  142. data/lib/contrast/utils/thread_tracker.rb +26 -9
  143. data/lib/contrast/utils/timer.rb +6 -1
  144. data/lib/contrast.rb +1 -3
  145. data/resources/assess/policy.json +2 -11
  146. data/ruby-agent.gemspec +1 -1
  147. metadata +36 -22
  148. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  149. data/lib/contrast/api/decorators/application_update.rb +0 -52
  150. data/lib/contrast/api/decorators/library.rb +0 -56
  151. data/lib/contrast/api/decorators/library_usage_update.rb +0 -31
  152. data/lib/contrast/framework/platform_version.rb +0 -22
@@ -2,6 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/api/dtm.pb'
5
+ require 'contrast/utils/string_utils'
6
+ require 'contrast/components/logger'
5
7
 
6
8
  module Contrast
7
9
  module Agent
@@ -16,41 +18,31 @@ module Contrast
16
18
  # @attr_reader file [String] the name of the Gem. Required for reporting.
17
19
  # @attr_reader hash [String] the Sha256 of the Gem, matching its hash in RubyGems. Required for reporting.
18
20
  # @attr_reader internal_date [Integer] the time, in ms, when the Gem was published. Required for reporting.
19
- # @attr_reader manifest [String] the YAML form of the Gem's specification.
21
+ # @attr_accessor manifest [String] the YAML form of the Gem's specification.
20
22
  # @attr_reader tags [String] Inventory tags set by the user via configuration.
21
23
  # @attr_reader url [String] The homepage of the Gem.
22
24
  # @attr_reader version [String] The version of the Gem.
23
25
  class LibraryDiscovery
26
+ include Contrast::Components::Logger::InstanceMethods
27
+
28
+ StringUtils = Contrast::Utils::StringUtils
29
+
24
30
  # required attributes
25
31
  attr_reader :external_date, :file, :hash, :internal_date
26
32
  # optional attributes
27
- attr_reader :class_count, :manifest, :tags, :url, :version
28
-
29
- class << self
30
- # Convert a DTM for SpeedRacer to an Event for TeamServer.
31
- #
32
- # @param library_dtm [Contrast::Api::Dtm::Library]
33
- # @return [Contrast::Agent::Reporting::LibraryDiscovery]
34
- def convert library_dtm
35
- report = new
36
- report.attach_data(library_dtm)
37
- report
38
- end
39
- end
33
+ attr_reader :class_count, :tags, :url, :version
34
+ attr_accessor :manifest
40
35
 
41
- # Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly
42
- #
43
- # @param library_dtm [Contrast::Api::Dtm::Library]
44
- def attach_data library_dtm
45
- @class_count = library_dtm.class_count
46
- @external_date = library_dtm.external_ms
47
- @file = library_dtm.file_path
48
- @hash = library_dtm.hash_code
49
- @internal_date = library_dtm.internal_ms
50
- @manifest = library_dtm.manifest
36
+ def initialize digest, spec
37
+ @file = StringUtils.force_utf8(spec.name) # rubocop:disable Security/Module/Name
38
+ @hash = StringUtils.force_utf8(digest)
39
+ @version = StringUtils.force_utf8(spec.version)
40
+ @manifest = StringUtils.force_utf8(StringUtils.force_utf8(spec.to_yaml.to_s))
41
+ @external_date = (spec.date.to_f * 1000.0).to_i
42
+ @internal_date = @external_date
43
+ @url = StringUtils.force_utf8(spec.homepage)
44
+ @class_count = Contrast::Utils::Sha256Builder.instance.files(spec.full_gem_path.to_s).length
51
45
  @tags = Contrast::INVENTORY.tags
52
- @url = library_dtm.url
53
- @version = library_dtm.version
54
46
  end
55
47
 
56
48
  # Convert the instance variables on the class, and other information, into the identifiers required for
@@ -59,8 +51,14 @@ module Contrast
59
51
  # @return [Hash]
60
52
  # @raise [ArgumentError]
61
53
  def to_controlled_hash
62
- validate
63
- msg = {
54
+ begin
55
+ validate
56
+ rescue ArgumentError => e
57
+ logger.error('LibraryDiscovery validation failed with: ', e)
58
+ return
59
+ end
60
+
61
+ {
64
62
  classCount: class_count,
65
63
  externalDate: external_date,
66
64
  file: file,
@@ -68,10 +66,9 @@ module Contrast
68
66
  internalDate: internal_date,
69
67
  manifest: manifest,
70
68
  url: url,
71
- version: version
72
- }
73
- msg[:tags] = tags if tags
74
- msg
69
+ version: version,
70
+ tags: tags
71
+ }.compact
75
72
  end
76
73
 
77
74
  # Ensure the required fields are present.
@@ -1,45 +1,43 @@
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
  module Reporting
7
9
  # The usage, meaning loaded files, of a library seen during this request
8
10
  class LibraryUsageObservation
11
+ include Contrast::Components::Logger::InstanceMethods
12
+
9
13
  # @param [String] Sha256Sum of library as identified by the agent
10
14
  attr_accessor :id
11
15
  # @param [Array<String>] List of file paths that have been loaded out of or executed by the library
12
16
  attr_reader :names
13
17
 
14
- class << self
15
- # Convert a DTM for SpeedRacer to an Event for TeamServer.
16
- #
17
- # @param usage_dtm [Contrast::Api::Dtm::LibraryUsageUpdate]
18
- # @return [Contrast::Agent::Reporting::LibraryUsageObservation]
19
- def convert usage_dtm
20
- observation = new
21
- observation.attach_data(usage_dtm)
22
- observation
23
- end
24
- end
25
-
26
- def initialize
27
- @names = []
28
- end
29
-
30
- def attach_data usage_dtm
31
- @id = usage_dtm.hash_code
32
- @names = usage_dtm.class_names.keys
18
+ # @param id [String] Sha256Sum of library as identified by the agent
19
+ # @param class_names [Array<String>] List of file paths that have been loaded out of or executed by the library
20
+ def initialize id, class_names
21
+ @id = id
22
+ @names = class_names
33
23
  end
34
24
 
25
+ # @raise [ArgumentError]
35
26
  def to_controlled_hash
36
- validate
27
+ begin
28
+ validate
29
+ rescue ArgumentError => e
30
+ logger.error('LibraryUsageObservation validation failed with: ', e)
31
+ return
32
+ end
33
+
37
34
  {
38
35
  id: @id,
39
36
  names: @names
40
37
  }
41
38
  end
42
39
 
40
+ # @raise [ArgumentError]
43
41
  def validate
44
42
  raise(ArgumentError, "#{ self } did not have a proper id. Unable to continue.") unless id
45
43
  raise(ArgumentError, "#{ self } did not have a proper names. Unable to continue.") if names.empty?
@@ -3,28 +3,17 @@
3
3
 
4
4
  require 'contrast/agent/reporting/reporting_events/application_reporting_event'
5
5
  require 'contrast/agent/reporting/reporting_events/library_usage_observation'
6
+ require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
8
9
  module Agent
9
10
  module Reporting
10
11
  # List of libraries that have been observed to have something loaded or executed.
11
- #
12
- # @attr_reader observations - Array[Contrast::Agent::Reporting::LibraryUsageObservation]
13
- # - Hash of LibraryUsageObservations
14
12
  class ObservedLibraryUsage < Contrast::Agent::Reporting::ApplicationReportingEvent
15
- attr_reader :observations
13
+ include Contrast::Components::Logger::InstanceMethods
16
14
 
17
- class << self
18
- # Convert a Hash of LibraryUsageUpdate DTMs for SpeedRacer to an Event for TeamServer.
19
- #
20
- # @param usages_dtm_hash Hash[Contrast::Api::Dtm::LibraryUsageUpdate]
21
- # @return [Contrast::Agent::Reporting::ObservedLibraryUsage]
22
- def convert usages_dtm_hash
23
- report = new
24
- report.attach_data(usages_dtm_hash)
25
- report
26
- end
27
- end
15
+ # @return Array[Contrast::Agent::Reporting::LibraryUsageObservation]
16
+ attr_reader :observations
28
17
 
29
18
  def initialize
30
19
  @event_endpoint = Contrast::Agent::Reporting::Endpoints.library_usage
@@ -37,16 +26,14 @@ module Contrast
37
26
  end
38
27
 
39
28
  def to_controlled_hash
40
- validate
41
- { observations: @observations.map(&:to_controlled_hash) }
42
- end
43
-
44
- def attach_data usages_dtm_hash
45
- usages_dtm_hash.each do |_key, value|
46
- next unless value.class_names.any?
47
-
48
- @observations << Contrast::Agent::Reporting::LibraryUsageObservation.convert(value)
29
+ begin
30
+ validate
31
+ rescue ArgumentError => e
32
+ logger.error('ObservedLibraryUsage validation failed with: ', e)
33
+ return
49
34
  end
35
+
36
+ { observations: @observations.map(&:to_controlled_hash) }
50
37
  end
51
38
 
52
39
  def validate
@@ -16,6 +16,8 @@ module Contrast
16
16
  # includes the literal URL and HTTP Verb used to invoke them, as they must have been called at this point to be
17
17
  # recorded.
18
18
  class ObservedRoute < Contrast::Agent::Reporting::ApplicationReportingEvent
19
+ include Contrast::Components::Logger::InstanceMethods
20
+
19
21
  # @param [String] the method signature used to uniquely identify the coverage report.
20
22
  attr_accessor :signature
21
23
  # @param [String] the normalized URL used to access the method in the route.
@@ -45,18 +47,23 @@ module Contrast
45
47
  # @return [Hash]
46
48
  # @raise [ArgumentError]
47
49
  def to_controlled_hash
48
- validate
49
- rc_hash = {
50
- session_id: @agent_session_id_value,
50
+ begin
51
+ validate
52
+ rescue ArgumentError => e
53
+ logger.error('ObservedRoute validation failed with: ', e)
54
+ return
55
+ end
56
+
57
+ {
58
+ session_id: ::Contrast::ASSESS.session_id,
51
59
  sources: @sources.map(&:to_controlled_hash),
52
60
  signature: @signature,
53
61
  verb: @verb,
54
62
  url: @url
55
- }
56
- rc_hash.delete(:verb) unless @verb
57
- rc_hash
63
+ }.compact
58
64
  end
59
65
 
66
+ # @raise [ArgumentError]
60
67
  def validate
61
68
  raise(ArgumentError, "#{ self } did not have a proper sources. Unable to continue.") if @sources.nil?
62
69
  raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
@@ -30,7 +30,6 @@ module Contrast
30
30
  @app_name = ::Contrast::APP_CONTEXT.app_name
31
31
  @app_version = ::Contrast::APP_CONTEXT.app_version
32
32
  @routes = []
33
- @agent_session_id_value = ::Contrast::ASSESS.session_id
34
33
  end
35
34
 
36
35
  # Convert the instance variables on the class, and other information, into the identifiers required for
@@ -39,7 +38,13 @@ module Contrast
39
38
  # @return [Hash]
40
39
  # @raise [ArgumentError]
41
40
  def to_controlled_hash
42
- validate
41
+ begin
42
+ validate
43
+ rescue ArgumentError => e
44
+ logger.error('PreflightMessage validation failed with: ', e)
45
+ return
46
+ end
47
+
43
48
  {
44
49
  code: CODE,
45
50
  app_language: @app_language,
@@ -48,10 +53,11 @@ module Contrast
48
53
  data: '',
49
54
  key: 0,
50
55
  routes: @routes,
51
- session_id: @agent_session_id_value
56
+ session_id: ::Contrast::ASSESS.session_id
52
57
  }
53
58
  end
54
59
 
60
+ # @raise [ArgumentError]
55
61
  def validate
56
62
  raise(ArgumentError, "#{ cs__class } did not have a proper data. Unable to continue.") unless data
57
63
  unless @app_name
@@ -60,7 +66,7 @@ module Contrast
60
66
  unless @app_language
61
67
  raise(ArgumentError, "#{ cs__class } did not have a proper application language. Unable to continue.")
62
68
  end
63
- unless @agent_session_id_value
69
+ unless ::Contrast::ASSESS.session_id
64
70
  raise(ArgumentError, "#{ cs__class } did not have a proper session id. Unable to continue.")
65
71
  end
66
72
 
@@ -14,15 +14,15 @@ module Contrast
14
14
  #
15
15
  # @abstract
16
16
  class ReportingEvent
17
+ include Contrast::Components::Logger::InstanceMethods
18
+
17
19
  # @return [String] the endpoint, with host, to which this event should be sent
18
20
  attr_reader :event_endpoint
19
21
  # @return event_method [Symbol] the HTTP method to use to send this event
20
22
  attr_reader :event_method
21
23
 
22
24
  def initialize
23
- @agent_session_id_value = ::Contrast::ASSESS.session_id
24
- @event_endpoint ||= nil
25
- @event_method ||= :POST
25
+ @event_method ||= :POST # rubocop:disable Lint/DisjunctiveAssignmentInConstructor
26
26
  end
27
27
 
28
28
  # Some reports require specific additional headers to be used. To that end, we'll attach them here, letting
@@ -37,7 +37,13 @@ module Contrast
37
37
  # @return [Hash]
38
38
  # @raise [ArgumentError]
39
39
  def to_controlled_hash
40
- validate
40
+ begin
41
+ validate
42
+ rescue ArgumentError => e
43
+ logger.error('ReportingEvent validation failed with: ', e)
44
+ return
45
+ end
46
+
41
47
  {}
42
48
  end
43
49
 
@@ -32,6 +32,15 @@ module Contrast
32
32
  @count = 0
33
33
  end
34
34
 
35
+ # Parse the given controller and route from a Rack based application framework in order to create an instance
36
+ # of this class
37
+ #
38
+ # @param final_controller [Grape::API, Sinatra::Base] the controller responsible for the definition of the
39
+ # entrypoint of the route actively being executed
40
+ # @param method [String] the HTTP request method of the route actively being executed
41
+ # @param route_pattern [Grape::Router::Route, Mustermann::Sinatra] the pattern to which the url maps
42
+ # @param url [String] the literal url of the route actively being executed
43
+ # @return [Contrast::Agent::Reporting::RouteCoverage]
35
44
  def attach_rack_based_data final_controller, method, route_pattern, url = nil
36
45
  if route_pattern.cs__is_a?(Grape::Router::Route)
37
46
  safe_pattern = route_pattern.pattern&.path&.to_s
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'contrast/agent/reporting/reporting_events/route_discovery_observation'
5
5
  require 'contrast/api/dtm.pb'
6
+ require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
8
9
  module Agent
@@ -17,6 +18,8 @@ module Contrast
17
18
  # @attr_reader signature [String] the unique identifier for this route; typically the method signature. Required
18
19
  # for reporting.
19
20
  class RouteDiscovery
21
+ include Contrast::Components::Logger::InstanceMethods
22
+
20
23
  # required attributes
21
24
  attr_reader :observations, :signature
22
25
 
@@ -47,7 +50,13 @@ module Contrast
47
50
  # @return [Hash]
48
51
  # @raise [ArgumentError]
49
52
  def to_controlled_hash
50
- validate
53
+ begin
54
+ validate
55
+ rescue ArgumentError => e
56
+ logger.error('RouteDiscovery validation failed with: ', e)
57
+ return
58
+ end
59
+
51
60
  {
52
61
  count: 0, # we have this to make TS happy
53
62
  observations: @observations.map(&:to_controlled_hash),
@@ -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"
@@ -16,7 +16,7 @@ module Contrast
16
16
  attr_reader :path_for_requests, :path_for_responses
17
17
 
18
18
  def initialize
19
- generate_paths if enabled? && Contrast::CONTRAST_SERVICE.use_agent_communication?
19
+ generate_paths if enabled?
20
20
  end
21
21
 
22
22
  # This method will be handling the auditing of the requests and responses we send to SpeedRacer. If the audit
@@ -44,11 +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
- return unless Contrast::CONTRAST_SERVICE.use_agent_communication?
49
-
50
- logger.debug('logging to file', file_name: file_name) # TODO: RUBY-99999 DO NOT COMMIT THIS
51
- write_to_file(type, file_name, data)
47
+ write_to_file(type, file_name, data) if enabled?
52
48
  end
53
49
 
54
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,31 +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 a Hash of Contrast::Api::Dtm::LibraryUsageUpdate class
25
- #
26
- # @param message [Protobuf::Field::FieldHash<String,::Contrast::Api::Dtm::LibraryUsageUpdate>]
27
- # @return [Boolean]
28
- def library_usage? message
29
- message.cs__is_a?(Protobuf::Field::FieldHash) &&
30
- message.values[0].cs__is_a?(Contrast::Api::Dtm::LibraryUsageUpdate)
31
- end
32
-
33
- # Checks if the message is of Contrast::Api::Dtm::ApplicationUpdate class
34
- #
35
- # @param dtm [Contrast::Api::Dtm::ApplicationUpdate,Object]
36
- # @return [Boolean]
37
- def application_update? dtm
38
- dtm.cs__is_a?(Contrast::Api::Dtm::ApplicationUpdate)
39
- end
40
-
41
15
  # @param dtm [Contrast::Api::Dtm::Finding,Object]
42
16
  # @return [Boolean]
43
17
  def finding? dtm
@@ -56,13 +30,7 @@ module Contrast
56
30
  # @param dtm [Contrast::Api::Dtm]
57
31
  # @return event [Contrast::Agent::Reporting::ReportingEvent, nil]
58
32
  def dtm_to_event dtm
59
- # For the ServerActivity we need to create and send empty body only. This is done because we need the
60
- # response from TS.
61
- return Contrast::Agent::Reporting::ServerActivity.new if server_activity?(dtm)
62
-
63
33
  # For the others, we convert them.
64
- return Contrast::Agent::Reporting::ObservedLibraryUsage.convert(dtm) if library_usage?(dtm)
65
- return Contrast::Agent::Reporting::ApplicationUpdate.convert(dtm) if application_update?(dtm)
66
34
  return Contrast::Agent::Reporting::Finding.convert(dtm) if finding?(dtm)
67
35
  return Contrast::Agent::Reporting::ApplicationActivity.convert(dtm) if activity?(dtm)
68
36
 
@@ -53,13 +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
59
- return unless Contrast::Agent::Reporter.enabled?
57
+ def send_event event, connection
60
58
  return unless connection
61
59
 
62
- log_send_event(event) if send_immediately
63
60
  request = build_request(event)
64
61
  response = connection.request(request)
65
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
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'contrast/agent/reporting/settings/application_settings'
5
5
  require 'contrast/agent/reporting/settings/server_features'
6
+ require 'contrast/agent/reporting/settings/reaction'
6
7
 
7
8
  module Contrast
8
9
  module Agent
@@ -21,19 +22,76 @@ module Contrast
21
22
  # @return [Contrast::Agent::Reporting::Settings::FeatureSettings, nil]
22
23
  attr_accessor :server_features
23
24
 
25
+ # Success boolean message value
26
+ #
27
+ # @return [Boolean]
28
+ attr_accessor :success
29
+
30
+ # Message with reasons for success or fail.
31
+ #
32
+ # @return [Array<String>] Messages received from TS.
33
+ attr_accessor :messages
34
+
24
35
  class << self
25
- def application_response
36
+ # All of the settings from TeamServer that apply at the application level.
37
+ #
38
+ # @return response [Contrast::Agent::Reporting::Response]
39
+ def build_application_response
26
40
  res = new
27
41
  res.application_settings = Contrast::Agent::Reporting::Settings::ApplicationSettings.new
28
42
  res
29
43
  end
30
44
 
31
- def server_response
45
+ # All of the settings from TeamServer that apply at the server level.
46
+ #
47
+ # @return response [Contrast::Agent::Reporting::Response]
48
+ def build_server_response
32
49
  res = new
33
50
  res.server_features = Contrast::Agent::Reporting::Settings::ServerFeatures.new
34
51
  res
35
52
  end
36
53
  end
54
+
55
+ # Reaction the agent should take based on a state in TS.
56
+ # This is moved one level up because the responses we
57
+ # receive for feature and settings from TS have different
58
+ # place to store these reactions:
59
+ #
60
+ # body.reactions vs body.settings.reactions
61
+ #
62
+ # @return [Array<Contrast::Agent::Reporting::Settings::Reaction>]
63
+ def reactions
64
+ @_reactions ||= []
65
+ end
66
+
67
+ # Set the reaction
68
+ #
69
+ # @param reaction_array [Array<Reaction>] {
70
+ # level [String] The level at which the agent should log this reaction.
71
+ # [ERROR, WARN, INFO, DEBUG, TRACE]
72
+ # message [String] A message to log when receiving this reaction.
73
+ # operation [String] What to do in response to this reaction.[NOOP, DISABLE] }
74
+ # @return [Array<Contrast::Agent::Reporting::Settings::Reaction>]
75
+ def reactions= reaction_array
76
+ return unless reaction_array.is_a?(Array)
77
+
78
+ reaction_array.each do |r|
79
+ reactions << Contrast::Agent::Reporting::Settings::Reaction.new(r[:level], r[:operation], r[:message])
80
+ end
81
+ end
82
+
83
+ # This method is used only for testing with golden files.
84
+ def to_controlled_hash
85
+ {
86
+ success: success,
87
+ messages: messages,
88
+ features: server_features.nil? ? nil : server_features.to_controlled_hash,
89
+ settings: application_settings.nil? ? nil : application_settings.to_controlled_hash,
90
+ logLevel: server_features&.log_level,
91
+ logFile: server_features&.log_file,
92
+ reactions: server_features.nil? ? nil : reactions.map(&:to_controlled_hash)
93
+ }.compact
94
+ end
37
95
  end
38
96
  end
39
97
  end