# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Config # Common Configuration settings. Those in this section pertain to the # specific settings that apply to Ruby class RubyConfiguration < BaseConfiguration DISABLED_RAKE_TASK_LIST = %w[ about assets:clean assets:clobber assets:environment assets:precompile assets:precompile:all db:create db:drop db:fixtures:load db:migrate db:migrate:status db:rollback db:schema:cache:clear db:schema:cache:dump db:schema:dump db:schema:load db:seed db:setup db:structure:dump db:version doc:app graphql:install graphql:object log:clear middleware notes notes:custom rails:template rails:update routes secret spec spec:features spec:requests spec:controllers spec:helpers spec:models spec:views spec:routing spec:rcov stats test test:all test:all:db test:recent test:single test:uncommitted time:zones:all tmp:clear tmp:create webpacker:compile contrast:service:start contrast:service:status contrast:service:stop ].cs__freeze DEFAULT_UNINSTRUMENTED_NAMESPACES = %w[FactoryGirl FactoryBot].cs__freeze attr_writer :disabled_agent_rake_tasks, :exceptions, :interpolate, :propagate_yield, :require_scan, :track_frozen_sources, :non_request_tracking, :uninstrument_namespace def initialize hsh = {} @disabled_agent_rake_tasks = traverse_config(hsh, :disabled_agent_rake_tasks) @exceptions = Contrast::Config::ExceptionConfiguration.new(traverse_config(hsh, :exceptions)) @interpolate = traverse_config(hsh, :interpolate) @propagate_yield = traverse_config(hsh, :propagate_yield) @require_scan = traverse_config(hsh, :require_scan) @track_frozen_sources = traverse_config(hsh, :track_frozen_sources) @non_request_tracking = traverse_config(hsh, :non_request_tracking) @uninstrument_namespace = traverse_config(hsh, :uninstrument_namespace) @configuration_map = {} build_configuration_map end # These commands being detected will result the agent disabling instrumentation, generally any command # that doesn't result in the application listening on a port can be added here, this normally includes tasks # that are ran pre-startup(like migrations) or to show information about the application(such as routes) # @return [Array, DISABLED_RAKE_TASK_LIST] def disabled_agent_rake_tasks @disabled_agent_rake_tasks.nil? ? DISABLED_RAKE_TASK_LIST : @disabled_agent_rake_tasks end # @return [Contrast::Config::ExceptionConfiguration] def exceptions @exceptions ||= Contrast::Config::ExceptionConfiguration.new end # controls whether or not we patch interpolation, either by rewrite or by funchook # @return [Boolean, Contrast::Utils::ObjectShare::TRUE] def interpolate @interpolate.nil? ? Contrast::Utils::ObjectShare::TRUE : @interpolate end # controls whether or not we patch the rb_yield block to track split propagation # @return [Boolean, Contrast::Utils::ObjectShare::TRUE] def propagate_yield @propagate_yield.nil? ? Contrast::Utils::ObjectShare::TRUE : @propagate_yield end # control whether or not we run file scanning rules on require # @return [Boolean, Contrast::Utils::ObjectShare::TRUE] def require_scan @require_scan.nil? ? Contrast::Utils::ObjectShare::TRUE : @require_scan end # controls whether or not we track frozen Strings by replacing them # @return [Boolean, Contrast::Utils::ObjectShare::TRUE] def track_frozen_sources @track_frozen_sources.nil? ? Contrast::Utils::ObjectShare::TRUE : @track_frozen_sources end # controls tracking outside of request # @return [Boolean, Contrast::Utils::ObjectShare::FALSE] def non_request_tracking @non_request_tracking.nil? ? Contrast::Utils::ObjectShare::FALSE : @non_request_tracking end # @return [Array, DEFAULT_UNINSTRUMENTED_NAMESPACES] def uninstrument_namespace @uninstrument_namespace.nil? ? DEFAULT_UNINSTRUMENTED_NAMESPACES : @uninstrument_namespace end # TODO: RUBY-1493 MOVE TO BASE CONFIG def []= key, value instance_variable_set("@#{ key }".to_sym, value) @configuration_map[key] = value end def [] key send(key.to_sym) end # Traverse the given entity to build out the configuration graph. # # The values will be either a hash, indicating internal nodes to # traverse, or a value to set or the EMPTY_VALUE symbol, indicating a # leaf node. # # The spec_key are the Contrast defined keys based on the instance variables of # a given configuration. def traverse_config values, spec_key internal_nodes = values.cs__respond_to?(:has_key?) val = internal_nodes ? value_from_key_config(spec_key, values) : nil val == EMPTY_VALUE ? nil : val end def build_configuration_map instance_variables.each do |key| str_key = key.to_s.tr('@', '') next if str_key == 'configuration_map' @configuration_map[str_key] = send(str_key.to_sym) end end end end end