contrast-agent 3.14.0 → 3.15.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.
- checksums.yaml +4 -4
 - data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +18 -15
 - data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
 - data/ext/cs__assess_string/cs__assess_string.c +24 -25
 - data/ext/cs__assess_string/cs__assess_string.h +3 -1
 - data/ext/cs__common/cs__common.c +4 -2
 - data/ext/cs__common/cs__common.h +1 -1
 - data/lib/contrast.rb +1 -1
 - data/lib/contrast/agent/assess.rb +1 -0
 - data/lib/contrast/agent/assess/contrast_event.rb +4 -12
 - data/lib/contrast/agent/assess/finalizers/freeze.rb +3 -1
 - data/lib/contrast/agent/assess/finalizers/hash.rb +45 -1
 - data/lib/contrast/agent/assess/policy/patcher.rb +1 -1
 - data/lib/contrast/agent/assess/policy/policy.rb +0 -2
 - data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -1
 - data/lib/contrast/agent/assess/policy/preshift.rb +7 -11
 - data/lib/contrast/agent/assess/policy/propagation_method.rb +50 -33
 - data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
 - data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
 - data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
 - data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -3
 - data/lib/contrast/agent/assess/policy/propagator/insert.rb +6 -3
 - data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
 - data/lib/contrast/agent/assess/policy/propagator/match_data.rb +6 -6
 - data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
 - data/lib/contrast/agent/assess/policy/propagator/prepend.rb +8 -5
 - data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
 - data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
 - data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
 - data/lib/contrast/agent/assess/policy/propagator/select.rb +15 -7
 - data/lib/contrast/agent/assess/policy/propagator/splat.rb +14 -8
 - data/lib/contrast/agent/assess/policy/propagator/split.rb +14 -8
 - data/lib/contrast/agent/assess/policy/propagator/substitution.rb +30 -21
 - data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
 - data/lib/contrast/agent/assess/policy/source_method.rb +85 -58
 - data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -11
 - data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
 - data/lib/contrast/agent/assess/policy/trigger_method.rb +38 -15
 - data/lib/contrast/agent/assess/policy/trigger_node.rb +14 -13
 - data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
 - data/lib/contrast/agent/assess/properties.rb +2 -0
 - data/lib/contrast/agent/assess/property/updated.rb +136 -0
 - data/lib/contrast/agent/assess/tracker.rb +66 -0
 - data/lib/contrast/agent/class_reopener.rb +7 -5
 - data/lib/contrast/agent/middleware.rb +0 -1
 - data/lib/contrast/agent/patching/policy/patcher.rb +13 -22
 - data/lib/contrast/agent/patching/policy/policy.rb +1 -4
 - data/lib/contrast/agent/response.rb +17 -6
 - data/lib/contrast/agent/rewriter.rb +1 -3
 - data/lib/contrast/agent/version.rb +1 -1
 - data/lib/contrast/api/communication/messaging_queue.rb +1 -4
 - data/lib/contrast/api/decorators/application_update.rb +2 -4
 - data/lib/contrast/api/decorators/trace_event.rb +5 -5
 - data/lib/contrast/components/app_context.rb +11 -9
 - data/lib/contrast/components/config.rb +3 -13
 - data/lib/contrast/components/contrast_service.rb +2 -2
 - data/lib/contrast/config/application_configuration.rb +5 -2
 - data/lib/contrast/config/service_configuration.rb +8 -2
 - data/lib/contrast/configuration.rb +88 -47
 - data/lib/contrast/extension/assess.rb +0 -2
 - data/lib/contrast/extension/assess/array.rb +8 -5
 - data/lib/contrast/extension/assess/erb.rb +6 -3
 - data/lib/contrast/extension/assess/fiber.rb +9 -9
 - data/lib/contrast/extension/assess/hash.rb +2 -3
 - data/lib/contrast/extension/assess/kernel.rb +12 -5
 - data/lib/contrast/extension/assess/marshal.rb +3 -2
 - data/lib/contrast/extension/assess/regexp.rb +5 -4
 - data/lib/contrast/extension/assess/string.rb +8 -10
 - data/lib/contrast/framework/rack/patch/session_cookie.rb +12 -18
 - data/lib/contrast/framework/rails/patch/assess_configuration.rb +4 -10
 - data/lib/contrast/framework/rails/support.rb +2 -0
 - data/lib/contrast/logger/application.rb +11 -3
 - data/lib/contrast/utils/assess/tracking_util.rb +48 -3
 - data/lib/contrast/utils/duck_utils.rb +0 -10
 - data/lib/contrast/utils/env_configuration_item.rb +2 -1
 - data/lib/contrast/utils/invalid_configuration_util.rb +21 -19
 - data/lib/contrast/utils/string_utils.rb +10 -5
 - data/resources/assess/policy.json +0 -10
 - data/ruby-agent.gemspec +16 -15
 - data/service_executables/VERSION +1 -1
 - data/service_executables/linux/contrast-service +0 -0
 - data/service_executables/mac/contrast-service +0 -0
 - metadata +42 -21
 - data/lib/contrast/agent/assess/finalizers/finalize.rb +0 -21
 - data/lib/contrast/extension/assess/assess_extension.rb +0 -145
 - data/lib/contrast/utils/freeze_util.rb +0 -32
 
| 
         @@ -16,6 +16,9 @@ module Contrast 
     | 
|
| 
       16 
16 
     | 
    
         
             
                          # copy tags from the param to the target in chunks of param size or less
         
     | 
| 
       17 
17 
     | 
    
         
             
                          # if param is appended in space less than param length
         
     | 
| 
       18 
18 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 19 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 20 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       19 
22 
     | 
    
         
             
                            sources = propagation_node.sources
         
     | 
| 
       20 
23 
     | 
    
         
             
                            source1 = find_source(sources[0], preshift)
         
     | 
| 
       21 
24 
     | 
    
         
             
                            # Some appends have two args. If they don't this is probably something
         
     | 
| 
         @@ -25,25 +28,25 @@ module Contrast 
     | 
|
| 
       25 
28 
     | 
    
         
             
                            # if the object and the return are the same length just copy the tags
         
     | 
| 
       26 
29 
     | 
    
         
             
                            # from the object(since nothing from args was added to return)
         
     | 
| 
       27 
30 
     | 
    
         
             
                            if source1.length == target.length
         
     | 
| 
       28 
     | 
    
         
            -
                               
     | 
| 
      
 31 
     | 
    
         
            +
                              properties.copy_from(source1, target, 0, propagation_node.untags)
         
     | 
| 
       29 
32 
     | 
    
         
             
                            else
         
     | 
| 
       30 
33 
     | 
    
         
             
                              # find original in the target, copy tags to the new position in
         
     | 
| 
       31 
34 
     | 
    
         
             
                              # target
         
     | 
| 
       32 
35 
     | 
    
         
             
                              original_start_index = target.index(source1)
         
     | 
| 
       33 
     | 
    
         
            -
                               
     | 
| 
      
 36 
     | 
    
         
            +
                              properties.copy_from(source1, target, original_start_index, propagation_node.untags)
         
     | 
| 
       34 
37 
     | 
    
         | 
| 
       35 
38 
     | 
    
         
             
                              start = original_start_index + source1.length
         
     | 
| 
       36 
39 
     | 
    
         
             
                              while start < target.length
         
     | 
| 
       37 
     | 
    
         
            -
                                 
     | 
| 
      
 40 
     | 
    
         
            +
                                properties.copy_from(source2, target, start, propagation_node.untags)
         
     | 
| 
       38 
41 
     | 
    
         
             
                                start += source2.length
         
     | 
| 
       39 
42 
     | 
    
         
             
                                next unless start > target.length
         
     | 
| 
       40 
43 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                                 
     | 
| 
      
 44 
     | 
    
         
            +
                                properties.tags_at(start - source2.length).each do |tag|
         
     | 
| 
       42 
45 
     | 
    
         
             
                                  tag.update_end(target.length)
         
     | 
| 
       43 
46 
     | 
    
         
             
                                end
         
     | 
| 
       44 
47 
     | 
    
         
             
                              end
         
     | 
| 
       45 
48 
     | 
    
         
             
                            end
         
     | 
| 
       46 
     | 
    
         
            -
                             
     | 
| 
      
 49 
     | 
    
         
            +
                            properties.cleanup_tags
         
     | 
| 
       47 
50 
     | 
    
         
             
                          end
         
     | 
| 
       48 
51 
     | 
    
         
             
                        end
         
     | 
| 
       49 
52 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -12,19 +12,22 @@ module Contrast 
     | 
|
| 
       12 
12 
     | 
    
         
             
                      class Center < Contrast::Agent::Assess::Policy::Propagator::Base
         
     | 
| 
       13 
13 
     | 
    
         
             
                        class << self
         
     | 
| 
       14 
14 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 15 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 16 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       15 
18 
     | 
    
         
             
                            sources = propagation_node.sources
         
     | 
| 
       16 
19 
     | 
    
         
             
                            source1 = find_source(sources[0], preshift)
         
     | 
| 
       17 
20 
     | 
    
         | 
| 
       18 
21 
     | 
    
         
             
                            if source1.length == target.length
         
     | 
| 
       19 
     | 
    
         
            -
                               
     | 
| 
       20 
     | 
    
         
            -
                               
     | 
| 
      
 22 
     | 
    
         
            +
                              properties.copy_from(source1, target, 0, propagation_node.untags)
         
     | 
| 
      
 23 
     | 
    
         
            +
                              properties.cleanup_tags
         
     | 
| 
       21 
24 
     | 
    
         
             
                              return
         
     | 
| 
       22 
25 
     | 
    
         
             
                            end
         
     | 
| 
       23 
26 
     | 
    
         | 
| 
       24 
27 
     | 
    
         
             
                            # find original in the target, copy tags to the new position in target
         
     | 
| 
       25 
28 
     | 
    
         
             
                            original_start_index = target[0..target.length / 2 + 1].rindex(source1)
         
     | 
| 
       26 
29 
     | 
    
         
             
                            original_start_index ||= 1
         
     | 
| 
       27 
     | 
    
         
            -
                             
     | 
| 
      
 30 
     | 
    
         
            +
                            properties.copy_from(source1, target, original_start_index, propagation_node.untags)
         
     | 
| 
       28 
31 
     | 
    
         | 
| 
       29 
32 
     | 
    
         
             
                            return unless sources[1]
         
     | 
| 
       30 
33 
     | 
    
         | 
| 
         @@ -54,12 +57,13 @@ module Contrast 
     | 
|
| 
       54 
57 
     | 
    
         
             
                          end
         
     | 
| 
       55 
58 
     | 
    
         | 
| 
       56 
59 
     | 
    
         
             
                          def iterate_tags target, propagation_node, source, start, stop
         
     | 
| 
      
 60 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
       57 
61 
     | 
    
         
             
                            while start < stop
         
     | 
| 
       58 
     | 
    
         
            -
                               
     | 
| 
      
 62 
     | 
    
         
            +
                              properties.copy_from(source, target, start, propagation_node.untags)
         
     | 
| 
       59 
63 
     | 
    
         
             
                              start += source.length
         
     | 
| 
       60 
64 
     | 
    
         
             
                              next unless start > stop
         
     | 
| 
       61 
65 
     | 
    
         | 
| 
       62 
     | 
    
         
            -
                               
     | 
| 
      
 66 
     | 
    
         
            +
                              properties.tags_at(start - source.length).each do |tag|
         
     | 
| 
       63 
67 
     | 
    
         
             
                                tag.update_end(stop)
         
     | 
| 
       64 
68 
     | 
    
         
             
                              end
         
     | 
| 
       65 
69 
     | 
    
         
             
                            end
         
     | 
| 
         @@ -31,12 +31,15 @@ module Contrast 
     | 
|
| 
       31 
31 
     | 
    
         
             
                                next unless value
         
     | 
| 
       32 
32 
     | 
    
         
             
                                next if known_tainted&.include?(key)
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
                                properties = Contrast::Agent::Assess::Tracker.properties(value)
         
     | 
| 
      
 35 
     | 
    
         
            +
                                next unless properties
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       34 
37 
     | 
    
         
             
                                # TODO: RUBY-540 handle sanitization, handle nested objects
         
     | 
| 
       35 
38 
     | 
    
         
             
                                Contrast::Agent::Assess::Policy::PropagationMethod.apply_tags(propagation_node, value)
         
     | 
| 
       36 
     | 
    
         
            -
                                 
     | 
| 
      
 39 
     | 
    
         
            +
                                properties.build_event(propagation_node, value, preshift.object, target, preshift.args)
         
     | 
| 
       37 
40 
     | 
    
         
             
                                next unless tracked_value?(value)
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                                tainted_columns[key] =  
     | 
| 
      
 42 
     | 
    
         
            +
                                tainted_columns[key] = properties
         
     | 
| 
       40 
43 
     | 
    
         
             
                              end
         
     | 
| 
       41 
44 
     | 
    
         
             
                            end
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
         @@ -45,7 +48,6 @@ module Contrast 
     | 
|
| 
       45 
48 
     | 
    
         
             
                            if known_tainted
         
     | 
| 
       46 
49 
     | 
    
         
             
                              known_tainted.concat(tainted_columns.keys)
         
     | 
| 
       47 
50 
     | 
    
         
             
                            else
         
     | 
| 
       48 
     | 
    
         
            -
                              class_type.send(:include, Contrast::Extension::Assess::AssessExtension) unless class_type < Contrast::Extension::Assess::AssessExtension
         
     | 
| 
       49 
51 
     | 
    
         
             
                              ASSESS.tainted_columns[class_name] = tainted_columns.keys
         
     | 
| 
       50 
52 
     | 
    
         
             
                            end
         
     | 
| 
       51 
53 
     | 
    
         | 
| 
         @@ -16,6 +16,9 @@ module Contrast 
     | 
|
| 
       16 
16 
     | 
    
         
             
                          # Unlike additive propagation, this currently only supports one source
         
     | 
| 
       17 
17 
     | 
    
         
             
                          # We assume that insert changes the preshift target
         
     | 
| 
       18 
18 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 19 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 20 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
       19 
22 
     | 
    
         
             
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
       20 
23 
     | 
    
         | 
| 
       21 
24 
     | 
    
         
             
                            patcher_target = propagation_node.targets[0]
         
     | 
| 
         @@ -38,10 +41,10 @@ module Contrast 
     | 
|
| 
       38 
41 
     | 
    
         
             
                            overflow = insert_point...(insert_point + source.length)
         
     | 
| 
       39 
42 
     | 
    
         | 
| 
       40 
43 
     | 
    
         
             
                            # handle shifting the inserted range
         
     | 
| 
       41 
     | 
    
         
            -
                             
     | 
| 
      
 44 
     | 
    
         
            +
                            properties.shift_tags([overflow])
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                             
     | 
| 
       44 
     | 
    
         
            -
                             
     | 
| 
      
 46 
     | 
    
         
            +
                            properties.copy_from(source, target, insert_point, propagation_node.untags)
         
     | 
| 
      
 47 
     | 
    
         
            +
                            properties.cleanup_tags
         
     | 
| 
       45 
48 
     | 
    
         
             
                          end
         
     | 
| 
       46 
49 
     | 
    
         
             
                        end
         
     | 
| 
       47 
50 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -14,8 +14,11 @@ module Contrast 
     | 
|
| 
       14 
14 
     | 
    
         
             
                          # Keep means the tags just pass from the source to the target
         
     | 
| 
       15 
15 
     | 
    
         
             
                          # as is.
         
     | 
| 
       16 
16 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 17 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 18 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       17 
20 
     | 
    
         
             
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
       18 
     | 
    
         
            -
                             
     | 
| 
      
 21 
     | 
    
         
            +
                            properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       19 
22 
     | 
    
         
             
                          end
         
     | 
| 
       20 
23 
     | 
    
         
             
                        end
         
     | 
| 
       21 
24 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -67,18 +67,18 @@ module Contrast 
     | 
|
| 
       67 
67 
     | 
    
         
             
                          def square_bracket_single argument_index, preshift, return_value, propagation_node
         
     | 
| 
       68 
68 
     | 
    
         
             
                            original_start_index = preshift.object.begin(argument_index)
         
     | 
| 
       69 
69 
     | 
    
         
             
                            original_end_index = preshift.object.end(argument_index)
         
     | 
| 
       70 
     | 
    
         
            -
                            original_properties = preshift.object 
     | 
| 
      
 70 
     | 
    
         
            +
                            original_properties = Contrast::Agent::Assess::Tracker.properties(preshift.object)
         
     | 
| 
       71 
71 
     | 
    
         
             
                            applicable_tags = original_properties.tags_at_range(original_start_index...original_end_index)
         
     | 
| 
       72 
72 
     | 
    
         
             
                            return if applicable_tags.empty?
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
      
 74 
     | 
    
         
            +
                            return_properties = Contrast::Agent::Assess::Tracker.properties(return_value)
         
     | 
| 
       74 
75 
     | 
    
         
             
                            applicable_tags.each do |tag_name, tag_ranges|
         
     | 
| 
       75 
     | 
    
         
            -
                               
     | 
| 
      
 76 
     | 
    
         
            +
                              return_properties.set_tags(tag_name, tag_ranges)
         
     | 
| 
       76 
77 
     | 
    
         
             
                            end
         
     | 
| 
       77 
     | 
    
         
            -
                             
     | 
| 
       78 
     | 
    
         
            -
                               
     | 
| 
      
 78 
     | 
    
         
            +
                            original_properties.events.each do |event|
         
     | 
| 
      
 79 
     | 
    
         
            +
                              return_properties.add_event(event)
         
     | 
| 
       79 
80 
     | 
    
         
             
                            end
         
     | 
| 
       80 
     | 
    
         
            -
                            return_value. 
     | 
| 
       81 
     | 
    
         
            -
                                propagation_node, return_value, preshift.object, return_value, preshift.args)
         
     | 
| 
      
 81 
     | 
    
         
            +
                            return_properties.build_event(propagation_node, return_value, preshift.object, return_value, preshift.args)
         
     | 
| 
       82 
82 
     | 
    
         
             
                          end
         
     | 
| 
       83 
83 
     | 
    
         
             
                        end
         
     | 
| 
       84 
84 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -15,23 +15,25 @@ module Contrast 
     | 
|
| 
       15 
15 
     | 
    
         
             
                          # String has some silly methods like next. Basically, this flips a
         
     | 
| 
       16 
16 
     | 
    
         
             
                          # character in a predictable manner
         
     | 
| 
       17 
17 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
       18 
     | 
    
         
            -
                             
     | 
| 
      
 18 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 19 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
       19 
20 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                             
     | 
| 
      
 21 
     | 
    
         
            +
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
      
 22 
     | 
    
         
            +
                            properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       21 
23 
     | 
    
         | 
| 
       22 
24 
     | 
    
         
             
                            # this means the char that was shifted overflowed and created new
         
     | 
| 
       23 
25 
     | 
    
         
             
                            # chars (i.e 'z' "wraps" to create 'aa' )
         
     | 
| 
       24 
26 
     | 
    
         
             
                            unless target.length == source.length
         
     | 
| 
       25 
     | 
    
         
            -
                               
     | 
| 
      
 27 
     | 
    
         
            +
                              properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
                              first_difference = (0...source.length).find { |i| source[i] != target[i] } || source.length
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                               
     | 
| 
      
 31 
     | 
    
         
            +
                              properties.tags_at(first_difference).each do |tag|
         
     | 
| 
       30 
32 
     | 
    
         
             
                                tag.shift_end(target.length - source.length)
         
     | 
| 
       31 
33 
     | 
    
         
             
                              end
         
     | 
| 
       32 
34 
     | 
    
         
             
                            end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                             
     | 
| 
      
 36 
     | 
    
         
            +
                            properties.cleanup_tags
         
     | 
| 
       35 
37 
     | 
    
         
             
                          end
         
     | 
| 
       36 
38 
     | 
    
         
             
                        end
         
     | 
| 
       37 
39 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -14,6 +14,9 @@ module Contrast 
     | 
|
| 
       14 
14 
     | 
    
         
             
                          # For the source, prepend its tags to the target. It's basically the
         
     | 
| 
       15 
15 
     | 
    
         
             
                          # opposite of append. :-P
         
     | 
| 
       16 
16 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 17 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 18 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       17 
20 
     | 
    
         
             
                            sources = propagation_node.sources
         
     | 
| 
       18 
21 
     | 
    
         
             
                            # source1 is the copy of the thing being prepended to
         
     | 
| 
       19 
22 
     | 
    
         
             
                            source1 = find_source(sources[0], preshift)
         
     | 
| 
         @@ -26,25 +29,25 @@ module Contrast 
     | 
|
| 
       26 
29 
     | 
    
         
             
                            # tags from the object(since nothing from args was added to
         
     | 
| 
       27 
30 
     | 
    
         
             
                            # return)
         
     | 
| 
       28 
31 
     | 
    
         
             
                            if source1.length == target.length
         
     | 
| 
       29 
     | 
    
         
            -
                               
     | 
| 
      
 32 
     | 
    
         
            +
                              properties.copy_from(source1, target, 0, propagation_node.untags)
         
     | 
| 
       30 
33 
     | 
    
         
             
                            else
         
     | 
| 
       31 
34 
     | 
    
         
             
                              # find original in the target, copy tags to the new position in target
         
     | 
| 
       32 
     | 
    
         
            -
                               
     | 
| 
      
 35 
     | 
    
         
            +
                              properties.copy_from(source1, target, original_start_index, propagation_node.untags)
         
     | 
| 
       33 
36 
     | 
    
         
             
                              # then we add the tags from the thing prepended to the start
         
     | 
| 
       34 
37 
     | 
    
         
             
                              # of the target
         
     | 
| 
       35 
38 
     | 
    
         
             
                              start = 0
         
     | 
| 
       36 
39 
     | 
    
         
             
                              while start < original_start_index
         
     | 
| 
       37 
     | 
    
         
            -
                                 
     | 
| 
      
 40 
     | 
    
         
            +
                                properties.copy_from(source2, target, start, propagation_node.untags)
         
     | 
| 
       38 
41 
     | 
    
         
             
                                start += source2.length
         
     | 
| 
       39 
42 
     | 
    
         
             
                                next unless start > original_start_index
         
     | 
| 
       40 
43 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                                 
     | 
| 
      
 44 
     | 
    
         
            +
                                properties.tags_at(start - source2.length).each do |tag|
         
     | 
| 
       42 
45 
     | 
    
         
             
                                  tag.update_end(original_start_index)
         
     | 
| 
       43 
46 
     | 
    
         
             
                                end
         
     | 
| 
       44 
47 
     | 
    
         
             
                              end
         
     | 
| 
       45 
48 
     | 
    
         
             
                            end
         
     | 
| 
       46 
49 
     | 
    
         
             
                            # and finally merge the tags if any overlap.
         
     | 
| 
       47 
     | 
    
         
            -
                             
     | 
| 
      
 50 
     | 
    
         
            +
                            properties.cleanup_tags
         
     | 
| 
       48 
51 
     | 
    
         
             
                          end
         
     | 
| 
       49 
52 
     | 
    
         
             
                        end
         
     | 
| 
       50 
53 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -17,15 +17,19 @@ module Contrast 
     | 
|
| 
       17 
17 
     | 
    
         
             
                          # Once the tag is applied, remove the section that was removed by the delete.
         
     | 
| 
       18 
18 
     | 
    
         
             
                          # Unlike additive propagation, this currently only supports one source
         
     | 
| 
       19 
19 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
       20 
     | 
    
         
            -
                             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                            target.cs__copy_from(source, 0, propagation_node.untags)
         
     | 
| 
      
 20 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 21 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
       23 
22 
     | 
    
         | 
| 
      
 23 
     | 
    
         
            +
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
      
 24 
     | 
    
         
            +
                            properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       24 
25 
     | 
    
         
             
                            source_chars = source.is_a?(String) ? source.chars : source.string.chars
         
     | 
| 
       25 
26 
     | 
    
         
             
                            handle_removal(source_chars, target)
         
     | 
| 
       26 
27 
     | 
    
         
             
                          end
         
     | 
| 
       27 
28 
     | 
    
         | 
| 
       28 
29 
     | 
    
         
             
                          def handle_removal source_chars, target
         
     | 
| 
      
 30 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 31 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
       29 
33 
     | 
    
         
             
                            source_idx = 0
         
     | 
| 
       30 
34 
     | 
    
         | 
| 
       31 
35 
     | 
    
         
             
                            target_chars = target.chars
         
     | 
| 
         @@ -60,7 +64,7 @@ module Contrast 
     | 
|
| 
       60 
64 
     | 
    
         
             
                            remove_ranges << (source_idx...source_chars.length) if source_idx != source_chars.length
         
     | 
| 
       61 
65 
     | 
    
         | 
| 
       62 
66 
     | 
    
         
             
                            # handle deleting the removed ranges
         
     | 
| 
       63 
     | 
    
         
            -
                             
     | 
| 
      
 67 
     | 
    
         
            +
                            properties.delete_tags_at_ranges(remove_ranges)
         
     | 
| 
       64 
68 
     | 
    
         
             
                          end
         
     | 
| 
       65 
69 
     | 
    
         
             
                        end
         
     | 
| 
       66 
70 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -14,9 +14,12 @@ module Contrast 
     | 
|
| 
       14 
14 
     | 
    
         
             
                          # Replace means we're replacing the target w/ the source. Anything
         
     | 
| 
       15 
15 
     | 
    
         
             
                          # on the source should be passed to the target.
         
     | 
| 
       16 
16 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
      
 17 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 18 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       17 
20 
     | 
    
         
             
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
       18 
     | 
    
         
            -
                             
     | 
| 
       19 
     | 
    
         
            -
                             
     | 
| 
      
 21 
     | 
    
         
            +
                            properties.clear_tags
         
     | 
| 
      
 22 
     | 
    
         
            +
                            properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       20 
23 
     | 
    
         
             
                          end
         
     | 
| 
       21 
24 
     | 
    
         
             
                        end
         
     | 
| 
       22 
25 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -13,13 +13,15 @@ module Contrast 
     | 
|
| 
       13 
13 
     | 
    
         
             
                      class Reverse < Contrast::Agent::Assess::Policy::Propagator::Base
         
     | 
| 
       14 
14 
     | 
    
         
             
                        class << self
         
     | 
| 
       15 
15 
     | 
    
         
             
                          def propagate propagation_node, preshift, target
         
     | 
| 
       16 
     | 
    
         
            -
                             
     | 
| 
      
 16 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 17 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                             
     | 
| 
      
 19 
     | 
    
         
            +
                            source = find_source(propagation_node.sources[0], preshift)
         
     | 
| 
      
 20 
     | 
    
         
            +
                            properties.copy_from(source, target, 0, propagation_node.untags)
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
22 
     | 
    
         
             
                            length = target.length
         
     | 
| 
       21 
     | 
    
         
            -
                             
     | 
| 
       22 
     | 
    
         
            -
                              tags =  
     | 
| 
      
 23 
     | 
    
         
            +
                            properties.tag_keys.each do |key|
         
     | 
| 
      
 24 
     | 
    
         
            +
                              tags = properties.fetch_tag(key)
         
     | 
| 
       23 
25 
     | 
    
         
             
                              tags.each do |tag|
         
     | 
| 
       24 
26 
     | 
    
         
             
                                new_end = length - tag.start_idx
         
     | 
| 
       25 
27 
     | 
    
         
             
                                new_start = new_end - tag.length
         
     | 
| 
         @@ -27,7 +29,7 @@ module Contrast 
     | 
|
| 
       27 
29 
     | 
    
         
             
                              end
         
     | 
| 
       28 
30 
     | 
    
         
             
                            end
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
                             
     | 
| 
      
 32 
     | 
    
         
            +
                            properties.cleanup_tags
         
     | 
| 
       31 
33 
     | 
    
         
             
                          end
         
     | 
| 
       32 
34 
     | 
    
         
             
                        end
         
     | 
| 
       33 
35 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -14,6 +14,9 @@ module Contrast 
     | 
|
| 
       14 
14 
     | 
    
         
             
                      class Select
         
     | 
| 
       15 
15 
     | 
    
         
             
                        class << self
         
     | 
| 
       16 
16 
     | 
    
         
             
                          def select_tagger patcher, preshift, ret, _block
         
     | 
| 
      
 17 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(ret)
         
     | 
| 
      
 18 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
       17 
20 
     | 
    
         
             
                            source = preshift.object
         
     | 
| 
       18 
21 
     | 
    
         
             
                            args = preshift.args
         
     | 
| 
       19 
22 
     | 
    
         | 
| 
         @@ -21,12 +24,17 @@ module Contrast 
     | 
|
| 
       21 
24 
     | 
    
         
             
                            # Additionally, an empty string is returned when the starting index for
         
     | 
| 
       22 
25 
     | 
    
         
             
                            # a character range is at the end of the string. Let's just skip that
         
     | 
| 
       23 
26 
     | 
    
         
             
                            # and only track a string that has length
         
     | 
| 
       24 
     | 
    
         
            -
                             
     | 
| 
      
 27 
     | 
    
         
            +
                            unless ret &&
         
     | 
| 
      
 28 
     | 
    
         
            +
                                  !ret.empty? &&
         
     | 
| 
      
 29 
     | 
    
         
            +
                                  Contrast::Agent::Assess::Tracker.tracked?(source)
         
     | 
| 
      
 30 
     | 
    
         
            +
                              return
         
     | 
| 
      
 31 
     | 
    
         
            +
                            end
         
     | 
| 
       25 
32 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
      
 33 
     | 
    
         
            +
                            source_properties = Contrast::Agent::Assess::Tracker.properties(source)
         
     | 
| 
      
 34 
     | 
    
         
            +
                            source_properties.events.each do |event|
         
     | 
| 
      
 35 
     | 
    
         
            +
                              properties.events << event
         
     | 
| 
       28 
36 
     | 
    
         
             
                            end
         
     | 
| 
       29 
     | 
    
         
            -
                             
     | 
| 
      
 37 
     | 
    
         
            +
                            properties.build_event(
         
     | 
| 
       30 
38 
     | 
    
         
             
                                patcher,
         
     | 
| 
       31 
39 
     | 
    
         
             
                                ret,
         
     | 
| 
       32 
40 
     | 
    
         
             
                                source,
         
     | 
| 
         @@ -36,10 +44,10 @@ module Contrast 
     | 
|
| 
       36 
44 
     | 
    
         
             
                            range = determine_select_range(source, args)
         
     | 
| 
       37 
45 
     | 
    
         
             
                            return unless range
         
     | 
| 
       38 
46 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                            tags =  
     | 
| 
       40 
     | 
    
         
            -
                             
     | 
| 
      
 47 
     | 
    
         
            +
                            tags = source_properties.tags_at_range(range)
         
     | 
| 
      
 48 
     | 
    
         
            +
                            properties.clear_tags
         
     | 
| 
       41 
49 
     | 
    
         
             
                            tags.each_pair do |key, value|
         
     | 
| 
       42 
     | 
    
         
            -
                               
     | 
| 
      
 50 
     | 
    
         
            +
                              properties.set_tags(key, value)
         
     | 
| 
       43 
51 
     | 
    
         
             
                            end
         
     | 
| 
       44 
52 
     | 
    
         
             
                            ret
         
     | 
| 
       45 
53 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -17,11 +17,11 @@ module Contrast 
     | 
|
| 
       17 
17 
     | 
    
         
             
                            propagation_node.sources.each do |source|
         
     | 
| 
       18 
18 
     | 
    
         
             
                              case source
         
     | 
| 
       19 
19 
     | 
    
         
             
                              when Contrast::Utils::ObjectShare::OBJECT_KEY
         
     | 
| 
       20 
     | 
    
         
            -
                                tracked_inputs << preshift.object if preshift.object 
     | 
| 
      
 20 
     | 
    
         
            +
                                tracked_inputs << preshift.object if Contrast::Agent::Assess::Tracker.tracked?(preshift.object)
         
     | 
| 
       21 
21 
     | 
    
         
             
                              else
         
     | 
| 
       22 
22 
     | 
    
         
             
                                arg = preshift.args[source]
         
     | 
| 
       23 
23 
     | 
    
         
             
                                if arg.is_a?(String)
         
     | 
| 
       24 
     | 
    
         
            -
                                  tracked_inputs << arg if  
     | 
| 
      
 24 
     | 
    
         
            +
                                  tracked_inputs << arg if Contrast::Agent::Assess::Tracker.tracked?(arg)
         
     | 
| 
       25 
25 
     | 
    
         
             
                                elsif Contrast::Utils::DuckUtils.iterable_hash?(arg)
         
     | 
| 
       26 
26 
     | 
    
         
             
                                  arg.each_pair do |key, value|
         
     | 
| 
       27 
27 
     | 
    
         
             
                                    tracked_inputs << key if tracked_value?(key)
         
     | 
| 
         @@ -36,19 +36,25 @@ module Contrast 
     | 
|
| 
       36 
36 
     | 
    
         
             
                            end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                            splat_tags(tracked_inputs, target)
         
     | 
| 
       39 
     | 
    
         
            -
                            target. 
     | 
| 
      
 39 
     | 
    
         
            +
                            Contrast::Agent::Assess::Tracker.properties(target).cleanup_tags
         
     | 
| 
       40 
40 
     | 
    
         
             
                          end
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
                          def splat_tags tracked_inputs, target
         
     | 
| 
       43 
43 
     | 
    
         
             
                            return if tracked_inputs.empty?
         
     | 
| 
       44 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 46 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       45 
48 
     | 
    
         
             
                            tracked_inputs.each do |input|
         
     | 
| 
       46 
     | 
    
         
            -
                               
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                              input_properties = Contrast::Agent::Assess::Tracker.properties(input)
         
     | 
| 
      
 50 
     | 
    
         
            +
                              next unless input_properties
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                              properties.splat_from(input, target)
         
     | 
| 
      
 53 
     | 
    
         
            +
                              next if input == target
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                              input_properties.events.each do |event|
         
     | 
| 
      
 56 
     | 
    
         
            +
                                properties.events << event
         
     | 
| 
       50 
57 
     | 
    
         
             
                              end
         
     | 
| 
       51 
     | 
    
         
            -
                              input.cs__splat_tags(target)
         
     | 
| 
       52 
58 
     | 
    
         
             
                            end
         
     | 
| 
       53 
59 
     | 
    
         
             
                          end
         
     | 
| 
       54 
60 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -53,17 +53,20 @@ module Contrast 
     | 
|
| 
       53 
53 
     | 
    
         
             
                            target.each do |elem|
         
     | 
| 
       54 
54 
     | 
    
         
             
                              elem_length = elem.length
         
     | 
| 
       55 
55 
     | 
    
         
             
                              range = current_index...(current_index + elem_length)
         
     | 
| 
       56 
     | 
    
         
            -
                               
     | 
| 
      
 56 
     | 
    
         
            +
                              elem_properties = Contrast::Agent::Assess::Tracker.properties(elem)
         
     | 
| 
      
 57 
     | 
    
         
            +
                              next unless elem_properties
         
     | 
| 
       57 
58 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                               
     | 
| 
      
 59 
     | 
    
         
            +
                              source_properties = Contrast::Agent::Assess::Tracker.properties(source)
         
     | 
| 
      
 60 
     | 
    
         
            +
                              tags = source_properties.tags_at_range(range)
         
     | 
| 
      
 61 
     | 
    
         
            +
                              elem_properties.clear_tags
         
     | 
| 
       59 
62 
     | 
    
         
             
                              tags.each_pair do |key, value|
         
     | 
| 
       60 
     | 
    
         
            -
                                 
     | 
| 
      
 63 
     | 
    
         
            +
                                elem_properties.set_tags(key, value)
         
     | 
| 
       61 
64 
     | 
    
         
             
                              end
         
     | 
| 
       62 
     | 
    
         
            -
                               
     | 
| 
       63 
     | 
    
         
            -
                                 
     | 
| 
      
 65 
     | 
    
         
            +
                              source_properties.events.each do |event|
         
     | 
| 
      
 66 
     | 
    
         
            +
                                elem_properties.add_event(event)
         
     | 
| 
       64 
67 
     | 
    
         
             
                              end
         
     | 
| 
       65 
     | 
    
         
            -
                               
     | 
| 
       66 
     | 
    
         
            -
                               
     | 
| 
      
 68 
     | 
    
         
            +
                              elem_properties.build_event(propagation_node, elem, preshift.object, target, preshift.args, 0)
         
     | 
| 
      
 69 
     | 
    
         
            +
                              elem_properties.add_properties(propagation_node.properties)
         
     | 
| 
       67 
70 
     | 
    
         
             
                              current_index = current_index + elem_length + separator_length
         
     | 
| 
       68 
71 
     | 
    
         
             
                            end
         
     | 
| 
       69 
72 
     | 
    
         
             
                            nil
         
     | 
| 
         @@ -125,8 +128,11 @@ module Contrast 
     | 
|
| 
       125 
128 
     | 
    
         
             
                            index = SPLIT_TRACKER.get(:split_index)&.fetch(depth)
         
     | 
| 
       126 
129 
     | 
    
         
             
                            return unless index
         
     | 
| 
       127 
130 
     | 
    
         | 
| 
      
 131 
     | 
    
         
            +
                            properties = Contrast::Agent::Assess::Tracker.properties(target)
         
     | 
| 
      
 132 
     | 
    
         
            +
                            return unless properties
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
       128 
134 
     | 
    
         
             
                            true_source = source[index]
         
     | 
| 
       129 
     | 
    
         
            -
                             
     | 
| 
      
 135 
     | 
    
         
            +
                            properties.copy_from(true_source, target)
         
     | 
| 
       130 
136 
     | 
    
         
             
                          rescue StandardError => e
         
     | 
| 
       131 
137 
     | 
    
         
             
                            logger.warn('Unable to track within split context', e)
         
     | 
| 
       132 
138 
     | 
    
         
             
                          ensure
         
     |