# frozen_string_literal: true class RuleSet < ApplicationRecord has_many :rules, dependent: :destroy validates :name, presence: true, uniqueness: true validates :slug, presence: true, uniqueness: true scope :enabled, -> { where(enabled: true) } scope :by_priority, -> { order(priority: :desc, created_at: :desc) } before_validation :generate_slug, if: :name? before_validation :set_default_values # Rule Types RULE_TYPES = %w[ip cidr path user_agent parameter method rate_limit country].freeze ACTIONS = %w[allow deny challenge rate_limit].freeze def to_waf_rules return [] unless enabled? rules.enabled.by_priority.map do |rule| { id: rule.id, type: rule.rule_type, target: rule.target, action: rule.action, conditions: rule.conditions, priority: rule.priority, expires_at: rule.expires_at } end end def add_rule(rule_type, target, action, conditions: {}, expires_at: nil, priority: 100) rules.create!( rule_type: rule_type, target: target, action: action, conditions: conditions, expires_at: expires_at, priority: priority ) end def remove_rule(rule_id) rules.find(rule_id).destroy end def block_ip(ip_address, expires_at: nil, reason: nil) add_rule('ip', ip_address, 'deny', expires_at: expires_at, priority: 1000) end def allow_ip(ip_address, expires_at: nil) add_rule('ip', ip_address, 'allow', expires_at: expires_at, priority: 1000) end def block_cidr(cidr, expires_at: nil, reason: nil) add_rule('cidr', cidr, 'deny', expires_at: expires_at, priority: 900) end def block_path(path, conditions: {}, expires_at: nil) add_rule('path', path, 'deny', conditions: conditions, expires_at: expires_at, priority: 500) end def block_user_agent(user_agent_pattern, expires_at: nil) add_rule('user_agent', user_agent_pattern, 'deny', expires_at: expires_at, priority: 600) end def push_to_agents! # This would integrate with the agent distribution system Rails.logger.info "Pushing rule set '#{name}' with #{rules.count} rules to agents" # Broadcast update to connected projects projects = Project.where(id: projects_subscription || []) projects.each(&:broadcast_rules_refresh) end def active_projects return Project.none unless projects_subscription.present? Project.where(id: projects_subscription).enabled end def subscribe_project(project) subscriptions = projects_subscription || [] subscriptions << project.id unless subscriptions.include?(project.id) update(projects_subscription: subscriptions.uniq) end def unsubscribe_project(project) subscriptions = projects_subscription || [] subscriptions.delete(project.id) update(projects_subscription: subscriptions) end private def generate_slug self.slug = name&.parameterize&.downcase end def set_default_values self.enabled = true if enabled.nil? self.priority = 100 if priority.nil? self.projects_subscription = [] if projects_subscription.nil? end end