Add WafPolicies

This commit is contained in:
Dan Milne
2025-11-10 14:10:37 +11:00
parent af7413c899
commit 772fae7e8b
22 changed files with 1784 additions and 147 deletions

View File

@@ -7,12 +7,13 @@
class Rule < ApplicationRecord
# Rule types and actions
RULE_TYPES = %w[network rate_limit path_pattern].freeze
ACTIONS = %w[allow deny rate_limit redirect log].freeze
SOURCES = %w[manual auto:scanner_detected auto:rate_limit_exceeded auto:bot_detected imported default manual:surgical_block manual:surgical_exception].freeze
ACTIONS = %w[allow deny rate_limit redirect log challenge].freeze
SOURCES = %w[manual auto:scanner_detected auto:rate_limit_exceeded auto:bot_detected imported default manual:surgical_block manual:surgical_exception policy].freeze
# Associations
belongs_to :user
belongs_to :network_range, optional: true
belongs_to :waf_policy, optional: true
# Validations
validates :rule_type, presence: true, inclusion: { in: RULE_TYPES }
@@ -39,6 +40,8 @@ class Rule < ApplicationRecord
scope :by_source, ->(source) { where(source: source) }
scope :surgical_blocks, -> { where(source: "manual:surgical_block") }
scope :surgical_exceptions, -> { where(source: "manual:surgical_exception") }
scope :policy_generated, -> { where(source: "policy") }
scope :from_waf_policy, ->(waf_policy) { where(waf_policy: waf_policy) }
# Sync queries
scope :since, ->(timestamp) { where("updated_at >= ?", Time.at(timestamp)).order(:updated_at, :id) }
@@ -94,6 +97,37 @@ class Rule < ApplicationRecord
source == "manual:surgical_exception"
end
# Policy-generated rule methods
def policy_generated?
source == "policy"
end
# Action-specific methods
def redirect_action?
action == "redirect"
end
def challenge_action?
action == "challenge"
end
# Redirect/challenge convenience methods
def redirect_url
metadata&.dig('redirect_url')
end
def redirect_status
metadata&.dig('redirect_status') || 302
end
def challenge_type
metadata&.dig('challenge_type') || 'captcha'
end
def challenge_message
metadata&.dig('challenge_message')
end
def related_surgical_rules
if surgical_block?
# Find the corresponding exception rule
@@ -365,6 +399,12 @@ class Rule < ApplicationRecord
unless metadata&.dig("redirect_url").present?
errors.add(:metadata, "must include 'redirect_url' for redirect action")
end
when "challenge"
# Challenge is flexible - can use defaults
challenge_type_value = metadata&.dig("challenge_type")
if challenge_type_value && !%w[captcha javascript proof_of_work].include?(challenge_type_value)
errors.add(:metadata, "challenge_type must be one of: captcha, javascript, proof_of_work")
end
when "rate_limit"
unless metadata&.dig("limit").present? && metadata&.dig("window").present?
errors.add(:metadata, "must include 'limit' and 'window' for rate_limit action")