# frozen_string_literal: true require "test_helper" class RuleTest < ActiveSupport::TestCase # Validation tests test "should create valid network rule" do network_range = NetworkRange.create!(cidr: "10.0.0.0/8") rule = Rule.new( waf_rule_type: "network", waf_action: "deny", network_range: network_range, source: "manual", user: users(:one) ) assert rule.valid? rule.save! assert_equal 8, rule.priority # Auto-calculated from CIDR prefix end test "should create valid network rule with IPv6" do network_range = NetworkRange.create!(cidr: "2001:db8::/32") rule = Rule.new( waf_rule_type: "network", waf_action: "deny", network_range: network_range, source: "manual", user: users(:one) ) assert rule.valid? rule.save! assert_equal 32, rule.priority end test "should create valid rate_limit rule" do rule = Rule.new( waf_rule_type: "rate_limit", waf_action: "rate_limit", conditions: { cidr: "0.0.0.0/0", scope: "global" }, metadata: { limit: 100, window: 60 }, source: "manual", user: users(:one) ) assert rule.valid? end test "should create valid path_pattern rule" do rule = Rule.new( waf_rule_type: "path_pattern", waf_action: "log", conditions: { patterns: ["/.env", "/.git"] }, source: "default", user: users(:one) ) assert rule.valid? end test "should require waf_rule_type" do rule = Rule.new(waf_action: "deny", waf_rule_type: nil, conditions: { patterns: ["/test"] }, user: users(:one)) assert_not rule.valid? assert_includes rule.errors[:waf_rule_type], "can't be blank" end test "should require waf_action" do rule = Rule.new(waf_rule_type: "path_pattern", waf_action: nil, conditions: { patterns: ["/test"] }, user: users(:one)) assert_not rule.valid? assert_includes rule.errors[:waf_action], "can't be blank" end test "should validate network has valid CIDR" do rule = Rule.new( waf_rule_type: "network", waf_action: "deny", conditions: { cidr: "invalid-cidr" }, # Invalid CIDR user: users(:one) ) assert_not rule.valid? # Network rules now validate differently - they need a network_range assert_includes rule.errors[:network_range], "is required for network rules" end test "should validate rate_limit has limit and window in metadata" do rule = Rule.new( waf_rule_type: "rate_limit", waf_action: "rate_limit", conditions: { cidr: "0.0.0.0/0", scope: "global" }, metadata: { limit: 100 }, # Missing window user: users(:one) ) assert_not rule.valid? assert_includes rule.errors[:metadata], "must include 'limit' and 'window' for rate_limit rules" end # Default value tests test "should default enabled to true" do network_range = NetworkRange.create!(cidr: "10.0.0.0/8") rule = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: network_range, user: users(:one) ) assert rule.enabled? end # Priority calculation tests test "should calculate priority from IPv4 CIDR prefix" do network_range = NetworkRange.create!(cidr: "192.168.1.0/24") rule = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: network_range, user: users(:one) ) assert_equal 24, rule.priority end # Scope tests test "active scope returns enabled and non-expired rules" do active_range = NetworkRange.create!(cidr: "10.0.0.0/8") active = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: active_range, enabled: true, user: users(:one) ) disabled_range = NetworkRange.create!(cidr: "192.168.0.0/16") disabled = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: disabled_range, enabled: false, user: users(:one) ) expired_range = NetworkRange.create!(cidr: "172.16.0.0/12") expired = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: expired_range, enabled: true, expires_at: 1.hour.ago, user: users(:one) ) results = Rule.active.to_a assert_includes results, active assert_not_includes results, disabled assert_not_includes results, expired end # Instance method tests test "active? returns true for enabled non-expired rule" do network_range = NetworkRange.create!(cidr: "10.0.0.0/8") rule = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: network_range, enabled: true, user: users(:one) ) assert rule.active? end test "disable! sets enabled to false and adds metadata" do network_range = NetworkRange.create!(cidr: "10.0.0.0/8") rule = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: network_range, user: users(:one) ) rule.disable!(reason: "False positive") assert_not rule.enabled? assert_equal "False positive", rule.metadata["disabled_reason"] assert rule.metadata["disabled_at"].present? end # Agent format tests test "to_agent_format returns correct structure" do network_range = NetworkRange.create!(cidr: "10.0.0.0/8") rule = Rule.create!( waf_rule_type: "network", waf_action: "deny", network_range: network_range, expires_at: 1.day.from_now, source: "manual", metadata: { reason: "Test" }, user: users(:one) ) format = rule.to_agent_format assert_equal rule.id, format[:id] assert_equal "network", format[:waf_rule_type] assert_equal "deny", format[:waf_action] assert_equal 8, format[:priority] assert_equal true, format[:enabled] end end