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
@@ -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'
@@ -32,10 +32,8 @@ module Contrast
32
32
  @heartbeat = Contrast::Agent::ServiceHeartbeat.new
33
33
  @messaging_queue = Contrast::Api::Communication::MessagingQueue.new
34
34
  end
35
- if Contrast::Agent::Reporter.enabled?
36
- @reporter = Contrast::Agent::Reporter.new
37
- @reporter_heartbeat = Contrast::Agent::ReporterHeartbeat.new
38
- end
35
+ @reporter = Contrast::Agent::Reporter.new
36
+ @reporter_heartbeat = Contrast::Agent::ReporterHeartbeat.new
39
37
  @telemetry = Contrast::Agent::Telemetry::Base.new if Contrast::Agent::Telemetry::Base.enabled?
40
38
  end
41
39
 
@@ -51,8 +49,6 @@ module Contrast
51
49
  telemetry_status = init_thread(telemetry_queue)
52
50
  @pids[Process.pid] = @pids[Process.pid] && telemetry_status
53
51
  end
54
- return @pids unless Contrast::Agent::Reporter.enabled?
55
-
56
52
  reporter_status = init_thread(reporter)
57
53
  reporter_heartbeat_status = init_thread(reporter_heartbeat)
58
54
  @pids[Process.pid] = @pids[Process.pid] && reporter_status && reporter_heartbeat_status
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '6.1.1'
6
+ VERSION = '6.3.0'
7
7
  end
8
8
  end
@@ -76,10 +76,8 @@ module Contrast
76
76
  thread_watcher.telemetry_queue
77
77
  end
78
78
 
79
- # @return [nil, Contrast::Agent::Reporter]
79
+ # @return [Contrast::Agent::Reporter]
80
80
  def self.reporter
81
- return unless thread_watcher.reporter
82
-
83
81
  thread_watcher.reporter
84
82
  end
85
83
 
@@ -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,13 +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
- require 'contrast/api/decorators/library_usage_update'
22
19
  require 'contrast/api/decorators/route_coverage'
23
20
  require 'contrast/api/decorators/trace_event_object'
24
21
  require 'contrast/api/decorators/trace_event_signature'
@@ -76,12 +76,6 @@ module Contrast
76
76
  @_scan_response
77
77
  end
78
78
 
79
- def track_frozen_sources?
80
- @_track_frozen_sources = !false?(::Contrast::CONFIG.root.agent.ruby.track_frozen_sources) if
81
- @_track_frozen_sources.nil?
82
- @_track_frozen_sources
83
- end
84
-
85
79
  def require_scan?
86
80
  @_require_scan = !false?(::Contrast::CONFIG.root.agent.ruby.require_scan) if @_require_scan.nil?
87
81
  @_require_scan
@@ -27,7 +27,7 @@ module Contrast
27
27
  CONTRAST_LOG = 'contrast_agent.log'
28
28
  CONTRAST_NAME = 'Contrast Agent'
29
29
 
30
- class Interface # :nodoc:
30
+ class Interface # :nodoc: # rubocop:disable Metrics/ClassLength
31
31
  SESSION_VARIABLES = 'Invalid configuration. '\
32
32
  "Setting both application.session_id and application.session_metadata is not allowed.\n"
33
33
  API_URL = "Invalid configuration. Missing a required connection value 'url' is not set."
@@ -57,6 +57,8 @@ module Contrast
57
57
  @config = Contrast::Configuration.new
58
58
  env_overrides
59
59
  validate
60
+ rescue ArgumentError => e
61
+ proto_logger.error('Configuration failed with error: ', e)
60
62
  end
61
63
  alias_method :rebuild, :build
62
64
 
@@ -136,7 +138,7 @@ module Contrast
136
138
  next unless env_key.to_s.start_with?(CONTRAST_ENV_MARKER)
137
139
 
138
140
  config_item = Contrast::Utils::EnvConfigurationItem.new(env_key, env_value)
139
- @config.assign_value_to_path_array(config_item.dot_path_array, config_item.value)
141
+ assign_value_to_path_array(root, config_item.dot_path_array, config_item.value)
140
142
  end
141
143
  end
142
144
 
@@ -193,6 +195,20 @@ module Contrast
193
195
  def logger_path
194
196
  root.agent.logger.path
195
197
  end
198
+
199
+ # Assign the value from an ENV variable to the Contrast::Config::RootConfiguration object, when
200
+ # appropriate.
201
+ #
202
+ # @return nil
203
+ def assign_value_to_path_array current_level, dot_path_array, value
204
+ dot_path_array[0...-1].each do |segment|
205
+ segment = segment.tr('-', '_')
206
+ current_level = current_level.send(segment) if current_level.cs__respond_to?(segment)
207
+ end
208
+ return unless current_level.nil? == false && current_level.cs__respond_to?(dot_path_array[-1])
209
+
210
+ current_level.send("#{ dot_path_array[-1] }=", value)
211
+ end
196
212
  end
197
213
  end
198
214
  end
@@ -20,19 +20,6 @@ module Contrast
20
20
  end
21
21
  hsh
22
22
  end
23
-
24
- def assign_value_to_path_array dot_path_array, value
25
- current_level = self
26
- dot_path_array[0...-1].each do |segment|
27
- segment = segment.tr('-', '_')
28
- current_level = current_level.send(segment) if current_level.cs__respond_to?(segment)
29
- end
30
- last_entry = dot_path_array[-1]
31
- if current_level.nil? == false && current_level.cs__respond_to?(last_entry)
32
- current_level.send("#{ last_entry }=", value)
33
- end
34
- nil
35
- end
36
23
  end
37
24
  end
38
25
  end
@@ -26,6 +26,7 @@ module Contrast
26
26
  # @return [Boolean, nil]
27
27
  attr_accessor :enable
28
28
 
29
+ # @raise[ArgumentError]
29
30
  def initialize hsh = {}
30
31
  raise(ArgumentError, 'Expected a hash') unless hsh.is_a?(Hash)
31
32
 
@@ -21,7 +21,7 @@ module Contrast
21
21
  DEFAULT_UNINSTRUMENTED_NAMESPACES = %w[FactoryGirl FactoryBot].cs__freeze
22
22
 
23
23
  attr_writer :disabled_agent_rake_tasks, :exceptions, :interpolate, :propagate_yield, :require_scan,
24
- :track_frozen_sources, :non_request_tracking, :uninstrument_namespace
24
+ :non_request_tracking, :uninstrument_namespace
25
25
 
26
26
  def initialize hsh = {}
27
27
  return unless hsh
@@ -31,7 +31,6 @@ module Contrast
31
31
  @interpolate = hsh[:interpolate]
32
32
  @propagate_yield = hsh[:propagate_yield]
33
33
  @require_scan = hsh[:require_scan]
34
- @track_frozen_sources = hsh[:track_frozen_sources]
35
34
  @non_request_tracking = hsh[:non_request_tracking]
36
35
  @uninstrument_namespace = hsh[:uninstrument_namespace]
37
36
  end
@@ -67,16 +66,10 @@ module Contrast
67
66
  @require_scan.nil? ? Contrast::Utils::ObjectShare::TRUE : @require_scan
68
67
  end
69
68
 
70
- # controls whether or not we track frozen Strings by replacing them
71
- # @return [Boolean, Contrast::Utils::ObjectShare::TRUE]
72
- def track_frozen_sources
73
- @track_frozen_sources.nil? ? Contrast::Utils::ObjectShare::TRUE : @track_frozen_sources
74
- end
75
-
76
69
  # controls tracking outside of request
77
70
  # @return [Boolean, Contrast::Utils::ObjectShare::FALSE]
78
71
  def non_request_tracking
79
- @non_request_tracking.nil? ? Contrast::Utils::ObjectShare::FALSE : @non_request_tracking
72
+ @non_request_tracking.nil? ? Contrast::Utils::ObjectShare::FALSE : @non_request_tracking
80
73
  end
81
74
 
82
75
  # @return [Array, DEFAULT_UNINSTRUMENTED_NAMESPACES]
@@ -18,8 +18,6 @@ module Contrast
18
18
  include Contrast::Components::Scope::InstanceMethods
19
19
  extend Contrast::Components::Scope::InstanceMethods
20
20
 
21
- def_delegator :root, :assign_value_to_path_array
22
-
23
21
  attr_reader :default_name, :root
24
22
 
25
23
  DEFAULT_YAML_PATH = 'contrast_security.yaml'
@@ -25,10 +25,6 @@ module Contrast
25
25
  def apply_trigger obj, source, ret, clazz, method
26
26
  return unless ::Contrast::ASSESS.non_request_tracking? || Contrast::Agent::REQUEST_TRACKER.current
27
27
 
28
- # Since we know this is the source of the trigger, we can do some
29
- # optimization here and return when it is not tracked
30
- return unless Contrast::Utils::Assess::TrackingUtil.tracked?(source)
31
-
32
28
  # source might not be all the args passed in, but it is the one we care
33
29
  # about. we could pass in all the args in the last param here if it
34
30
  # becomes an issue in rendering on TS
@@ -15,11 +15,12 @@ module Contrast
15
15
  class << self
16
16
  def cs__duplicate_and_freeze object
17
17
  return object unless object.is_a?(String) && !object.cs__frozen?
18
- return object unless Contrast::Agent::Assess::Tracker.tracked?(object)
19
18
 
20
19
  # Copy the object, then freeze it, so that it looks the same
21
20
  # externally, but will have our finalizer on it.
22
- object.dup&.cs__freeze
21
+ copy = object.dup
22
+ Contrast::Agent::Assess::Tracker.pre_freeze(copy)
23
+ copy&.cs__freeze
23
24
  rescue StandardError
24
25
  # we'll rescue this error, but we can't log it here as that will
25
26
  # result in a seg fault
@@ -4,6 +4,7 @@
4
4
  require 'contrast/extension/assess/exec_trigger'
5
5
  require 'contrast/components/logger'
6
6
  require 'contrast/agent/assess/events/event_data'
7
+ require 'contrast/agent/patching/policy/patch'
7
8
 
8
9
  module Contrast
9
10
  module Extension
@@ -97,6 +98,27 @@ module Contrast
97
98
  end
98
99
  end
99
100
  end
101
+
102
+ # Used for Kernel exec aliasing since we have no other way of accessing the
103
+ # Kernel#exec under C if we alias it there.
104
+ module ContrastKernel
105
+ # Method to replace the call to Kernel#exec when applying alias patch.
106
+ # It will invoke Contrast::Extension::Assess::KernelPropagator before
107
+ # calling the original method.
108
+ #
109
+ # @param source [String, Proc] Potentially untrusted shell command to execute.
110
+ # @return nil - This method will invoke the Kernel#exec which will
111
+ def cs__kernel_exec source
112
+ # Check if in contrast scope and we have source.
113
+ unless Contrast::Agent::Patching::Policy::Patch.in_contrast_scope? || source.nil?
114
+ Contrast::Agent::Patching::Policy::Patch.with_contrast_scope do
115
+ Contrast::Extension::Assess::KernelPropagator.apply_trigger(source)
116
+ end
117
+ end
118
+ # Call this in the end else any code bellow this call won't be executed.
119
+ Kernel.exec(source)
120
+ end
121
+ end
100
122
  end
101
123
  end
102
124
  end
@@ -58,6 +58,22 @@ module Contrast
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ # Used for aliasing
63
+ module ContrastMarshal
64
+ def cs__marshal_load source
65
+ # Do the protect
66
+ Contrast::Extension::Assess::MarshalPropagator.cs__load_protect(source) if source
67
+ # call the original
68
+ result = Marshal.load(source) # rubocop:disable Security/MarshalLoad
69
+ # Do the assess
70
+ tracked = Contrast::Agent::Assess::Tracker::PROPERTIES_HASH.tracked?(source) if source
71
+ skip = Contrast::Agent::Patching::Policy::Patch.skip_assess_analysis? if tracked
72
+ Contrast::Extension::Assess::MarshalPropagator.cs__load_assess(source, result) if skip
73
+ # return original
74
+ result
75
+ end
76
+ end
61
77
  end
62
78
  end
63
79
  end
@@ -31,31 +31,32 @@ module Contrast
31
31
  INTERPOLATION_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(NODE_HASH)
32
32
 
33
33
  class << self
34
+ # We call this method from C, and the Scope check is happening there. If we are in
35
+ # Contrast Scope the method won't be invoked.
36
+ #
37
+ # @param inputs [Array<String>] Inputs for interpolation.
38
+ # @param result [String] The result from the interpolation.
34
39
  def track_interpolation inputs, result
35
40
  return unless ::Contrast::AGENT.interpolation_enabled?
36
- return if in_contrast_scope?
37
41
  return unless inputs.any? { |input| Contrast::Agent::Assess::Tracker.tracked?(input) }
42
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties!(result))
38
43
 
39
- with_contrast_scope do
40
- return unless (properties = Contrast::Agent::Assess::Tracker.properties!(result))
41
-
42
- parent_events = []
43
- offset = 0
44
- inputs.each do |input|
45
- properties.copy_from(input, result, offset)
46
- add_dynamic_sources_info(input, result)
47
- offset += input.length
48
- parent_event = Contrast::Agent::Assess::Tracker.properties(input)&.event
49
- parent_events << parent_event if parent_event
50
- end
51
- event_data = Contrast::Agent::Assess::Events::EventData.new(INTERPOLATION_NODE,
52
- result,
53
- inputs,
54
- result,
55
- inputs)
56
- properties.build_event(event_data)
57
- properties.event.instance_variable_set(:@_parent_events, parent_events)
44
+ parent_events = []
45
+ offset = 0
46
+ inputs.each do |input|
47
+ properties.copy_from(input, result, offset)
48
+ add_dynamic_sources_info(input, result)
49
+ offset += input.length
50
+ parent_event = Contrast::Agent::Assess::Tracker.properties(input)&.event
51
+ parent_events << parent_event if parent_event
58
52
  end
53
+ event_data = Contrast::Agent::Assess::Events::EventData.new(INTERPOLATION_NODE,
54
+ result,
55
+ inputs,
56
+ result,
57
+ inputs)
58
+ properties.build_event(event_data)
59
+ properties.event.instance_variable_set(:@_parent_events, parent_events)
59
60
  rescue StandardError => e
60
61
  logger.error('Unable to track interpolation', e)
61
62
  end
@@ -1,43 +1,52 @@
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/discovered_route'
5
+
4
6
  module Contrast
5
7
  module Framework
6
8
  # The API for all subclasses to implement to correctly support a given framework
7
9
  module BaseSupport
8
10
  # The top level module name used by the framework
11
+ # @raise [NoMethodError] raises error if subclass does not implement this method
9
12
  def detection_class
10
13
  raise(NoMethodError('Subclasses of BaseSupport should implement this method'))
11
14
  end
12
15
 
16
+ # @raise [NoMethodError] raises error if subclass does not implement this method
13
17
  def version
14
18
  raise(NoMethodError('Subclasses of BaseSupport should implement this method'))
15
19
  end
16
20
 
21
+ # @raise [NoMethodError] raises error if subclass does not implement this method
17
22
  def application_name
18
23
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
19
24
  end
20
25
 
26
+ # @raise [NoMethodError] raises error if subclass does not implement this method
21
27
  def server_type
22
28
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
23
29
  end
24
30
 
25
- # Find all the predefined routes for this application and append them to the
26
- # provided inventory message
27
- # msg should be a Contrast::Api::Dtm::ApplicationUpdate or some other msg
28
- # that has a routes array consisting of Contrast::Api::Dtm::RouteCoverage
31
+ # Find all the predefined routes for this application
32
+ #
33
+ # @return [Array<Contrast::Agent::Reporting::DiscoveredRoute>]
34
+ # @raise [NoMethodError] raises error if subclass does not implement this method
29
35
  def collect_routes
30
36
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
31
37
  end
32
38
 
39
+ # @raise [NoMethodError] raises error if subclass does not implement this method
33
40
  def current_route_coverage
34
41
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
35
42
  end
36
43
 
44
+ # @raise [NoMethodError] raises error if subclass does not implement this method
37
45
  def current_route
38
46
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
39
47
  end
40
48
 
49
+ # @raise [NoMethodError] raises error if subclass does not implement this method
41
50
  def retrieve_request _env
42
51
  raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
43
52
  end