contrast-agent 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -0
  3. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +22 -10
  4. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +4 -3
  5. data/lib/contrast/agent/assess/contrast_event.rb +49 -130
  6. data/lib/contrast/agent/assess/contrast_object.rb +51 -0
  7. data/lib/contrast/agent/assess/events/source_event.rb +4 -9
  8. data/lib/contrast/agent/assess/policy/patcher.rb +4 -3
  9. data/lib/contrast/agent/assess/policy/policy_node.rb +31 -59
  10. data/lib/contrast/agent/assess/policy/preshift.rb +3 -3
  11. data/lib/contrast/agent/assess/policy/propagation_method.rb +13 -19
  12. data/lib/contrast/agent/assess/policy/propagation_node.rb +12 -24
  13. data/lib/contrast/agent/assess/policy/propagator/append.rb +1 -2
  14. data/lib/contrast/agent/assess/policy/propagator/center.rb +1 -2
  15. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  16. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -3
  17. data/lib/contrast/agent/assess/policy/propagator/insert.rb +1 -2
  18. data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -2
  19. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
  20. data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -2
  21. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -2
  22. data/lib/contrast/agent/assess/policy/propagator/remove.rb +2 -4
  23. data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -2
  24. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -2
  25. data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -4
  26. data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -4
  27. data/lib/contrast/agent/assess/policy/propagator/split.rb +73 -117
  28. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +11 -11
  29. data/lib/contrast/agent/assess/policy/propagator/trim.rb +3 -7
  30. data/lib/contrast/agent/assess/policy/source_method.rb +2 -14
  31. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +5 -8
  32. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
  33. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  34. data/lib/contrast/agent/assess/property/tagged.rb +21 -15
  35. data/lib/contrast/agent/assess/rule/redos.rb +1 -1
  36. data/lib/contrast/agent/assess/tracker.rb +16 -18
  37. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +7 -0
  38. data/lib/contrast/agent/middleware.rb +50 -1
  39. data/lib/contrast/agent/patching/policy/method_policy.rb +1 -1
  40. data/lib/contrast/agent/patching/policy/patch.rb +4 -4
  41. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +47 -1
  42. data/lib/contrast/agent/protect/policy/rule_applicator.rb +53 -0
  43. data/lib/contrast/agent/protect/rule/base.rb +63 -14
  44. data/lib/contrast/agent/protect/rule/cmd_injection.rb +3 -3
  45. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -4
  46. data/lib/contrast/agent/protect/rule/deserialization.rb +4 -1
  47. data/lib/contrast/agent/protect/rule/no_sqli.rb +3 -3
  48. data/lib/contrast/agent/protect/rule/sqli.rb +3 -3
  49. data/lib/contrast/agent/protect/rule/xxe.rb +32 -11
  50. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +10 -6
  51. data/lib/contrast/agent/reaction_processor.rb +1 -1
  52. data/lib/contrast/agent/response.rb +5 -5
  53. data/lib/contrast/agent/rewriter.rb +3 -3
  54. data/lib/contrast/agent/scope.rb +33 -13
  55. data/lib/contrast/agent/static_analysis.rb +13 -7
  56. data/lib/contrast/agent/version.rb +1 -1
  57. data/lib/contrast/api/decorators/library.rb +1 -0
  58. data/lib/contrast/api/decorators/library_usage_update.rb +1 -0
  59. data/lib/contrast/api/decorators/trace_event.rb +19 -31
  60. data/lib/contrast/api/decorators/trace_event_object.rb +11 -3
  61. data/lib/contrast/api/decorators/trace_event_signature.rb +27 -5
  62. data/lib/contrast/api/decorators/user_input.rb +2 -1
  63. data/lib/contrast/common_agent_configuration.rb +1 -1
  64. data/lib/contrast/components/assess.rb +36 -0
  65. data/lib/contrast/components/interface.rb +5 -3
  66. data/lib/contrast/components/scope.rb +23 -0
  67. data/lib/contrast/components/settings.rb +3 -3
  68. data/lib/contrast/config/assess_configuration.rb +2 -1
  69. data/lib/contrast/extension/assess/array.rb +1 -2
  70. data/lib/contrast/extension/assess/erb.rb +1 -3
  71. data/lib/contrast/extension/assess/exec_trigger.rb +1 -1
  72. data/lib/contrast/extension/assess/fiber.rb +2 -3
  73. data/lib/contrast/extension/assess/hash.rb +4 -2
  74. data/lib/contrast/extension/assess/kernel.rb +1 -2
  75. data/lib/contrast/extension/assess/marshal.rb +34 -26
  76. data/lib/contrast/extension/assess/regexp.rb +3 -8
  77. data/lib/contrast/extension/assess/string.rb +1 -2
  78. data/lib/contrast/framework/base_support.rb +51 -53
  79. data/lib/contrast/framework/manager.rb +3 -2
  80. data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
  81. data/lib/contrast/framework/rack/support.rb +2 -1
  82. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
  83. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  84. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +1 -1
  85. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +1 -1
  86. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +1 -1
  87. data/lib/contrast/framework/rails/support.rb +2 -1
  88. data/lib/contrast/framework/sinatra/support.rb +3 -2
  89. data/lib/contrast/logger/application.rb +0 -3
  90. data/lib/contrast/utils/duck_utils.rb +1 -1
  91. data/lib/contrast/utils/heap_dump_util.rb +1 -1
  92. data/lib/contrast/utils/object_share.rb +3 -3
  93. data/lib/contrast/utils/preflight_util.rb +1 -1
  94. data/lib/contrast/utils/prevent_serialization.rb +1 -1
  95. data/lib/contrast/utils/resource_loader.rb +1 -1
  96. data/lib/contrast/utils/sha256_builder.rb +2 -2
  97. data/lib/contrast/utils/string_utils.rb +1 -1
  98. data/lib/contrast/utils/tag_util.rb +9 -13
  99. data/resources/assess/policy.json +9 -9
  100. data/resources/deadzone/policy.json +156 -0
  101. data/resources/protect/policy.json +12 -0
  102. data/ruby-agent.gemspec +9 -6
  103. data/service_executables/VERSION +1 -1
  104. data/service_executables/linux/contrast-service +0 -0
  105. data/service_executables/mac/contrast-service +0 -0
  106. metadata +68 -25
@@ -96,11 +96,11 @@ module Contrast
96
96
  return unless method_exists?(clazz, method_name, type)
97
97
 
98
98
  method_instance = method_instance(clazz, method_name, type)
99
- return nil if method_instance.nil?
99
+ return if method_instance.nil?
100
100
 
101
101
  location = method_instance.source_location
102
- return nil unless location_available?(location)
103
- return nil if opener.written_from_location?(location)
102
+ return unless location_available?(location)
103
+ return if opener.written_from_location?(location)
104
104
 
105
105
  opener.written_from_location!(location)
106
106
  opener.source_code(location, method_name)
@@ -15,29 +15,40 @@ module Contrast
15
15
  # Instead, we should say "If I'm already doing Contrast things, don't track
16
16
  # this"
17
17
  class Scope
18
- SCOPE_LIST = %i[contrast deserialization].cs__freeze
18
+ SCOPE_LIST = %i[contrast deserialization split].cs__freeze
19
19
 
20
20
  def initialize
21
- instance_variable_set(:@contrast_scope, 0)
22
- instance_variable_set(:@deserialization_scope, 0)
21
+ @contrast_scope = 0
22
+ @deserialization_scope = 0
23
+ @split_scope = 0
23
24
  end
24
25
 
25
26
  def in_contrast_scope?
26
- instance_variable_get(:@contrast_scope).positive?
27
+ @contrast_scope.positive?
27
28
  end
28
29
 
29
30
  def in_deserialization_scope?
30
- instance_variable_get(:@deserialization_scope).positive?
31
+ @deserialization_scope.positive?
32
+ end
33
+
34
+ def in_split_scope?
35
+ @split_scope.positive?
31
36
  end
32
37
 
33
38
  def enter_contrast_scope!
34
- level = instance_variable_get(:@contrast_scope)
35
- instance_variable_set(:@contrast_scope, level + 1)
39
+ @contrast_scope += 1
36
40
  end
37
41
 
38
42
  def enter_deserialization_scope!
39
- level = instance_variable_get(:@deserialization_scope)
40
- instance_variable_set(:@deserialization_scope, level + 1)
43
+ @deserialization_scope += 1
44
+ end
45
+
46
+ def enter_split_scope!
47
+ @split_scope += 1
48
+ end
49
+
50
+ def split_scope_depth
51
+ @split_scope
41
52
  end
42
53
 
43
54
  # Scope Exits...
@@ -61,13 +72,15 @@ module Contrast
61
72
  # exit = 1
62
73
  # scope = 1
63
74
  def exit_contrast_scope!
64
- level = instance_variable_get(:@contrast_scope)
65
- instance_variable_set(:@contrast_scope, level - 1)
75
+ @contrast_scope -= 1
66
76
  end
67
77
 
68
78
  def exit_deserialization_scope!
69
- level = instance_variable_get(:@deserialization_scope)
70
- instance_variable_set(:@deserialization_scope, level - 1)
79
+ @deserialization_scope -= 1
80
+ end
81
+
82
+ def exit_split_scope!
83
+ @split_scope -= 1
71
84
  end
72
85
 
73
86
  def with_contrast_scope
@@ -84,6 +97,13 @@ module Contrast
84
97
  exit_deserialization_scope!
85
98
  end
86
99
 
100
+ def with_split_scope
101
+ enter_split_scope!
102
+ yield
103
+ ensure
104
+ exit_split_scope!
105
+ end
106
+
87
107
  # Dynamic versions of the above.
88
108
  # These are equivalent, but they're slower and riskier.
89
109
  # Prefer the static methods if you know what scope you need at the call site.
@@ -17,14 +17,9 @@ module Contrast
17
17
  # report the already-loaded gems.
18
18
  def catchup
19
19
  @_catchup ||= begin
20
- with_contrast_scope do
21
- Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.catchup
22
- send_inventory_message
23
- true
24
- end
20
+ threaded_analysis!
21
+ true
25
22
  end
26
- rescue StandardError => e
27
- logger.warn('Unable to run post-initialization static analysis', e)
28
23
  end
29
24
 
30
25
  def send_inventory_message
@@ -35,6 +30,17 @@ module Contrast
35
30
  Contrast::Utils::InventoryUtil.append_db_config(app_update_msg)
36
31
  Contrast::Agent.messaging_queue.send_event_eventually(app_update_msg)
37
32
  end
33
+
34
+ private
35
+
36
+ def threaded_analysis!
37
+ Contrast::Agent::Thread.new do
38
+ Contrast::Agent::Inventory::DependencyUsageAnalysis.instance.catchup
39
+ send_inventory_message
40
+ rescue StandardError => e
41
+ logger.warn('Unable to run post-initialization static analysis', e)
42
+ end
43
+ end
38
44
  end
39
45
  end
40
46
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module Contrast
5
5
  module Agent
6
- VERSION = '4.2.0'
6
+ VERSION = '4.3.0'
7
7
  end
8
8
  end
@@ -13,6 +13,7 @@ module Contrast
13
13
  def self.included klass
14
14
  klass.extend(ClassMethods)
15
15
  end
16
+
16
17
  # Used to add class methods to the Library class on inclusion of the decorator
17
18
  module ClassMethods
18
19
  def build digest, gem_specification
@@ -11,6 +11,7 @@ module Contrast
11
11
  def self.included klass
12
12
  klass.extend(ClassMethods)
13
13
  end
14
+
14
15
  # Used to add class methods to the LibraryUsageUpdate class on inclusion of the decorator
15
16
  module ClassMethods
16
17
  def build digest, files
@@ -15,44 +15,30 @@ module Contrast
15
15
 
16
16
  # Wrapper around build_event_object for the args array. Handles
17
17
  # tainting the correct argument.
18
- def build_event_args contrast_event, taint_target
18
+ def build_event_args! contrast_event, taint_target
19
19
  contrast_event.args.each_index do |idx|
20
20
  truncate_arg = taint_target != idx
21
21
  event_arg = Contrast::Api::Dtm::TraceEventObject.build(contrast_event.args[idx], truncate_arg)
22
22
  args << event_arg
23
23
  end
24
+ self
24
25
  end
25
26
 
26
- # TeamServer only supports one object's taint ranges at a time.
27
- # We'll find the taint ranges for the target and return those
28
- def build_taint_ranges contrast_event, taint_target
27
+ # TeamServer only supports one object's taint ranges at a time. We keep
28
+ # those tags on the event directly, so we just need to convert them to
29
+ # their DTM form in order to report this.
30
+ #
31
+ # @param contrast_event [Contrast::Agent::AssessContrastEvent]
32
+ def build_taint_ranges! contrast_event
29
33
  # If there's no taint_target, this isn't a dataflow trace, but a
30
34
  # trigger one
31
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless taint_target
35
+ return self unless contrast_event&.tags
32
36
 
33
- properties = case taint_target
34
- when Contrast::Utils::ObjectShare::OBJECT_KEY
35
- Contrast::Agent::Assess::Tracker.properties(contrast_event.object)
36
- when Contrast::Utils::ObjectShare::RETURN_KEY
37
- Contrast::Agent::Assess::Tracker.properties(contrast_event.ret)
38
- else
39
- target = contrast_event.args[taint_target]
40
- if target.is_a?(Hash)
41
- if contrast_event.policy_node&.targets&.any?
42
- Contrast::Agent::Assess::Tracker.properties(target[contrast_event.policy_node.targets[0]])
43
- else
44
- Contrast::Agent::Assess::Tracker.properties(target[contrast_event.policy_node.sources[0]])
45
- end
46
- else
47
- Contrast::Agent::Assess::Tracker.properties(target)
48
- end
49
- end
50
- return unless properties.tracked?
51
-
52
- self.taint_ranges += properties.tags_to_dtm
37
+ self.taint_ranges += Contrast::Api::Dtm::TraceTaintRange.build_for_event(contrast_event.tags)
38
+ self
53
39
  end
54
40
 
55
- def build_parent_ids contrast_event
41
+ def build_parent_ids! contrast_event
56
42
  contrast_event&.parent_events&.each do |event|
57
43
  next unless event
58
44
 
@@ -60,12 +46,14 @@ module Contrast
60
46
  parent.id = event.event_id.to_i
61
47
  parent_object_ids << parent
62
48
  end
49
+ self
63
50
  end
64
51
 
65
- def build_stack contrast_event
52
+ def build_stack! contrast_event
66
53
  # We delayed doing this as long as possible b/c it's expensive
67
54
  stack_dtms = Contrast::Utils::StackTraceUtils.build_assess_stack_array(contrast_event.stack_trace)
68
55
  self.stack += stack_dtms
56
+ self
69
57
  end
70
58
 
71
59
  # Class methods for TraceEvent
@@ -85,10 +73,10 @@ module Contrast
85
73
  event_dtm.object = Contrast::Api::Dtm::TraceEventObject.build(contrast_event.object, truncate_obj)
86
74
  truncate_ret = Contrast::Utils::ObjectShare::RETURN_KEY != taint_target
87
75
  event_dtm.ret = Contrast::Api::Dtm::TraceEventObject.build(contrast_event.ret, truncate_ret)
88
- event_dtm.build_event_args(contrast_event, taint_target)
89
- event_dtm.build_parent_ids(contrast_event)
90
- event_dtm.build_taint_ranges(contrast_event, taint_target)
91
- event_dtm.build_stack(contrast_event)
76
+ event_dtm.build_event_args!(contrast_event, taint_target)
77
+ event_dtm.build_parent_ids!(contrast_event)
78
+ event_dtm.build_taint_ranges!(contrast_event)
79
+ event_dtm.build_stack!(contrast_event)
92
80
  event_dtm.object_id = contrast_event.event_id.to_i
93
81
  event_dtm.signature = Contrast::Api::Dtm::TraceEventSignature.build(contrast_event.ret, contrast_event.policy_node, contrast_event.args)
94
82
  event_dtm
@@ -29,13 +29,21 @@ module Contrast
29
29
  ELLIPSIS = '...'
30
30
  UNTRUNCATED_PORTION_LENGTH = 25
31
31
  TRUNCATION_LENGTH = (UNTRUNCATED_PORTION_LENGTH * 2) + ELLIPSIS.length
32
- def build object, truncate
32
+
33
+ # Convert the given Object into a Contrast::Api::Dtm::TraceEventObject
34
+ #
35
+ # @param contrast_object [Contrast::Agent::Assess::ContrastObject, nil]
36
+ # the thing to convert, if any
37
+ # @param truncate [Boolean] if the converted object can/should be
38
+ # truncated.
39
+ # @return [Contrast::Api::Dtm::TraceEventObject]
40
+ def build contrast_object, truncate
33
41
  event_object = new
34
42
  with_contrast_scope do
35
- obj_string = Contrast::Utils::StringUtils.force_utf8(object)
43
+ obj_string = Contrast::Utils::StringUtils.force_utf8(contrast_object&.object)
36
44
  obj_string = truncate(obj_string) if truncate && obj_string.length > TRUNCATION_LENGTH
37
45
  event_object.value = Base64.encode64(obj_string)
38
- event_object.tracked = Contrast::Utils::Assess::TrackingUtil.tracked?(object)
46
+ event_object.tracked = contrast_object&.tracked?
39
47
  end
40
48
  event_object
41
49
  end
@@ -17,27 +17,49 @@ module Contrast
17
17
 
18
18
  # Class methods for TraceEventSignature
19
19
  module ClassMethods
20
+ # Convert the given composites into components that TeamServer can
21
+ # understand in order to build a representation of the method
22
+ # invoked.
23
+ #
24
+ # @param ret_obj [Contrast::Agent::Assess::ContrastObject, nil] the
25
+ # return value of the method call.
26
+ # @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
27
+ # the policy which pertains to the method invoked.
28
+ # @param args [Array<Contrast::Agent::Assess::ContrastObject>, nil]
29
+ # @return [Contrast::Api::Dtm::TraceEventSignature]
20
30
  def build ret_obj, policy_node, args
21
31
  signature = new
22
- return_type = ret_obj ? ret_obj.cs__class.name : Contrast::Utils::ObjectShare::NIL_STRING
23
- signature.return_type = Contrast::Utils::StringUtils.force_utf8(return_type)
32
+ signature.return_type = Contrast::Utils::StringUtils.force_utf8(type_name(ret_obj))
24
33
  signature.class_name = Contrast::Utils::StringUtils.force_utf8(policy_node.class_name)
25
34
  signature.method_name = Contrast::Utils::StringUtils.force_utf8(policy_node.method_name)
26
35
  if args
27
36
  args&.each do |arg|
28
- arg_type = arg ? arg.cs__class.name : Contrast::Utils::ObjectShare::NIL_STRING
29
- signature.arg_types << Contrast::Utils::StringUtils.force_utf8(arg_type)
37
+ signature.arg_types << Contrast::Utils::StringUtils.force_utf8(type_name(arg))
30
38
  end
31
39
  end
32
40
  signature.constructor = policy_node.method_name == :new
33
41
  # if there's a ret, then this method isn't nil. not 100% full proof since you can
34
42
  # return nil, but this is the best we've got currently.
35
- signature.void_method = ret_obj.nil?
43
+ signature.void_method = ret_obj.nil? || ret_obj.object.nil?
36
44
  # 8 is STATIC in Java... we have to placate them for now
37
45
  # it has been requested that flags be removed since it isn't used
38
46
  signature.flags = 8 unless policy_node.instance_method?
39
47
  signature
40
48
  end
49
+
50
+ private
51
+
52
+ # While Ruby signatures do not require neither a return type and can
53
+ # return anything depending on inputs, code paths, etc, nor constant
54
+ # parameter types, TeamServer was designed with strongly typed
55
+ # languages (Java) in mind, so we need types in our signatures.
56
+ #
57
+ # @param contrast_object [Contrast::Agent::Assess::ContrastObject, nil]
58
+ # the object to find the type of
59
+ # @return [String] the name of the module of the ret_obj, or `nil`
60
+ def type_name contrast_object
61
+ contrast_object ? contrast_object.object_type : Contrast::Utils::ObjectShare::NIL_STRING
62
+ end
41
63
  end
42
64
  end
43
65
  end
@@ -12,7 +12,8 @@ module Contrast
12
12
  module UserInput
13
13
  UNKNOWN_USER_INPUT = Contrast::Api::Dtm::UserInput.new.tap do |user_input|
14
14
  user_input.input_type = :UNKNOWN
15
- end.cs__freeze
15
+ end
16
+ UNKNOWN_USER_INPUT.cs__freeze
16
17
 
17
18
  def self.included klass
18
19
  klass.extend(ClassMethods)
@@ -66,7 +66,7 @@ module Contrast
66
66
 
67
67
  %w[name default description required_languages display].each do |field|
68
68
  # TODO: RUBY-1052
69
- define_method(field) { hsh[field].dup } # rubocop:disable Kernel/DefineMethod
69
+ define_method(field) { hsh[field].dup } # rubocop:disable Performance/Kernel/DefineMethod
70
70
  end
71
71
  end
72
72
 
@@ -35,6 +35,42 @@ module Contrast
35
35
  disabled_rules.include?(name)
36
36
  end
37
37
 
38
+ # The value of the stacktrace should be treated as an ENUM. We upcase it for
39
+ # faster comparisons when we use it. Anything not one of the known values of
40
+ # 'NONE', 'SOME', or 'ALL' is treated as 'ALL'
41
+ #
42
+ # @return [Symbol] the normalized value of CONFIG.root.assess.stacktraces
43
+ def capture_stacktrace_value
44
+ @_capture_stacktrace_value ||= case CONFIG.root.assess.stacktraces.upcase
45
+ when 'NONE'
46
+ :NONE
47
+ when 'SOME'
48
+ :SOME
49
+ else
50
+ :ALL
51
+ end
52
+ end
53
+
54
+ # Consider capture_stacktrace_value along with the node type
55
+ # to dertmine whether stacktraces should be captured.
56
+ #
57
+ # capture_stacktrace_value -> (:ALL, :NONE, :SOME)
58
+ # node types (SourceNode, PolicyNode, TriggerNode, PropagationNode)
59
+ #
60
+ # @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode] The node in question.
61
+ # @param return [Boolean] to capture or not to capture, that is the question.
62
+ def capture_stacktrace? policy_node
63
+ return true if capture_stacktrace_value == :ALL
64
+
65
+ return false if capture_stacktrace_value == :NONE
66
+
67
+ # Below here capture_stacktrace_value must be :SOME.
68
+ return true if policy_node.cs__is_a?(Contrast::Agent::Assess::Policy::SourceNode)
69
+ return true if policy_node.cs__is_a?(Contrast::Agent::Assess::Policy::TriggerNode)
70
+
71
+ false
72
+ end
73
+
38
74
  def scan_response?
39
75
  @_scan_response = !false?(CONFIG.root.assess.enable_scan_response) if @_scan_response.nil?
40
76
  @_scan_response
@@ -168,9 +168,11 @@ Contrast::Components::ComponentReceiverClassInterface::COMPONENT_MAP[:settings]
168
168
  require 'contrast/components/assess'
169
169
  require 'contrast/components/protect'
170
170
  require 'contrast/components/inventory'
171
- Contrast::Components::ComponentReceiverClassInterface::COMPONENT_MAP[:analysis] = [Contrast::Components::Protect,
172
- Contrast::Components::Assess,
173
- Contrast::Components::Inventory]
171
+ Contrast::Components::ComponentReceiverClassInterface::COMPONENT_MAP[:analysis] = [
172
+ Contrast::Components::Protect,
173
+ Contrast::Components::Assess,
174
+ Contrast::Components::Inventory
175
+ ]
174
176
 
175
177
  require 'contrast/components/logger'
176
178
  Contrast::Components::ComponentReceiverClassInterface::COMPONENT_MAP[:logging] = [Contrast::Components::Logger]
@@ -56,6 +56,10 @@ module Contrast
56
56
  scope_for_current_ec.enter_deserialization_scope!
57
57
  end
58
58
 
59
+ def enter_split_scope!
60
+ scope_for_current_ec.enter_split_scope!
61
+ end
62
+
59
63
  def enter_scope! name
60
64
  scope_for_current_ec.enter_scope! name
61
65
  end
@@ -68,6 +72,10 @@ module Contrast
68
72
  scope_for_current_ec.exit_deserialization_scope!
69
73
  end
70
74
 
75
+ def exit_split_scope!
76
+ scope_for_current_ec.exit_split_scope!
77
+ end
78
+
71
79
  def exit_scope! name
72
80
  scope_for_current_ec.exit_scope! name
73
81
  end
@@ -80,6 +88,14 @@ module Contrast
80
88
  scope_for_current_ec.in_deserialization_scope?
81
89
  end
82
90
 
91
+ def in_split_scope?
92
+ scope_for_current_ec.in_split_scope?
93
+ end
94
+
95
+ def split_scope_depth
96
+ scope_for_current_ec.split_scope_depth
97
+ end
98
+
83
99
  def in_scope? name
84
100
  scope_for_current_ec.in_scope? name
85
101
  end
@@ -97,6 +113,13 @@ module Contrast
97
113
  scope_for_current_ec.exit_deserialization_scope!
98
114
  end
99
115
 
116
+ def with_split_scope
117
+ scope_for_current_ec.enter_split_scope!
118
+ yield
119
+ ensure
120
+ scope_for_current_ec.exit_split_scope!
121
+ end
122
+
100
123
  # TODO: RUBY-572
101
124
  #
102
125
  # Current behavior is to no-op if we're not "in a request context".