# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/components/logger' module Contrast module Utils module Assess # EventLimitUtils is used to check and validate the number of source, propagation, or trigger events collected # during the reporting time frame module EventLimitUtils include Contrast::Components::Logger::InstanceMethods # Checks to see if the event limit for the policy type has been met or exceeded # @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] method to check for event limit def event_limit? method_policy return false unless (context = Contrast::Agent::REQUEST_TRACKER.current) if method_policy.source_node max = (::Contrast::ASSESS.max_source_events || Contrast::Config::AssessConfiguration::DEFAULT_MAX_SOURCE_EVENTS) return at_limit?(method_policy, context.source_event_count, max) end if method_policy.propagation_node max = (::Contrast::ASSESS.max_propagation_events || Contrast::Config::AssessConfiguration::DEFAULT_MAX_PROPAGATION_EVENTS) return at_limit?(method_policy, context.propagation_event_count, max) end false # policy does not have limit end def event_limit_for_rule? rule_id if Contrast::Utils::Timer.now_ms > threshold_time_limit @_rule_counts = nil @_threshold_time_limit = nil threshold_time_limit end rule_counts[rule_id] += 1 # TODO: RUBY-1680 remove default rule_counts[rule_id] >= (::Contrast::ASSESS.max_rule_reported || Contrast::Config::AssessConfiguration::DEFAULT_MAX_RULE_REPORTED) end # Increments the event count for the type of event that is being tracked # # @param node [Contrast::Agent::Assess::Policy::PolicyNode] policy to increment def increment_event_count node return unless (context = Contrast::Agent::REQUEST_TRACKER.current) context.source_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::SourceNode) context.propagation_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::PropagationNode) end private # helper method to check limit and log when necessary def at_limit? method_policy, current_count, event_max if current_count == event_max logger.warn('Event Limit Reached:', { count: current_count, max: event_max, policy: method_policy.method_name, node: method_policy }) # increment to be over count for logging purposes increment_event_count(method_policy) return true elsif current_count > event_max # increment to be over count for logging purposes increment_event_count(method_policy) logger.warn('Event Limit Exceeded:', { count: current_count, policy: method_policy.method_name, node: method_policy }) return true end false end def rule_counts @_rule_counts ||= Hash.new { |h, k| h[k] = 0 } end # the time threshold for which to track rule counts resets when now >= threshold_time_limit # @return [Integer] def threshold_time_limit @_threshold_time_limit ||= Contrast::Utils::Timer.now_ms + (::Contrast::ASSESS.time_limit_threshold || 0) end end end end end