lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb in contrast-agent-6.6.5 vs lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb in contrast-agent-6.7.0
- old
+ new
@@ -9,37 +9,34 @@
module Contrast
module Agent
module Assess
module Rule
module Provider
- # Hardcoded rules detect if any secret value has been written
- # directly into the sourcecode of the application. To use this base
- # class, a provider must implement three methods:
+ # Hardcoded rules detect if any secret value has been written directly into the sourcecode of the
+ # application. To use this base class, a provider must implement three methods:
# 1) name_passes? : does the constant name match a given value set
# 2) value_node_passes? : does the value of the constant match a
# given value set
# 3) redacted_marker : the value to plug in for the obfuscated value
module HardcodedValueRule
include Contrast::Components::Logger::InstanceMethods
+ # @return [Boolean]
def disabled?
!::Contrast::ASSESS.enabled? || ::Contrast::ASSESS.rule_disabled?(rule_id)
end
- # Parse the file pertaining to the given TracePoint to walk its AST
- # to determine if a Constant is hardcoded. For our purposes, this
- # hard coding means directly set rather than as an interpolated
- # String or through a method call.
+ # Parse the file pertaining to the given TracePoint to walk its AST to determine if a Constant is
+ # hardcoded. For our purposes, this hard coding means directly set rather than as an interpolated String or
+ # through a method call.
#
- # Note: This is a top layer check, we make no assertions about what
- # the methods or interpolations do. Their presence, even if only
- # calling a hardcoded thing, causes this check to not report.
+ # Note: This is a top layer check, we make no assertions about what the methods or interpolations do.
+ # Their presence, even if only calling a hardcoded thing, causes this check to not report.
#
- # @param trace_point [TracePoint] the TracePoint event created on
- # the :end of a Module being loaded
- # @param ast [RubyVM::AbstractSyntaxTree::Node] the abstract syntax
- # tree of the Module defined in the TracePoint end event
+ # @param trace_point [TracePoint] the TracePoint event created on the :end of a Module being loaded
+ # @param ast [RubyVM::AbstractSyntaxTree::Node] the abstract syntax tree of the Module defined in the
+ # TracePoint end event
def parse trace_point, ast
return if disabled?
parse_ast(trace_point.self, ast)
rescue StandardError => e
@@ -54,12 +51,12 @@
SOURCE_KEY = 'source'
private
# @param mod [Module] the module to which this AST pertains
- # @param ast [RubyVM::AbstractSyntaxTree::Node, Object] a node
- # within the AST, which may be a leaf, so any Object
+ # @param ast [RubyVM::AbstractSyntaxTree::Node, Object] a node within the AST, which may be a leaf, so any
+ # Object
def parse_ast mod, ast
return unless ast.cs__is_a?(RubyVM::AbstractSyntaxTree::Node)
return unless ast.cs__respond_to?(:children)
children = ast.children
@@ -70,36 +67,31 @@
end
# https://www.rubydoc.info/gems/ruby-internal/Node/CDECL
return unless ast.type == :CDECL
- # The CDECL Node has two children, the first being the Constant
- # name as a symbol, the second as the value to assign to that
- # constant
+ # The CDECL Node has two children, the first being the Constant name as a symbol, the second as the value
+ # to assign to that constant
children = ast.children
name = children[0].to_s
# If that constant name doesn't pass our checks, move on.
return unless name_passes?(name)
value = children[1]
- # The assignment node could be a direct value or a call of some
- # sort. We leave it to each rule to properly handle these nodes.
+ # The assignment node could be a direct value or a call of some sort. We leave it to each rule to
+ # properly handle these nodes.
return unless value_node_passes?(value)
- if Contrast::Agent::Reporter.enabled?
- new_finding_and_reporting(mod, name)
- else # TODO: RUBY-1438 -- remove
- build_finding(mod, name)
- end
+ build_and_report(mod, name)
+ rescue StandardError => e
+ logger.error('Unable to parse AST for Hardcoded Rule analysis.', e)
end
- # Constants can be set as frozen directly. We need to account for
- # this change as it means the Node given to the :CDECL call will be
- # a :CALL, not a constant.
+ # Constants can be set as frozen directly. We need to account for this change as it means the Node given to
+ # the :CDECL call will be a :CALL, not a constant.
#
- # @param value_node [RubyVM::AbstractSyntaxTree::Node] the node to
- # evaluate
+ # @param value_node [RubyVM::AbstractSyntaxTree::Node] the node to evaluate
# @return [Boolean] is this a freeze call or not
def freeze_call? value_node
return false unless value_node.type == :CALL
children = value_node.children
@@ -107,66 +99,32 @@
return false unless children.length >= 2
children[1] == :freeze
end
- def build_finding clazz, constant_string
- class_name = clazz.cs__name
+ # @param mod [Module] the module to which this AST pertains
+ # @param name [String] the name of the hardcoded constant
+ def build_and_report mod, name
+ finding = build_finding(mod, name)
+ return unless finding
- finding = assign_finding(class_name, constant_string)
- # TODO: RUBY-1705
- # The only place we still use dtm activity
- activity = Contrast::Api::Dtm::Activity.new
- activity.findings << finding
- Contrast::Agent.messaging_queue.send_event_eventually(activity, force: true)
- rescue StandardError => e
- logger.error('Unable to build a finding for Hardcoded Rule', e)
- nil
- end
+ preflight = Contrast::Agent::Reporting::BuildPreflight.generate(finding)
+ return unless preflight
- # @param class_name [String] the name of the class in which the hardcoded value is present
- # @param constant_string [String] the name of the constant
- # @return [Contrast::Api::Dtm::Finding]
- def assign_finding class_name, constant_string
- finding = Contrast::Api::Dtm::Finding.new
- finding.rule_id = Contrast::Utils::StringUtils.protobuf_safe_string(rule_id)
- finding.version = Contrast::Agent::Assess::Policy::TriggerMethod::CURRENT_FINDING_VERSION
-
- finding.properties[SOURCE_KEY] = Contrast::Utils::StringUtils.protobuf_safe_string(class_name)
- finding.properties[CONSTANT_NAME_KEY] = Contrast::Utils::StringUtils.protobuf_safe_string(constant_string)
- finding.properties[CODE_SOURCE_KEY] =
- Contrast::Utils::StringUtils.protobuf_safe_string(constant_string + redacted_marker)
-
- hash = Contrast::Utils::HashDigest.generate_class_scanning_hash(finding)
- finding.hash_code = Contrast::Utils::StringUtils.protobuf_safe_string(hash)
- finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
- finding
+ Contrast::Agent::Reporting::ReportingStorage[preflight.messages[0].data] = finding
+ Contrast::Agent.reporter&.send_event(preflight)
end
- def new_finding_and_reporting clazz, constant_string
- return unless Contrast::Agent::Reporter.enabled?
-
- # sent to reporter
- # and add logger message for the report of the preflight
- new_preflight = Contrast::Agent::Reporting::Preflight.new
- new_preflight_message = Contrast::Agent::Reporting::PreflightMessage.new
- new_preflight_message.hash_code = hash
- new_preflight_message.data = "#{ rule_id },#{ hash }"
- new_preflight.messages << new_preflight_message
-
- # extract to new method
- # here we will generate new type of finding
- ruby_finding = Contrast::Agent::Reporting::Finding.new(rule_id)
- ruby_finding.hash_code = hash
- ruby_finding.properties[SOURCE_KEY] = clazz.cs__name
- ruby_finding.properties[CONSTANT_NAME_KEY] = constant_string
- ruby_finding.properties[CODE_SOURCE_KEY] = constant_string + redacted_marker
- save_and_report_finding(ruby_finding, new_preflight)
- end
-
- def save_and_report_finding ruby_finding, new_preflight
- Contrast::Agent::Reporting::ReportingStorage[hash] = ruby_finding
- Contrast::Agent.reporter&.send_event(new_preflight)
+ # @param clazz [Class] the Class or Module containing the constant
+ # @param constant_string [String]
+ # @return [Contrast::Agent::Reporting::Finding]
+ def build_finding clazz, constant_string
+ finding = Contrast::Agent::Reporting::Finding.new(rule_id)
+ finding.properties[SOURCE_KEY] = clazz.cs__name
+ finding.properties[CONSTANT_NAME_KEY] = constant_string
+ finding.properties[CODE_SOURCE_KEY] = constant_string + redacted_marker
+ finding.hash_code = Contrast::Utils::HashDigest.generate_class_scanning_hash(finding)
+ finding
end
end
end
end
end