contrast-agent 3.14.0 → 3.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +18 -15
  3. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
  4. data/ext/cs__assess_string/cs__assess_string.c +24 -25
  5. data/ext/cs__assess_string/cs__assess_string.h +3 -1
  6. data/ext/cs__common/cs__common.c +4 -2
  7. data/ext/cs__common/cs__common.h +1 -1
  8. data/lib/contrast.rb +1 -1
  9. data/lib/contrast/agent/assess.rb +1 -0
  10. data/lib/contrast/agent/assess/contrast_event.rb +4 -12
  11. data/lib/contrast/agent/assess/finalizers/freeze.rb +3 -1
  12. data/lib/contrast/agent/assess/finalizers/hash.rb +45 -1
  13. data/lib/contrast/agent/assess/policy/patcher.rb +1 -1
  14. data/lib/contrast/agent/assess/policy/policy.rb +0 -2
  15. data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -1
  16. data/lib/contrast/agent/assess/policy/preshift.rb +7 -11
  17. data/lib/contrast/agent/assess/policy/propagation_method.rb +50 -33
  18. data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
  19. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  20. data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
  21. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -3
  22. data/lib/contrast/agent/assess/policy/propagator/insert.rb +6 -3
  23. data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
  24. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +6 -6
  25. data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
  26. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +8 -5
  27. data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
  28. data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
  29. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
  30. data/lib/contrast/agent/assess/policy/propagator/select.rb +15 -7
  31. data/lib/contrast/agent/assess/policy/propagator/splat.rb +14 -8
  32. data/lib/contrast/agent/assess/policy/propagator/split.rb +14 -8
  33. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +30 -21
  34. data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
  35. data/lib/contrast/agent/assess/policy/source_method.rb +85 -58
  36. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -11
  37. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
  38. data/lib/contrast/agent/assess/policy/trigger_method.rb +38 -15
  39. data/lib/contrast/agent/assess/policy/trigger_node.rb +14 -13
  40. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
  41. data/lib/contrast/agent/assess/properties.rb +2 -0
  42. data/lib/contrast/agent/assess/property/updated.rb +136 -0
  43. data/lib/contrast/agent/assess/tracker.rb +66 -0
  44. data/lib/contrast/agent/class_reopener.rb +7 -5
  45. data/lib/contrast/agent/middleware.rb +0 -1
  46. data/lib/contrast/agent/patching/policy/patcher.rb +13 -22
  47. data/lib/contrast/agent/patching/policy/policy.rb +1 -4
  48. data/lib/contrast/agent/response.rb +17 -6
  49. data/lib/contrast/agent/rewriter.rb +1 -3
  50. data/lib/contrast/agent/version.rb +1 -1
  51. data/lib/contrast/api/communication/messaging_queue.rb +1 -4
  52. data/lib/contrast/api/decorators/application_update.rb +2 -4
  53. data/lib/contrast/api/decorators/trace_event.rb +5 -5
  54. data/lib/contrast/components/app_context.rb +11 -9
  55. data/lib/contrast/components/config.rb +3 -13
  56. data/lib/contrast/components/contrast_service.rb +2 -2
  57. data/lib/contrast/config/application_configuration.rb +5 -2
  58. data/lib/contrast/config/service_configuration.rb +8 -2
  59. data/lib/contrast/configuration.rb +88 -47
  60. data/lib/contrast/extension/assess.rb +0 -2
  61. data/lib/contrast/extension/assess/array.rb +8 -5
  62. data/lib/contrast/extension/assess/erb.rb +6 -3
  63. data/lib/contrast/extension/assess/fiber.rb +9 -9
  64. data/lib/contrast/extension/assess/hash.rb +2 -3
  65. data/lib/contrast/extension/assess/kernel.rb +12 -5
  66. data/lib/contrast/extension/assess/marshal.rb +3 -2
  67. data/lib/contrast/extension/assess/regexp.rb +5 -4
  68. data/lib/contrast/extension/assess/string.rb +8 -10
  69. data/lib/contrast/framework/rack/patch/session_cookie.rb +12 -18
  70. data/lib/contrast/framework/rails/patch/assess_configuration.rb +4 -10
  71. data/lib/contrast/framework/rails/support.rb +2 -0
  72. data/lib/contrast/logger/application.rb +11 -3
  73. data/lib/contrast/utils/assess/tracking_util.rb +48 -3
  74. data/lib/contrast/utils/duck_utils.rb +0 -10
  75. data/lib/contrast/utils/env_configuration_item.rb +2 -1
  76. data/lib/contrast/utils/invalid_configuration_util.rb +21 -19
  77. data/lib/contrast/utils/string_utils.rb +10 -5
  78. data/resources/assess/policy.json +0 -10
  79. data/ruby-agent.gemspec +16 -15
  80. data/service_executables/VERSION +1 -1
  81. data/service_executables/linux/contrast-service +0 -0
  82. data/service_executables/mac/contrast-service +0 -0
  83. metadata +42 -21
  84. data/lib/contrast/agent/assess/finalizers/finalize.rb +0 -21
  85. data/lib/contrast/extension/assess/assess_extension.rb +0 -145
  86. data/lib/contrast/utils/freeze_util.rb +0 -32
@@ -7,21 +7,24 @@ module ERBPropagator
7
7
  def result_tagger patcher, preshift, ret, _block
8
8
  return unless preshift.args.length >= 1
9
9
 
10
+ properties = Contrast::Agent::Assess::Tracker.properties(ret)
11
+ return unless properties
12
+
10
13
  used_binding = preshift.args[0]
11
14
  binding_variable_set = used_binding.local_variables
12
15
 
13
16
  erb_pre_result = preshift.object.src
14
17
  binding_variable_set.each do |bound_var_symbol|
15
18
  bound_variable_value = used_binding.local_variable_get(bound_var_symbol)
16
- next unless bound_variable_value.cs__respond_to?(:cs__tracked?) && bound_variable_value.cs__tracked?
19
+ next unless Contrast::Agent::Assess::Tracker.tracked?(bound_variable_value)
17
20
  next unless erb_pre_result.include?(bound_var_symbol.to_s)
18
21
 
19
22
  start_index = ret.index(bound_variable_value)
20
23
  next if start_index.nil?
21
24
 
22
- ret.cs__copy_from(bound_variable_value, start_index)
25
+ properties.copy_from(bound_variable_value, ret, start_index)
23
26
  end
24
- ret.cs__properties.build_event(
27
+ properties.build_event(
25
28
  patcher,
26
29
  ret,
27
30
  preshift.object,
@@ -54,7 +54,6 @@ module Contrast
54
54
  class << self
55
55
  def track_rb_fiber_yield fiber, _method, results
56
56
  return unless ASSESS.enabled?
57
- return unless Contrast::Utils::DuckUtils.trackable?(fiber)
58
57
 
59
58
  # results will be nil if StopIteration was raised,
60
59
  # otherwise an Array of the yielded arguments
@@ -62,11 +61,11 @@ module Contrast
62
61
 
63
62
  with_contrast_scope do
64
63
  results.each do |result|
65
- next unless Contrast::Utils::DuckUtils.trackable?(result)
66
- next if result.cs__frozen?
64
+ result_properties = Contrast::Agent::Assess::Tracker.properties(result)
65
+ next unless result_properties
67
66
 
68
- fiber.cs__splat_tags(result)
69
- result.cs__properties.build_event(
67
+ result_properties.splat_from(fiber, result)
68
+ result_properties.build_event(
70
69
  FIBER_YIELD_NODE,
71
70
  result,
72
71
  fiber,
@@ -80,13 +79,14 @@ module Contrast
80
79
 
81
80
  def track_rb_fiber_new fiber, _enum, _enum_method, underlying, _underlying_method
82
81
  return unless ASSESS.enabled?
83
- return unless Contrast::Utils::DuckUtils.trackable?(fiber)
84
- return unless Contrast::Utils::DuckUtils.trackable?(underlying)
85
82
  return unless underlying.is_a?(String) && !underlying.empty?
86
83
 
87
84
  with_contrast_scope do
88
- underlying.cs__splat_tags(fiber)
89
- fiber.cs__properties.build_event(
85
+ properties = Contrast::Agent::Assess::Tracker.properties(fiber)
86
+ return unless properties
87
+
88
+ properties.splat_from(underlying, fiber)
89
+ properties.build_event(
90
90
  FIBER_NEW_NODE,
91
91
  fiber,
92
92
  underlying,
@@ -15,10 +15,9 @@ 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 object.cs__tracked?
18
+ return object unless Contrast::Agent::Assess::Tracker.tracked?(object)
19
19
 
20
- ret = object.dup
21
- object.cs__transfer_properties(ret)
20
+ ret = Contrast::Agent::Assess::Tracker.duplicate(object)
22
21
  ret.cs__freeze
23
22
  rescue StandardError
24
23
  # we'll rescue this error, but we can't log it here as that will
@@ -39,12 +39,15 @@ module Contrast
39
39
  # oh, and there's also %<name>type and %{name}... b/c of course there is
40
40
  # -HM
41
41
  def sprintf_tagger patcher, preshift, ret, _block
42
+ properties = Contrast::Agent::Assess::Tracker.properties(ret)
43
+ return unless properties
44
+
42
45
  format_string = preshift.args[0]
43
46
  args = preshift.args[1]
44
47
 
45
48
  track_sprintf(ret, format_string, args)
46
49
 
47
- ret.cs__properties.build_event(
50
+ properties.build_event(
48
51
  patcher,
49
52
  ret,
50
53
  preshift.object,
@@ -85,12 +88,16 @@ module Contrast
85
88
  private
86
89
 
87
90
  def handle_sprintf_value value, result
88
- return unless Contrast::Utils::DuckUtils.trackable?(value) && value.cs__tracked?
91
+ properties = Contrast::Agent::Assess::Tracker.properties(result)
92
+ return unless properties
93
+
94
+ value_properties = Contrast::Agent::Assess::Tracker.properties(value)
95
+ return unless value_properties
89
96
 
90
- value.cs__properties.events.each do |event|
91
- result.cs__properties.events << event
97
+ value_properties.events.each do |event|
98
+ properties.events << event
92
99
  end
93
- value.cs__splat_tags(result)
100
+ properties.splat_from(value, result)
94
101
  end
95
102
 
96
103
  def handle_sprintf_array args, result
@@ -22,7 +22,7 @@ module Contrast
22
22
 
23
23
  # Since we know this is the source of the trigger, we can do some
24
24
  # optimization here and return when it is not tracked
25
- return unless Contrast::Utils::Assess::TrackingUtil.tracked?(source)
25
+ return unless Contrast::Agent::Assess::Tracker.tracked?(source)
26
26
 
27
27
  # source might not be all the args passed in, but it is the one we care
28
28
  # about. we could pass in all the args in the last param here if it
@@ -34,7 +34,8 @@ module Contrast
34
34
  self,
35
35
  ret,
36
36
  source)
37
- ret.cs__copy_from(source) if ret.cs__respond_to?(:cs__copy_from)
37
+ properties = Contrast::Agent::Assess::Tracker.properties(ret)
38
+ properties.copy_from(source, ret)
38
39
  rescue StandardError => e
39
40
  logger.error('Unable to determine if a trigger occurred in Marshal.load', e)
40
41
  end
@@ -47,8 +47,6 @@ module Contrast
47
47
  return if scope_for_current_ec.instance_variable_get(:@contrast_scope) > 1
48
48
 
49
49
  target = info_hash[:back_ref]
50
- return unless Contrast::Utils::DuckUtils.trackable?(target)
51
-
52
50
  with_contrast_scope do
53
51
  result = info_hash[:result]
54
52
  return unless result
@@ -56,8 +54,11 @@ module Contrast
56
54
  string = info_hash[:string]
57
55
  return unless string
58
56
 
59
- string.cs__splat_tags(target)
60
- target.cs__properties.build_event(
57
+ properties = Contrast::Agent::Assess::Tracker.properties(target)
58
+ return unless properties
59
+
60
+ properties.splat_from(string, target)
61
+ properties.build_event(
61
62
  REGEXP_EQUAL_SQUIGGLE_NODE,
62
63
  target,
63
64
  self,
@@ -3,13 +3,6 @@
3
3
 
4
4
  require 'contrast/agent/assess/policy/propagation_node'
5
5
  require 'contrast/components/interface'
6
- require 'contrast/extension/assess/assess_extension'
7
-
8
- # This patch installs our extension as early as possible. The alternative is to
9
- # litter our code with Contrast::Utils::DuckUtils.trackable? checks.
10
- class String
11
- include Contrast::Extension::Assess::AssessExtension
12
- end
13
6
 
14
7
  module Contrast
15
8
  module Extension
@@ -40,16 +33,21 @@ module Contrast
40
33
  def track_interpolation inputs, result
41
34
  return unless AGENT.interpolation_enabled?
42
35
  return if in_contrast_scope?
43
- return unless inputs.any?(&:cs__tracked?)
36
+ return unless inputs.any? { |input| Contrast::Agent::Assess::Tracker.tracked?(input) }
44
37
 
45
38
  with_contrast_scope do
39
+ properties = Contrast::Agent::Assess::Tracker.properties(result)
40
+ return unless properties
41
+
46
42
  offset = 0
47
43
  inputs.each do |input|
48
- result.cs__copy_from(input, offset)
44
+ properties.copy_from(input, result, offset)
49
45
  offset += input.length
50
46
  end
51
- result.cs__properties.build_event(INTERPOLATION_NODE, result, inputs, result, inputs)
47
+ properties.build_event(INTERPOLATION_NODE, result, inputs, result, inputs)
52
48
  end
49
+ rescue StandardError => e
50
+ logger.error('Unable to track interpolation', e)
53
51
  end
54
52
 
55
53
  def instrument_string
@@ -67,12 +67,10 @@ module Contrast
67
67
  options,
68
68
  safe_default: false)
69
69
 
70
- with_contrast_scope do
71
- cs__report_finding(
72
- CS__SECURE_RULE_NAME,
73
- options,
74
- caller_locations(10, 9)[0])
75
- end
70
+ cs__report_finding(
71
+ CS__SECURE_RULE_NAME,
72
+ options,
73
+ caller_locations(10, 9)[0])
76
74
  rescue StandardError => e
77
75
  begin
78
76
  logger.error('Unable to track call to secure session', e)
@@ -88,12 +86,10 @@ module Contrast
88
86
  safe_default: false,
89
87
  comparison_type: :greater_than)
90
88
 
91
- with_contrast_scope do
92
- cs__report_finding(
93
- CS__SESSION_TIMEOUT_NAME,
94
- options,
95
- caller_locations(10, 9)[0])
96
- end
89
+ cs__report_finding(
90
+ CS__SESSION_TIMEOUT_NAME,
91
+ options,
92
+ caller_locations(10, 9)[0])
97
93
  rescue StandardError => e
98
94
  begin
99
95
  logger.error('Unable to track call to set session timeout', e)
@@ -105,12 +101,10 @@ module Contrast
105
101
  def apply_httponly options
106
102
  return unless vulnerable_setting?(:httponly, true, options)
107
103
 
108
- with_contrast_scope do
109
- cs__report_finding(
110
- CS__HTTPONLY_NAME,
111
- options,
112
- caller_locations(10, 9)[0])
113
- end
104
+ cs__report_finding(
105
+ CS__HTTPONLY_NAME,
106
+ options,
107
+ caller_locations(10, 9)[0])
114
108
  rescue StandardError => e
115
109
  begin
116
110
  logger.error('Unable to track call to httponly', e)
@@ -12,7 +12,7 @@ module Contrast
12
12
  module AssessConfiguration
13
13
  include Contrast::Components::Interface
14
14
 
15
- access_component :agent, :analysis, :logging, :scope
15
+ access_component :agent, :analysis, :logging
16
16
 
17
17
  CS__SESSION_TIMEOUT_NAME = 'session-timeout'
18
18
  SAFE_SESSION_TIMEOUT = (30 * 60 * 1000)
@@ -52,9 +52,7 @@ module Contrast
52
52
  return unless vulnerable_setting?(:expire_after, SAFE_SESSION_TIMEOUT, args, comparison_type: :greater_than, safe_default: false)
53
53
 
54
54
  rails_session_settings = args[1]
55
- with_contrast_scope do
56
- cs__report_finding(CS__SESSION_TIMEOUT_NAME, rails_session_settings, caller_locations(6, 5)[0])
57
- end
55
+ cs__report_finding(CS__SESSION_TIMEOUT_NAME, rails_session_settings, caller_locations(3, 2)[0])
58
56
  rescue StandardError => e
59
57
  begin
60
58
  logger.error('Unable to track call to set session timeout', e)
@@ -68,9 +66,7 @@ module Contrast
68
66
  return unless vulnerable_setting?(:secure, true, args)
69
67
 
70
68
  rails_session_settings = args[1]
71
- with_contrast_scope do
72
- cs__report_finding(CS__SECURE_RULE_NAME, rails_session_settings, caller_locations(6, 5)[0])
73
- end
69
+ cs__report_finding(CS__SECURE_RULE_NAME, rails_session_settings, caller_locations(3, 2)[0])
74
70
  rescue StandardError => e
75
71
  begin
76
72
  logger.error('Unable to track call to disable secure cookies', e)
@@ -84,9 +80,7 @@ module Contrast
84
80
  return unless vulnerable_setting?(:httponly, true, args)
85
81
 
86
82
  rails_session_settings = args[1]
87
- with_contrast_scope do
88
- cs__report_finding(CS__HTTPONLY_RULE_NAME, rails_session_settings, caller_locations(6, 5)[0])
89
- end
83
+ cs__report_finding(CS__HTTPONLY_RULE_NAME, rails_session_settings, caller_locations(3, 2)[0])
90
84
  rescue StandardError => e
91
85
  begin
92
86
  logger.error('Unable to track call to disable httponly in session cookie', e)
@@ -118,6 +118,8 @@ module Contrast
118
118
 
119
119
  # Rails engine routes need to be detected by inspecting Engine class route set
120
120
  def find_all_routes app, route_list
121
+ return route_list unless app.cs__respond_to?(:routes) && app.routes.cs__respond_to?(:routes)
122
+
121
123
  app.routes.routes.each do |route|
122
124
  if route.cs__respond_to?(:app) && route.app.cs__class == ActionDispatch::Routing::RouteSet::Dispatcher
123
125
  route_list << Contrast::Api::Dtm::RouteCoverage.from_action_dispatch_journey(route)
@@ -33,9 +33,17 @@ module Contrast
33
33
  def application_configuration
34
34
  return unless info?
35
35
 
36
- loggable = CONFIG.raw.send(:load_config)
37
- loggable.delete('api')
38
- info('Current configuration', configuration: JSON.pretty_generate(loggable))
36
+ loggable = CONFIG.raw.loggable
37
+ info('Current configuration', configuration: loggable)
38
+ env_keys = ENV.keys.select { |env_key| env_key&.to_s&.start_with?(Contrast::Components::Config::CONTRAST_ENV_MARKER) }
39
+ env_items = env_keys.map { |env_key| Contrast::Utils::EnvConfigurationItem.new(env_key, nil) }
40
+ env_translations = env_items.each_with_object({}) do |conversion, hash|
41
+ hash[conversion.key] = conversion.dot_path_array.join('.')
42
+ end
43
+ info('Set by environment', overrides: env_translations)
44
+ rescue StandardError => e
45
+ puts e
46
+ sleep(5)
39
47
  end
40
48
 
41
49
  def application_libraries
@@ -1,7 +1,9 @@
1
1
  # Copyright (c) 2020 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/assess/tracker'
4
5
  require 'contrast/components/interface'
6
+ require 'contrast/utils/duck_utils'
5
7
 
6
8
  module Contrast
7
9
  module Utils
@@ -23,6 +25,16 @@ module Contrast
23
25
  _tracked?(obj, 0)
24
26
  end
25
27
 
28
+ # Public interface to our tracking check, isolating the internals
29
+ # required for recursion.
30
+ #
31
+ # @param obj [Object] the thing to check if tracked
32
+ # @return [Boolean] if the obj, or something in it if a collection, is
33
+ # tracked.
34
+ def trackable? obj
35
+ _trackable?(obj, 0)
36
+ end
37
+
26
38
  private
27
39
 
28
40
  # Sometimes things are nested inside of each other, such as an Array
@@ -49,10 +61,8 @@ module Contrast
49
61
  obj.any? do |ele|
50
62
  _tracked?(ele, idx) unless obj == ele
51
63
  end
52
- elsif Contrast::Utils::DuckUtils.quacks_to?(obj, :cs__tracked?)
53
- obj.cs__tracked?
54
64
  else
55
- false
65
+ Contrast::Agent::Assess::Tracker.tracked?(obj)
56
66
  end
57
67
  rescue StandardError => e
58
68
  # This is used to ask if a ton of objects are tracked. They may not
@@ -61,6 +71,41 @@ module Contrast
61
71
  logger.warn('Failed to determine tracking', e, module: obj.cs__class)
62
72
  false
63
73
  end
74
+
75
+ # Sometimes things are nested inside of each other, such as an Array
76
+ # holding a Hash, holding that Array. In those cases, rather than
77
+ # entering an infinite loop, we'll break out.
78
+ # Right now, that level of nesting has been arbitrarily set to 10.
79
+ #
80
+ # @param obj [Object] the thing to check if trackable
81
+ # @param idx [Integer] the number of levels nested we've gone
82
+ # @return [Boolean] if the obj, or something in it if a collection, is
83
+ # trackable.
84
+ def _trackable? obj, idx
85
+ return false if obj.nil?
86
+ return false if idx > 10
87
+
88
+ idx += 1
89
+ if Contrast::Utils::DuckUtils.iterable_hash?(obj)
90
+ obj.each_pair do |k, v|
91
+ return true if _trackable?(k, idx)
92
+ return true if _trackable?(v, idx)
93
+ end
94
+ false
95
+ elsif Contrast::Utils::DuckUtils.iterable_enumerable?(obj)
96
+ obj.any? do |ele|
97
+ _trackable?(ele, idx) unless obj == ele
98
+ end
99
+ else
100
+ Contrast::Agent::Assess::Tracker.trackable?(obj)
101
+ end
102
+ rescue StandardError => e
103
+ # This is used to ask if a ton of objects are tracked. They may not
104
+ # all be iterable. Bad things could happen in some cases, like when
105
+ # checking a closed statement for SQL injection trigger events
106
+ logger.warn('Failed to determine trackable', e, module: obj.cs__class)
107
+ false
108
+ end
64
109
  end
65
110
  end
66
111
  end
@@ -62,16 +62,6 @@ module Contrast
62
62
  # otherwise, don't risk it
63
63
  false
64
64
  end
65
-
66
- # This method will return true if the object being checked has been patched
67
- # to have the cs__properties field. We check the cs__tracked? method since it
68
- # is side effect free (ie doesn't cause the properties object to be created).
69
- def trackable? object
70
- return true if object.cs__respond_to?(:cs__tracked?)
71
- return false unless object.is_a?(Delegator)
72
-
73
- object.cs__delegator_respond_to?(:cs__tracked?)
74
- end
75
65
  end
76
66
  end
77
67
  end
@@ -10,10 +10,11 @@ module Contrast
10
10
  END_UNDERSCORE = /(_+)$/.cs__freeze
11
11
  REPEATING_UNDERSCORE = /_{3,}/.cs__freeze
12
12
 
13
- attr_reader :value, :dot_path_array
13
+ attr_reader :value, :dot_path_array, :key
14
14
 
15
15
  def initialize key, value
16
16
  key = EnvConfigurationItem.resolve_corrected_path(key)
17
+ @key = key
17
18
  @dot_path_array = key.downcase.split(Contrast::Utils::ObjectShare::DOUBLE_UNDERSCORE)
18
19
  @value = value
19
20
 
@@ -9,7 +9,7 @@ module Contrast
9
9
  # customer applications, as determined by Configuration Rules at runtime.
10
10
  module InvalidConfigurationUtil
11
11
  include Contrast::Components::Interface
12
- access_component :analysis, :app_context, :logging
12
+ access_component :analysis, :app_context, :logging, :scope
13
13
 
14
14
  CS__PATH = 'path'
15
15
  CS__SESSION_ID = 'sessionId'
@@ -23,28 +23,30 @@ module Contrast
23
23
  # @param call_location [Thread::Backtrace::Location] the location where
24
24
  # the bad configuration was set
25
25
  def cs__report_finding rule_id, user_provided_options, call_location
26
- finding = Contrast::Api::Dtm::Finding.new
27
- finding.rule_id = rule_id
28
- path = call_location.path
29
- # just get the file name, not the full path
30
- path = path.split(Contrast::Utils::ObjectShare::SLASH).last
31
- session_id = user_provided_options[:key].to_s if user_provided_options
26
+ with_contrast_scope do
27
+ finding = Contrast::Api::Dtm::Finding.new
28
+ finding.rule_id = rule_id
29
+ path = call_location.path
30
+ # just get the file name, not the full path
31
+ path = path.split(Contrast::Utils::ObjectShare::SLASH).last
32
+ session_id = user_provided_options[:key].to_s if user_provided_options
32
33
 
33
- finding.version = Contrast::Agent::Assess::Policy::TriggerMethod::CURRENT_FINDING_VERSION
34
- finding.properties[CS__SESSION_ID] = Contrast::Utils::StringUtils.force_utf8(session_id)
35
- finding.properties[CS__PATH] = Contrast::Utils::StringUtils.force_utf8(path)
36
- file_path = call_location.absolute_path
37
- snippet = file_snippet(file_path, call_location)
38
- finding.properties[CS__SNIPPET] = Contrast::Utils::StringUtils.force_utf8(snippet)
34
+ finding.version = Contrast::Agent::Assess::Policy::TriggerMethod::CURRENT_FINDING_VERSION
35
+ finding.properties[CS__SESSION_ID] = Contrast::Utils::StringUtils.force_utf8(session_id)
36
+ finding.properties[CS__PATH] = Contrast::Utils::StringUtils.force_utf8(path)
37
+ file_path = call_location.absolute_path
38
+ snippet = file_snippet(file_path, call_location)
39
+ finding.properties[CS__SNIPPET] = Contrast::Utils::StringUtils.force_utf8(snippet)
39
40
 
40
- hash = Contrast::Utils::HashDigest.generate_config_hash(finding)
41
- finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash)
42
- finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
41
+ hash = Contrast::Utils::HashDigest.generate_config_hash(finding)
42
+ finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash)
43
+ finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
43
44
 
44
- activity = Contrast::Api::Dtm::Activity.new
45
- activity.findings << finding
45
+ activity = Contrast::Api::Dtm::Activity.new
46
+ activity.findings << finding
46
47
 
47
- Contrast::Agent.messaging_queue.send_event_eventually(activity)
48
+ Contrast::Agent.messaging_queue.send_event_eventually(activity)
49
+ end
48
50
  rescue StandardError => e
49
51
  logger.error('Unable to build a finding', e, rule: rule_id)
50
52
  end