contrast-agent 7.5.0 → 7.6.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__common/cs__common.c +5 -5
  3. data/ext/cs__contrast_patch/cs__contrast_patch.c +2 -1
  4. data/ext/cs__scope/cs__scope.c +6 -5
  5. data/lib/contrast/agent/assess/events/event_data.rb +11 -2
  6. data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -0
  7. data/lib/contrast/agent/assess/finalizers/hash.rb +7 -0
  8. data/lib/contrast/agent/assess/policy/patcher.rb +2 -0
  9. data/lib/contrast/agent/assess/policy/policy.rb +4 -0
  10. data/lib/contrast/agent/assess/policy/policy_node.rb +29 -7
  11. data/lib/contrast/agent/assess/policy/preshift.rb +34 -1
  12. data/lib/contrast/agent/assess/policy/propagation_method.rb +16 -1
  13. data/lib/contrast/agent/assess/policy/propagation_node.rb +40 -1
  14. data/lib/contrast/agent/assess/policy/propagator/append.rb +5 -0
  15. data/lib/contrast/agent/assess/policy/propagator/base.rb +10 -0
  16. data/lib/contrast/agent/assess/policy/propagator/buffer.rb +6 -0
  17. data/lib/contrast/agent/assess/policy/propagator/center.rb +14 -0
  18. data/lib/contrast/agent/assess/policy/propagator/custom.rb +6 -0
  19. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +14 -0
  20. data/lib/contrast/agent/assess/policy/propagator/insert.rb +6 -0
  21. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +38 -0
  22. data/lib/contrast/agent/assess/policy/propagator/next.rb +6 -0
  23. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +5 -0
  24. data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -0
  25. data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -0
  26. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +5 -0
  27. data/lib/contrast/agent/assess/policy/propagator/select.rb +30 -0
  28. data/lib/contrast/agent/assess/policy/propagator/splat.rb +10 -0
  29. data/lib/contrast/agent/assess/policy/source_node.rb +5 -1
  30. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +4 -0
  31. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -0
  32. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +19 -0
  33. data/lib/contrast/agent/assess/policy/trigger_method.rb +8 -1
  34. data/lib/contrast/agent/assess/policy/trigger_node.rb +11 -1
  35. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +4 -0
  36. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +6 -0
  37. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +6 -0
  38. data/lib/contrast/agent/hooks/at_exit_hook.rb +1 -0
  39. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
  40. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
  41. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -1
  42. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +3 -3
  43. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +18 -6
  44. data/lib/contrast/agent/request/request_handler.rb +1 -0
  45. data/lib/contrast/agent/version.rb +1 -1
  46. data/lib/contrast/configuration.rb +1 -1
  47. data/lib/contrast/utils/middleware_utils.rb +9 -0
  48. data/lib/contrast/utils/routes_sent.rb +3 -2
  49. data/lib/contrast.rb +2 -2
  50. data/resources/assess/policy.json +50 -1
  51. data/ruby-agent.gemspec +13 -13
  52. metadata +23 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6b34ada48cf9e91e05d85ea0f003575119b751bf135ef49709fb1501c475b3e
4
- data.tar.gz: 2915fb037c832fec213dfc7835b8d732e1c22005987ef2c4287dfb55264d41a2
3
+ metadata.gz: '089a689fce3dfbc204455c12d29788d316553aa3ff6738fcf515e9f90730a7ae'
4
+ data.tar.gz: 5fc2d10ffc084070fc3c268a9cb05d1f479b48cb16974b2501887cb1b762d6f6
5
5
  SHA512:
6
- metadata.gz: 627d1959c5993100f6bc08624d1a68627b02af18f6aa48c074f0cf374925877761b09077ce21366b6d5ddafb3185907472564753b3fbab65f6f7d74d2b74dc10
7
- data.tar.gz: 224228b9e9c276c39e6d78a330a456b37cf550b4155c4b96f5ff1d29e7bf7846521c102f510061f8d6ec5e9245b99fe567cce7a5202dd2acfd62c6e7bb9ca795
6
+ metadata.gz: d13b3205d1e0cb67c8974fdf6d12f78e5a95f2886c59a14439ddc59b9dd8a3b0d0ebd23c5ebfe687d02cf1a12c9b17b127d821ea8131f0876ab284dac62c8b1b
7
+ data.tar.gz: 73932d309fafe50ab5bc962655b58306cd5fae6a64729be1a4159274fe39c55c2138027c30525d07f773966476991685ba9b36cd0820527557d417324225af0d
@@ -28,12 +28,12 @@ void patch_via_funchook(void *original_function, void *hook_function) {
28
28
 
29
29
  void *funchook_lib_handle;
30
30
  void *funchook_reference, *(*funchook_create)(void);
31
- /* This variables are used to load the funchook dylib */
32
- #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
33
- #pragma GCC diagnostic push
31
+ /* This variables are used to load the funchook dylib */
32
+ #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
33
+ #pragma GCC diagnostic push
34
34
  int prepareResult, (*funchook_prepare)(void *, void **, void *);
35
35
  int installResult, (*funchook_install)(void *, int);
36
- #pragma GCC diagnostic pop
36
+ #pragma GCC diagnostic pop
37
37
 
38
38
  funchook_lib_handle =
39
39
  dlopen(StringValueCStr(funchook_path), RTLD_NOW | RTLD_GLOBAL);
@@ -198,7 +198,7 @@ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
198
198
  }
199
199
 
200
200
  VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
201
- VALUE is_instance) {
201
+ VALUE is_instance) {
202
202
  VALUE entry, ancestors, entry_methods;
203
203
  VALUE result = Qfalse;
204
204
  VALUE object_idx = Qnil;
@@ -107,7 +107,8 @@ VALUE rescue_func(VALUE arg1) {
107
107
  *
108
108
  **/
109
109
  VALUE contrast_patch_call_ensure(const VALUE *args) {
110
- /* we do not need to ensure that post patch is called if no error was thrown */
110
+ /* we do not need to ensure that post patch is called if no error was thrown
111
+ */
111
112
  if (!RTEST(rb_errinfo())) {
112
113
  return Qnil;
113
114
  }
@@ -3,9 +3,9 @@
3
3
 
4
4
  #include "cs__scope.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include <pthread.h>
6
7
  #include <ruby.h>
7
8
  #include <stdlib.h>
8
- #include <pthread.h>
9
9
 
10
10
  /*-----------------------------------------
11
11
  | Calls to Contrast modules and classes
@@ -161,8 +161,8 @@ VALUE contrast_scope_application_update() {
161
161
  return INT2FIX(env_var_set(eVar));
162
162
  }
163
163
 
164
- /**
165
- * @brief Determines if the Contrast Scope should be set with the Trap Context.
164
+ /**
165
+ * @brief Determines if the Contrast Scope should be set with the Trap Context.
166
166
  * @return 1 if set, 0 if not set.
167
167
  */
168
168
  int contrast_scope_with_trap_context() {
@@ -556,7 +556,7 @@ VALUE contrast_scope_for_current_ec(VALUE self, VALUE args) {
556
556
  * different thread, at once, but since the mutex stays in
557
557
  * the C API context, this might work fine. Still use only
558
558
  * when unusual conditions are met.
559
- *
559
+ *
560
560
  * In addition we could use C mutex lock just in case. Ruby
561
561
  * Threads under the hood are C threads (pthread), so they
562
562
  * should be treated as such. In theory only one thread can
@@ -894,7 +894,8 @@ void Init_cs__scope() {
894
894
  rb_const_ec = "EXECUTION_CONTEXT";
895
895
  rb_const_ec_keys = "EC_KEYS";
896
896
  c_const_ctr_agent_app_scope = "CONTRAST__AGENT__RUBY__APPLICATION_SCOPE";
897
- c_const_ctr_agent_scope_trap_context = "CONTRAST__AGENT__SCOPE__WITH_TRAP_CONTEXT";
897
+ c_const_ctr_agent_scope_trap_context =
898
+ "CONTRAST__AGENT__SCOPE__WITH_TRAP_CONTEXT";
898
899
 
899
900
  /* Symbols */
900
901
  rb_sym_scope_mod = rb_intern("Scope");
@@ -5,9 +5,18 @@ module Contrast
5
5
  module Agent
6
6
  module Assess
7
7
  module Events
8
- # this class will gather and build event
8
+ # this class will gather and build event.
9
9
  class EventData
10
- attr_reader :policy_node, :tagged, :object, :ret, :args
10
+ # @return [Contrast::Agent::Assess::Policy::PolicyNode, nil] the node that governs this event.
11
+ attr_reader :policy_node
12
+ # @return [Object, nil] the Target to which this event pertains.
13
+ attr_reader :tagged
14
+ # @return [Object, nil] the Object on which the method was invoked.
15
+ attr_reader :object
16
+ # @return [Object, nil] the Return of the invoked method.
17
+ attr_reader :ret
18
+ # @return [Array<Object>, nil] the Arguments with which the method was invoked.
19
+ attr_reader :args
11
20
 
12
21
  # Group event data together
13
22
  #
@@ -8,6 +8,7 @@ require 'contrast/agent/assess/tracker'
8
8
  class Object
9
9
  alias_method :cs__patched_object_freeze, :freeze
10
10
 
11
+ # Applies the the freeze patch and handles the pre-finalizes the object.
11
12
  def freeze
12
13
  Contrast::Agent::Assess::Tracker.pre_freeze(self)
13
14
  cs__patched_object_freeze
@@ -16,6 +16,10 @@ module Contrast
16
16
  FROZEN_FINALIZED_IDS = Set.new
17
17
  KEEP_AGE = 600_000.cs__freeze # 10 minutes
18
18
 
19
+ # Store the given Object in the Hash, using its __id__ as the key. If the Object is frozen, we need to
20
+ # pre-finalize it and store its __id__ in our tracking Set.
21
+ #
22
+ # @return [Object] the Object stored
19
23
  def []= key, obj
20
24
  return unless obj
21
25
  return unless ::Contrast::AGENT.enabled? && ::Contrast::ASSESS.enabled?
@@ -29,6 +33,9 @@ module Contrast
29
33
  super(key.__id__, obj)
30
34
  end
31
35
 
36
+ # Retrieves the Object stored in the Hash by its __id__.
37
+ #
38
+ # @return [Object, nil] the Object stored.
32
39
  def [] key
33
40
  super(key.__id__)
34
41
  end
@@ -34,6 +34,8 @@ module Contrast
34
34
  # load. These methods only exist once a module or class eval has been
35
35
  # called. This hook is provided so that patches to those methods can
36
36
  # pass us execution flow once a new method has been made available.
37
+ #
38
+ # @param mod [Module]
37
39
  def patch_assess_on_eval mod
38
40
  return unless ::Contrast::ASSESS.enabled?
39
41
  return if in_contrast_scope?
@@ -34,6 +34,8 @@ module Contrast
34
34
 
35
35
  # Indicates is this feature has been disabled by the configuration,
36
36
  # read at startup, and therefore can never be enabled.
37
+ #
38
+ # @return [Boolean] if this feature is disabled
37
39
  def disabled_globally?
38
40
  ::Contrast::ASSESS.forcibly_disabled?
39
41
  end
@@ -49,6 +51,8 @@ module Contrast
49
51
  # This let's us be flexible and extensible
50
52
  # * when we want to do lvl 2 rules, we could have the customers unzip
51
53
  # our gem, insert things into the json, zip, and go *
54
+ #
55
+ # @param string [String]
52
56
  def from_hash_string string
53
57
  # The default behavior of the agent is to load the policy on startup,
54
58
  # as at this point we do not know in which mode we'll be run.
@@ -26,8 +26,17 @@ module Contrast
26
26
  JSON_TARGET = 'target'
27
27
  TO_MARKER = '2'
28
28
 
29
- attr_accessor :tags, :type
30
- attr_reader :sources, :targets, :source_string, :target_string
29
+ # @return [Set<String>]
30
+ attr_accessor :tags
31
+ # @return [Symbol]
32
+ attr_accessor :type
33
+ attr_reader :sources
34
+ # @return [Array<String>]
35
+ attr_reader :targets
36
+ # @return [String]
37
+ attr_reader :source_string
38
+ # @return [String]
39
+ attr_reader :target_string
31
40
 
32
41
  # Here are all methods that can use original objects without mutation the source.
33
42
  # For methods with REMOVE action, their (!) bang alternative is not listed, since
@@ -68,6 +77,8 @@ module Contrast
68
77
  # String#to_s => self or string. This method is included here to cover the situations such as
69
78
  # String.to_s.html_safe, where normally the dynamic sources properties get lost. To solve this
70
79
  # we will simply return the original object here.
80
+ #
81
+ # @param policy_hash [Hash]
71
82
  def assign_on_bang_check policy_hash
72
83
  return true if @_use_original_object && TO_S.include?(policy_hash[JSON_METHOD_NAME])
73
84
 
@@ -76,18 +87,24 @@ module Contrast
76
87
  policy_hash[JSON_METHOD_NAME].end_with?(Contrast::Utils::ObjectShare::BANG)
77
88
  end
78
89
 
90
+ # @return [String]
79
91
  def feature
80
92
  'Assess'
81
93
  end
82
94
 
95
+ # @return [String]
83
96
  def node_class
84
97
  'Node'
85
98
  end
86
99
 
100
+ # @return [Symbol]
87
101
  def node_type
88
102
  :TYPE_METHOD
89
103
  end
90
104
 
105
+ # Set the target string.
106
+ #
107
+ # @param value [String]
91
108
  def target_string= value
92
109
  @target_string = value
93
110
  @targets = convert_policy_markers(value)
@@ -96,6 +113,9 @@ module Contrast
96
113
  # Sometimes we need to tie information to an event. We'll add a
97
114
  # properties section to the patch node, which can pass them along to
98
115
  # the pre-dtm event
116
+ #
117
+ # @param name [String]
118
+ # @param value [String]
99
119
  def add_property name, value
100
120
  return unless name && value
101
121
 
@@ -103,6 +123,8 @@ module Contrast
103
123
  @properties[name] = value
104
124
  end
105
125
 
126
+ # @param name [String]
127
+ # @return [String]
106
128
  def get_property name
107
129
  return unless @properties
108
130
 
@@ -112,6 +134,8 @@ module Contrast
112
134
  # Don't let nodes be created that will be missing things we need
113
135
  # later on. Really, if they don't have these things, they couldn't have
114
136
  # done their jobs anyway.
137
+ #
138
+ # @raise [ArgumentError] raises if the node is invalid.
115
139
  def validate
116
140
  super
117
141
  validate_tags
@@ -124,11 +148,10 @@ module Contrast
124
148
  # isn't a matching ENUM in TS land, the database gets got. We really
125
149
  # don't want to get them, so we're going to prevent the node from being
126
150
  # made.
151
+ #
127
152
  # @raise[ArgumentError] raises if any of the tags is invalid
128
153
  def validate_tags
129
- return unless tags
130
-
131
- tags.each do |tag|
154
+ tags&.each do |tag|
132
155
  next if Contrast::Agent::Reporting::FindingEventTaintRangeTags::VALID_TAGS.include?(tag) ||
133
156
  Contrast::Agent::Reporting::FindingEventTaintRangeTags::VALID_SOURCE_TAGS.include?(tag)
134
157
 
@@ -159,8 +182,7 @@ module Contrast
159
182
  # by changing them to 'A'
160
183
  source = all_type?(source_string) ? ALL_TYPE : source_string
161
184
  target = all_type?(target_string) ? ALL_TYPE : target_string
162
- str = source[0] + TO_MARKER + target[0]
163
- str.to_sym
185
+ (source[0] + TO_MARKER + target[0]).to_sym
164
186
  end
165
187
  end
166
188
 
@@ -21,7 +21,15 @@ module Contrast
21
21
  UNDUPLICABLE_MODULES << IO::Buffer if RUBY_VERSION >= '3.1.0'
22
22
  UNDUPLICABLE_MODULES.cs__freeze
23
23
 
24
- attr_accessor :object, :object_length, :args, :arg_lengths
24
+ # @return [Object] the object on which the method is to be called.
25
+ attr_accessor :object
26
+ # @return [Integer] the length of the object on which the method is to
27
+ # be called.
28
+ attr_accessor :object_length
29
+ # @return [Array<Object>] the arguments to be passed to the method.
30
+ attr_accessor :args
31
+ # @return [Array<Integer>] the lengths of the arguments to be passed to
32
+ attr_accessor :arg_lengths
25
33
 
26
34
  class << self
27
35
  # Save the state before we do the propagation. This is one of the
@@ -65,10 +73,23 @@ module Contrast
65
73
 
66
74
  private
67
75
 
76
+ # Determine if the given object is an IO object that is closed, not in
77
+ # initialization, and therefore unsafe to use.
78
+ #
79
+ # @param object [Object] the object on which the method is to be
80
+ # called.
81
+ # @param initializing [Boolean] whether or not the method being
82
+ # called is the initialize method.
68
83
  def unsafe_io_object? object, initializing
69
84
  Contrast::Utils::DuckUtils.closable_io?(object) && !initializing && object.closed?
70
85
  end
71
86
 
87
+ # check if object is duplicable
88
+ #
89
+ # @param initializing [Boolean] whether or not the method being
90
+ # called is the initialize method.
91
+ # @param object [Object] the object on which the method is to be
92
+ # called.
72
93
  def can_dup? initializing, object
73
94
  return false if initializing
74
95
 
@@ -76,6 +97,14 @@ module Contrast
76
97
  !UNDUPLICABLE_MODULES.include?(check)
77
98
  end
78
99
 
100
+ # Appends the object details to the given preshift and adds it to the LRU cache.
101
+ #
102
+ # @param preshift [Contrast::Agent::Assess::PreShift] the preshift to
103
+ # which the object details should be appended.
104
+ # @param initializing [Boolean] whether or not the method being
105
+ # called is the initialize method.
106
+ # @param object [Object] the object on which the method is to be
107
+ # called.
79
108
  def append_object_details preshift, initializing, object
80
109
  can = can_dup?(initializing, object)
81
110
  preshift.object = if @lru_cache.key?(object.__id__) && !Contrast::Agent::Assess::Tracker.tracked?(object)
@@ -97,6 +126,10 @@ module Contrast
97
126
  @lru_cache[object.__id__] = object
98
127
  end
99
128
 
129
+ # @param preshift [Contrast::Agent::Assess::PreShift] the preshift to
130
+ # which the argument details should be appended.
131
+ # @param args [Array<Object>] the arguments to be passed to the
132
+ # method.
100
133
  def append_arg_details preshift, args
101
134
  args_length = args.length
102
135
  preshift.args = Array.new(args_length)
@@ -88,6 +88,7 @@ module Contrast
88
88
  end
89
89
 
90
90
  # If this patcher has tags, apply them to the entire target
91
+ #
91
92
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
92
93
  # propagation event.
93
94
  # @param target [Object] the Target to which to propagate.
@@ -101,6 +102,9 @@ module Contrast
101
102
  end
102
103
  end
103
104
 
105
+ # Checks to see if the given target is valid for propagation.
106
+ #
107
+ # @return [Bool]
104
108
  def context_available?
105
109
  !!Contrast::Agent::REQUEST_TRACKER.current
106
110
  end
@@ -121,7 +125,8 @@ module Contrast
121
125
 
122
126
  private
123
127
 
124
- # This is checked right before actual propagation
128
+ # This is checked right before actual propagation.
129
+ #
125
130
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
126
131
  # propagation event.
127
132
  # @param target [Object] the Target to which to propagate.
@@ -198,6 +203,10 @@ module Contrast
198
203
  increment_event_count(propagation_node)
199
204
  end
200
205
 
206
+ # @param propagation_class [Contrast::Agent::Assess::Policy::Propagator]
207
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
208
+ # @param source [Object] The object from which the propagation begins.
209
+ # @param target [Object] the Target to which to propagate.
201
210
  def handle_propagation propagation_class, propagation_node, source, target
202
211
  if propagation_node.patch_method
203
212
  propagation_class.send(propagation_node.patch_method, propagation_node, source, target)
@@ -206,6 +215,12 @@ module Contrast
206
215
  end
207
216
  end
208
217
 
218
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
219
+ # @param target [Object] the Target to which to propagate.
220
+ # @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
221
+ # object [Object] the Object on which the method was invoked
222
+ # ret [Object] the Return of the invoked method
223
+ # args [Array<Object>] the Arguments with which the method was invoked
209
224
  def update_properties propagation_node, target, propagation_data
210
225
  if propagation_node.use_original_on_bang_method?
211
226
  properties = use_original_object_properties(propagation_data)
@@ -22,7 +22,34 @@ module Contrast
22
22
  JSON_PATCH_CLASS = 'patch_class'
23
23
  JSON_PATCH_METHOD = 'patch_method'
24
24
 
25
- attr_reader :action, :untags, :patch_method
25
+ # @return action [String] the action to be taken by this propagation
26
+ # node. This can be one of the following:
27
+ # - 'CUSTOM' - the propagation node is a custom propagation node
28
+ # - 'DB_WRITE' - the propagation node is a database write propagation
29
+ # node
30
+ # - 'APPEND' - the propagation node is an append propagation node
31
+ # - 'CENTER' - the propagation node is a center propagation node
32
+ # - 'INSERT' - the propagation node is an insert propagation node
33
+ # - 'KEEP' - the propagation node is a keep propagation node
34
+ # - 'NEXT' - the propagation node is a next propagation node
35
+ # - 'BUFFER' - the propagation node is a buffer propagation node
36
+ # - 'NOOP' - the propagation node is a noop propagation node
37
+ # - 'PREPEND' - the propagation node is a prepend propagation node
38
+ # - 'REPLACE' - the propagation node is a replace propagation node
39
+ # - 'REMOVE' - the propagation node is a remove propagation node
40
+ # - 'REVERSE' - the propagation node is a reverse propagation node
41
+ # - 'RESPONSE' - the propagation node is a response propagation node
42
+ # - 'SPLAT' - the propagation node is a splat propagation node
43
+ # - 'SPLIT' - the propagation node is a split propagation node
44
+ attr_reader :action
45
+ # @return untags [Array<String>] the tags to be removed from the
46
+ # target of this propagation node.
47
+ attr_reader :untags
48
+ # @return patch_class [String] the class name of the class that
49
+ # contains the method to be called for this propagation node.
50
+ attr_reader :patch_method
51
+ # @return patch_method [Symbol] the name of the method to be called
52
+ # for this propagation node.
26
53
  attr_accessor :patch_class
27
54
 
28
55
  TAGGER = 'Tagger'
@@ -36,6 +63,9 @@ module Contrast
36
63
  # Tags - array of tags to apply to the target, can be nil if no tags are added
37
64
  # Untags - array of tags to remove from the target, can be nil if not tags are removed
38
65
  # id, class_name, instance_method, method_name, source, target, action, tags = nil, untags = nil
66
+ #
67
+ # @param propagation_hash [Hash] the hash from which to build the
68
+ # propagation node.
39
69
  def initialize propagation_hash = {}
40
70
  super(propagation_hash)
41
71
  @action = propagation_hash[JSON_ACTION]
@@ -49,6 +79,7 @@ module Contrast
49
79
  nil
50
80
  end
51
81
 
82
+ # @return [String] class name
52
83
  def node_class
53
84
  @_node_class ||= tagger? ? TAGGER : PROPAGATOR
54
85
  end
@@ -56,12 +87,15 @@ module Contrast
56
87
  # Unlike the other agents, we don't have separate tag & propagation
57
88
  # events. To make TS happy, we need to have different types though.
58
89
  # Pretty straight forward: if there's a tag, this is a tagger
90
+ #
91
+ # @return [Symbol] the type of node.
59
92
  def node_type
60
93
  tagger? ? :TYPE_TAG : :TYPE_PROPAGATION
61
94
  end
62
95
 
63
96
  # Standard validation + TS trace version two rules:
64
97
  # Must have source, target, and action
98
+ #
65
99
  # @raise[ArgumentError] raises if any of the required propagation node field is not valid, or is missing
66
100
  def validate
67
101
  super
@@ -100,6 +134,8 @@ module Contrast
100
134
  end
101
135
  end
102
136
 
137
+ # @return [Boolean]
138
+ # propagation node.
103
139
  def needs_object?
104
140
  if @_needs_object.nil?
105
141
  @_needs_object = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
@@ -110,6 +146,7 @@ module Contrast
110
146
  @_needs_object
111
147
  end
112
148
 
149
+ # @return [Boolean]
113
150
  def needs_args?
114
151
  if @_needs_args.nil?
115
152
  @_needs_args = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
@@ -124,6 +161,8 @@ module Contrast
124
161
  # It indicates this method is more than just a transformation,
125
162
  # it is an interesting security event that has a meaningful
126
163
  # change.
164
+ #
165
+ # @return [Boolean]
127
166
  def tagger?
128
167
  @_tagger = tags&.any? || untags&.any? if @_tagger.nil?
129
168
  @_tagger
@@ -15,6 +15,11 @@ module Contrast
15
15
  # if the target length is greater than the source
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
+ #
19
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
20
+ # propagation action required by this method.
21
+ # @param preshift [Object] pre call state of the things.
22
+ # @param target [Object] the object to which the source is being appended
18
23
  def propagate propagation_node, preshift, target
19
24
  return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
20
25
 
@@ -12,6 +12,10 @@ module Contrast
12
12
  # to pass tags from it to a Target.
13
13
  class Base
14
14
  class << self
15
+ # Retrieve the source from the preshift state.
16
+ #
17
+ # @param source [Symbol] the source to retrieve.
18
+ # @param preshift [Contrast::Agent::Assess::PreShift] the pre-call state of the things.
15
19
  def find_source source, preshift
16
20
  case source
17
21
  when Contrast::Utils::ObjectShare::OBJECT_KEY
@@ -21,10 +25,16 @@ module Contrast
21
25
  end
22
26
  end
23
27
 
28
+ # Check if tags are present on the given target.
29
+ #
30
+ # @return [Boolean]
24
31
  def tracked_value? value
25
32
  Contrast::Agent::Assess::Tracker.tracked?(value)
26
33
  end
27
34
 
35
+ # Propagate the tags from the source to the target.
36
+ # This method should be extended by the subclasses.
37
+ #
28
38
  # @raise [NoMethodError] This is being raised if any of the implementing subclasses does not have
29
39
  # that method implemented, but is being called on.
30
40
  def propagate _propagation_node, _preshift, _target
@@ -17,6 +17,12 @@ module Contrast
17
17
  # Once the tag is applied, shift it to the location of the insert
18
18
  # Unlike additive propagation, this currently only supports one source
19
19
  # We assume that insert changes the preshift target
20
+ #
21
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
22
+ # propagation action required by this method.
23
+ # @param preshift [Object] pre call state of the things.
24
+ # @param target [Object] the object to which the source is being appended
25
+ # @return [Object] the target with the tags applied
20
26
  def propagate_insert propagation_node, preshift, target
21
27
  return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
22
28
 
@@ -11,6 +11,11 @@ module Contrast
11
11
  # are unaffected beyond any merging of overlapping tags.
12
12
  class Center < Contrast::Agent::Assess::Policy::Propagator::Base
13
13
  class << self
14
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
15
+ # propagation action required by this method.
16
+ # @param preshift [Object] pre call state of the things.
17
+ # @param target [Object] the object to which the source is being appended
18
+ # @return [Object] the target with the tags applied
14
19
  def propagate propagation_node, preshift, target
15
20
  return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
16
21
 
@@ -56,6 +61,15 @@ module Contrast
56
61
  iterate_tags(target, propagation_node, source, end_index, target.length)
57
62
  end
58
63
 
64
+ # This method will iterate over the tags of the source and apply
65
+ # them to the target.
66
+ #
67
+ # @param target [Object] the thing to apply tags to.
68
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
69
+ # the node that indicates how this propagation should be handled.
70
+ # @param source [Object] the thing to copy tags from.
71
+ # @param start [Integer] where to start copying tags from.
72
+ # @param stop [Integer] where to stop copying tags from.
59
73
  def iterate_tags target, propagation_node, source, start, stop
60
74
  properties = Contrast::Agent::Assess::Tracker.properties(target)
61
75
  while start < stop
@@ -17,6 +17,12 @@ module Contrast
17
17
  extend Contrast::Utils::Assess::EventLimitUtils
18
18
 
19
19
  class << self
20
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
21
+ # propagation action required by this method.
22
+ # @param preshift [Object] pre call state of the things.
23
+ # @param ret [Object] the return value of the method.
24
+ # @param block [Proc] the block passed to the method.
25
+ # @return [Object] the return value of the method.
20
26
  def propagate propagation_node, preshift, ret, block
21
27
  clazz = propagation_node.patch_class
22
28
  method = propagation_node.patch_method
@@ -16,6 +16,11 @@ module Contrast
16
16
  extend Contrast::Utils::Assess::EventLimitUtils
17
17
 
18
18
  class << self
19
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
20
+ # propagation action required by this method.
21
+ # @param preshift [Object] pre call state of the things.
22
+ # @param target [Object] the object to which the source is being appended
23
+ # @return [Object] the target with the tags applied
19
24
  def propagate propagation_node, preshift, target
20
25
  return unless Contrast::ASSESS.require_dynamic_sources?
21
26
 
@@ -41,6 +46,15 @@ module Contrast
41
46
 
42
47
  private
43
48
 
49
+ # Handles the write propagation for the given source.
50
+ #
51
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
52
+ # propagation action required by this method.
53
+ # @param source [Symbol] the source to retrieve.
54
+ # @param preshift [Contrast::Agent::Assess::PreShift] the pre-call state of the things.
55
+ # @param target [Object] the object to which the source is being appended
56
+ # @param known_tainted [Array] the list of known tainted columns
57
+ # @param tainted_columns [Hash] the hash of tainted columns
44
58
  def handle_write propagation_node, source, preshift, target, known_tainted, tainted_columns
45
59
  arg = preshift.args[source]
46
60
  return unless arg.cs__respond_to?(:each_pair)
@@ -15,6 +15,12 @@ module Contrast
15
15
  # Once the tag is applied, shift it to the location of the insert
16
16
  # Unlike additive propagation, this currently only supports one source
17
17
  # We assume that insert changes the preshift target
18
+ #
19
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
20
+ # propagation action required by this method.
21
+ # @param preshift [Object] pre call state of the things.
22
+ # @param target [Object] the object to which the source is being appended
23
+ # @return [Object] the target with the tags applied
18
24
  def propagate propagation_node, preshift, target
19
25
  return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
20
26