# frozen_string_literal: true # ProcessWafPoliciesJob - Process firewall policies for a network range # # This job checks network ranges against active WAF policies and generates # specific rules when matches are found. class ProcessWafPoliciesJob < ApplicationJob queue_as :waf_policies retry_on StandardError, wait: 5.seconds, attempts: 3 def perform(network_range_id:, event_id: nil) # Find the network range network_range = NetworkRange.find_by(id: network_range_id) return if network_range.nil? Rails.logger.debug "Processing WAF policies for network range #{network_range.cidr}" # Use WafPolicyMatcher to find and generate rules begin matcher = WafPolicyMatcher.new(network_range: network_range) result = matcher.match_and_generate_rules rescue => e Rails.logger.error "WafPolicyMatcher failed for network range #{network_range.cidr}: #{e.message}" result = { matching_policies: [], generated_rules: [] } end # Log results if result[:matching_policies].any? Rails.logger.info "Network range #{network_range.cidr} matched #{result[:matching_policies].length} policies" result[:matching_policies].each do |policy| Rails.logger.info " - Matched policy: #{policy.name} (#{policy.policy_type}: #{policy.action})" end end if result[:generated_rules].any? Rails.logger.info "Generated #{result[:generated_rules].length} rules for network range #{network_range.cidr}" result[:generated_rules].each do |rule| Rails.logger.info " - Rule: #{rule.rule_type} #{rule.action} for #{rule.network_range&.cidr} (ID: #{rule.id})" # Log if this is a redirect or challenge rule if rule.redirect_action? Rails.logger.info " Redirect to: #{rule.redirect_url} (#{rule.redirect_status})" elsif rule.challenge_action? Rails.logger.info " Challenge type: #{rule.challenge_type}" end end else Rails.logger.debug "No matching policies found for network range #{network_range.cidr}" end # Mark network range as evaluated network_range.update_column(:policies_evaluated_at, Time.current) # Update event record if provided if event_id.present? event = Event.find_by(id: event_id) if event.present? # Add policy match information to event metadata # Handle potential nil payload or type issues current_payload = event.payload || {} # Ensure payload is a hash before merging unless current_payload.is_a?(Hash) Rails.logger.warn "Event #{event_id} has invalid payload type: #{current_payload.class}, resetting to hash" current_payload = {} end event.update!(payload: current_payload.merge({ policy_matches: { matching_policies_count: result[:matching_policies].length, generated_rules_count: result[:generated_rules].length, processed_at: Time.current.iso8601 } })) else Rails.logger.warn "Event #{event_id} not found for ProcessWafPoliciesJob, skipping update" end end end # Class method for batch processing multiple network ranges def self.process_network_ranges(network_range_ids) network_range_ids.each do |network_range_id| perform_later(network_range_id: network_range_id) end end # Class method to reprocess all network ranges for a specific policy def self.reprocess_for_policy(waf_policy) waf_policy_id = waf_policy.is_a?(WafPolicy) ? waf_policy.id : waf_policy # Find all network ranges that could match this policy type network_ranges = case waf_policy.policy_type when 'country' NetworkRange.where.not(country: nil) when 'asn' NetworkRange.where.not(asn: nil) when 'company' NetworkRange.where.not(company: nil) when 'network_type' NetworkRange.where("is_datacenter = ? OR is_proxy = ? OR is_vpn = ?", true, true, true) else NetworkRange.none end Rails.logger.info "Reprocessing #{network_ranges.count} network ranges for policy #{waf_policy_id}" network_ranges.find_each do |network_range| perform_later(network_range_id: network_range.id) end end end