lib/contrast/agent/assess/rule/provider/hardcoded_key.rb in contrast-agent-3.15.0 vs lib/contrast/agent/assess/rule/provider/hardcoded_key.rb in contrast-agent-3.16.0
- old
+ new
@@ -31,10 +31,68 @@
def name_passes? constant_string
KEY_FIELD_NAMES.any? { |name| constant_string.index(name) } &&
NON_KEY_PARTIAL_NAMES.none? { |name| constant_string.index(name) }
end
+ BYTE_HOLDERS = %i[ARRAY LIST].cs__freeze
+ # Determine if the given value node violates the hardcode key rule
+ # @param value_node [RubyVM::AbstractSyntaxTree::Node] the node to
+ # evaluate
+ # @return [Boolean]
+ def value_node_passes? value_node
+ # If it's a freeze call, then evaluate the entity being frozen
+ value_node = value_node.children[0] if freeze_call?(value_node)
+ # If it's a String being turned into bytes, then it matches key
+ # expectations
+ return true if bytes_call?(value_node)
+
+ type = value_node.type
+ return false unless BYTE_HOLDERS.include?(type)
+ return false unless value_node.children.any?
+
+ # Unless this is an array of literal numerics, we don't match.
+ # That array seems to always end in a nil value, so we allow
+ # those as well.
+ value_node.children.each do |child|
+ next unless child
+
+ return false unless child.cs__is_a?(RubyVM::AbstractSyntaxTree::Node) &&
+ child.type == :LIT &&
+ child.children[0]&.cs__is_a?(Integer)
+ end
+
+ true
+ end
+
+ REDACTED_MARKER = ' = [**REDACTED**]'
+ def redacted_marker
+ REDACTED_MARKER
+ end
+
+ # A node is a bytes_call if it's the Node for String#bytes. We care
+ # about this specifically as it's likely to be a common way to
+ # generate a key constant, rather than directly declaring an
+ # integer array.
+ #
+ # @param value_node [RubyVM::AbstractSyntaxTree::Node] the node to
+ # evaluate
+ # @return [Boolean] is this a node for String#bytes or not
+ def bytes_call? value_node
+ return false unless value_node.type == :CALL
+
+ children = value_node.children
+ return false unless children
+ return false unless children.length >= 2
+
+ potential_string_node = children[0]
+ return false unless potential_string_node.cs__is_a?(RubyVM::AbstractSyntaxTree::Node) &&
+ potential_string_node.type == :STR
+
+ children[1] == :bytes
+ end
+
+ # TODO: RUBY-1014 remove `#value_type_passes?` and `#value_passes?`
# If the value is a byte array, or at least an array of numbers, it
# passes for this rule
def value_type_passes? value
return false unless value.is_a?(Array) && value.any?
@@ -46,14 +104,9 @@
# There isn't a filter for the byte value. The check is not evaluated
# for this rule
def value_passes? _value
true
- end
-
- REDACTED_MARKER = ' = [**REDACTED**]'
- def redacted_marker
- REDACTED_MARKER
end
end
end
end
end