Files
baffle-hub/test/models/waf_policy_test.rb
2025-11-13 14:42:43 +11:00

475 lines
14 KiB
Ruby

require "test_helper"
class WafPolicyTest < ActiveSupport::TestCase
setup do
@user = users(:jason)
@policy = WafPolicy.new(
name: "Block Malicious IPs",
policy_type: "country",
targets: ["BR", "CN"],
policy_action: "deny",
user: @user
)
end
# Validations
test "should be valid with all required attributes" do
assert @policy.valid?
end
test "should not be valid without name" do
@policy.name = nil
assert_not @policy.valid?
assert_includes @policy.errors[:name], "can't be blank"
end
test "should not be valid without unique name" do
@policy.name = waf_policies(:one).name
assert_not @policy.valid?
assert_includes @policy.errors[:name], "has already been taken"
end
test "should validate policy_type inclusion" do
@policy.policy_type = "invalid_type"
assert_not @policy.valid?
assert_includes @policy.errors[:policy_type], "is not included in the list"
end
test "should validate policy_action inclusion" do
@policy.policy_action = "invalid_action"
assert_not @policy.valid?
assert_includes @policy.errors[:policy_action], "is not included in the list"
end
test "should not be valid without targets" do
@policy.targets = []
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "can't be blank"
end
test "should validate targets is an array" do
@policy.targets = "not an array"
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "must be an array"
end
test "should validate country targets format" do
@policy.policy_type = "country"
# Valid country codes
@policy.targets = ["US", "BR", "CN"]
assert @policy.valid?
# Invalid country codes
@policy.targets = ["USA", "123", "B"]
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "must be valid ISO country codes"
end
test "should validate ASN targets format" do
@policy.policy_type = "asn"
# Valid ASNs
@policy.targets = [12345, 67890]
assert @policy.valid?
# Invalid ASNs
@policy.targets = ["AS12345", -1, 0]
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "must be valid ASNs"
end
test "should validate company targets format" do
@policy.policy_type = "company"
# Valid company names
@policy.targets = ["Google", "Amazon Web Services", "Microsoft"]
assert @policy.valid?
# Invalid company names
@policy.targets = ["", nil, " "]
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "must be valid company names"
end
test "should validate network_type targets format" do
@policy.policy_type = "network_type"
# Valid network types
@policy.targets = ["datacenter", "proxy", "vpn", "standard"]
assert @policy.valid?
# Invalid network types
@policy.targets = ["invalid", "malicious", "botnet"]
assert_not @policy.valid?
assert_includes @policy.errors[:targets], "must be one of: datacenter, proxy, vpn, standard"
end
test "should validate redirect configuration" do
@policy.policy_action = "redirect"
# Valid redirect config
@policy.additional_data = { "redirect_url" => "https://example.com/blocked" }
assert @policy.valid?
# Missing redirect URL
@policy.additional_data = { "other_config" => "value" }
assert_not @policy.valid?
assert_includes @policy.errors[:additional_data], "must include 'redirect_url' for redirect action"
end
test "should validate challenge configuration" do
@policy.policy_action = "challenge"
# Valid challenge types
@policy.additional_data = { "challenge_type" => "captcha" }
assert @policy.valid?
@policy.additional_data = { "challenge_type" => "javascript" }
assert @policy.valid?
# Invalid challenge type
@policy.additional_data = { "challenge_type" => "invalid" }
assert_not @policy.valid?
assert_includes @policy.errors[:additional_data], "challenge_type must be one of: captcha, javascript, proof_of_work"
# No challenge type (should be valid, uses defaults)
@policy.additional_data = {}
assert @policy.valid?
end
# Defaults and Callbacks
test "should default to enabled" do
@policy.enabled = nil
@policy.save!
assert @policy.enabled?
end
test "should default targets to empty array" do
policy = WafPolicy.new(
name: "Test Policy",
policy_type: "country",
policy_action: "deny",
user: @user
)
# before_validation should set defaults
policy.valid?
assert_equal [], policy.targets
end
test "should default additional_data to empty hash" do
policy = WafPolicy.new(
name: "Test Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user
)
policy.valid?
assert_equal({}, policy.additional_data)
end
# Policy Type Methods
test "policy type predicate methods work correctly" do
country_policy = WafPolicy.new(policy_type: "country")
assert country_policy.country_policy?
assert_not country_policy.asn_policy?
assert_not country_policy.company_policy?
assert_not country_policy.network_type_policy?
asn_policy = WafPolicy.new(policy_type: "asn")
assert_not asn_policy.country_policy?
assert asn_policy.asn_policy?
assert_not asn_policy.company_policy?
assert_not asn_policy.network_type_policy?
company_policy = WafPolicy.new(policy_type: "company")
assert_not company_policy.country_policy?
assert_not company_policy.asn_policy?
assert company_policy.company_policy?
assert_not company_policy.network_type_policy?
network_type_policy = WafPolicy.new(policy_type: "network_type")
assert_not network_type_policy.country_policy?
assert_not network_type_policy.asn_policy?
assert_not network_type_policy.company_policy?
assert network_type_policy.network_type_policy?
end
# Action Methods
test "action predicate methods work correctly" do
allow_policy = WafPolicy.new(policy_action: "allow")
assert allow_policy.allow_action?
assert_not allow_policy.deny_action?
assert_not allow_policy.redirect_action?
assert_not allow_policy.challenge_action?
deny_policy = WafPolicy.new(policy_action: "deny")
assert_not deny_policy.allow_action?
assert deny_policy.deny_action?
assert_not deny_policy.redirect_action?
assert_not deny_policy.challenge_action?
redirect_policy = WafPolicy.new(policy_action: "redirect")
assert_not redirect_policy.allow_action?
assert_not redirect_policy.deny_action?
assert redirect_policy.redirect_action?
assert_not redirect_policy.challenge_action?
challenge_policy = WafPolicy.new(policy_action: "challenge")
assert_not challenge_policy.allow_action?
assert_not challenge_policy.deny_action?
assert_not challenge_policy.redirect_action?
assert challenge_policy.challenge_action?
end
# Policy action methods (to avoid Rails conflicts)
test "policy action predicate methods work correctly" do
policy = WafPolicy.new(policy_action: "deny")
assert policy.deny_policy_action?
assert_not policy.allow_policy_action?
assert_not policy.redirect_policy_action?
assert_not policy.challenge_policy_action?
end
# Lifecycle Methods
test "active? works correctly" do
# Active policy
active_policy = WafPolicy.new(enabled: true, expires_at: nil)
assert active_policy.active?
# Enabled but expired
expired_policy = WafPolicy.new(enabled: true, expires_at: 1.day.ago)
assert_not expired_policy.active?
# Disabled with future expiration
disabled_policy = WafPolicy.new(enabled: false, expires_at: 1.day.from_now)
assert_not disabled_policy.active?
# Disabled with no expiration
disabled_no_exp = WafPolicy.new(enabled: false, expires_at: nil)
assert_not disabled_no_exp.active?
# Enabled with future expiration
future_exp = WafPolicy.new(enabled: true, expires_at: 1.day.from_now)
assert future_exp.active?
end
test "expired? works correctly" do
assert_not WafPolicy.new(expires_at: nil).expired?
assert_not WafPolicy.new(expires_at: 1.day.from_now).expired?
assert WafPolicy.new(expires_at: 1.day.ago).expired?
assert WafPolicy.new(expires_at: Time.current).expired?
end
test "activate! enables policy" do
@policy.enabled = false
@policy.save!
@policy.activate!
assert @policy.reload.enabled?
end
test "deactivate! disables policy" do
@policy.enabled = true
@policy.save!
@policy.deactivate!
assert_not @policy.reload.enabled?
end
test "expire! sets expiration to now" do
@policy.expire!
assert @policy.reload.expires_at <= Time.current
end
# Scopes
test "enabled scope returns only enabled policies" do
enabled_policy = WafPolicy.create!(
name: "Enabled Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user,
enabled: true
)
disabled_policy = WafPolicy.create!(
name: "Disabled Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user,
enabled: false
)
enabled_policies = WafPolicy.enabled
assert_includes enabled_policies, enabled_policy
assert_not_includes enabled_policies, disabled_policy
end
test "active scope returns only active policies" do
active_policy = WafPolicy.create!(
name: "Active Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user,
enabled: true,
expires_at: 1.day.from_now
)
expired_policy = WafPolicy.create!(
name: "Expired Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user,
enabled: true,
expires_at: 1.day.ago
)
disabled_policy = WafPolicy.create!(
name: "Disabled Policy",
policy_type: "country",
targets: ["US"],
policy_action: "deny",
user: @user,
enabled: false
)
active_policies = WafPolicy.active
assert_includes active_policies, active_policy
assert_not_includes active_policies, expired_policy
assert_not_includes active_policies, disabled_policy
end
# Class Factory Methods
test "create_country_policy works correctly" do
policy = WafPolicy.create_country_policy(
["US", "CA"],
policy_action: "deny",
user: @user,
name: "Custom Name"
)
assert policy.persisted?
assert_equal "Custom Name", policy.name
assert_equal "country", policy.policy_type
assert_equal "deny", policy.policy_action
assert_equal ["US", "CA"], policy.targets
assert_equal @user, policy.user
end
test "create_asn_policy works correctly" do
policy = WafPolicy.create_asn_policy(
[12345, 67890],
policy_action: "challenge",
user: @user
)
assert policy.persisted?
assert_equal "challenge ASNs 12345, 67890", policy.name
assert_equal "asn", policy.policy_type
assert_equal "challenge", policy.policy_action
assert_equal [12345, 67890], policy.targets
end
test "create_company_policy works correctly" do
policy = WafPolicy.create_company_policy(
["Google", "Amazon"],
policy_action: "deny",
user: @user
)
assert policy.persisted?
assert_equal "deny Google, Amazon", policy.name
assert_equal "company", policy.policy_type
assert_equal ["Google", "Amazon"], policy.targets
end
test "create_network_type_policy works correctly" do
policy = WafPolicy.create_network_type_policy(
["datacenter", "proxy"],
policy_action: "redirect",
user: @user,
additional_data: { redirect_url: "https://example.com/blocked" }
)
assert policy.persisted?
assert_equal "redirect datacenter, proxy", policy.name
assert_equal "network_type", policy.policy_type
assert_equal ["datacenter", "proxy"], policy.targets
end
# Redirect/Challenge Specific Methods
test "redirect_url and redirect_status methods work" do
policy = WafPolicy.new(
policy_action: "redirect",
additional_data: {
"redirect_url" => "https://example.com/blocked",
"redirect_status" => 301
}
)
assert_equal "https://example.com/blocked", policy.redirect_url
assert_equal 301, policy.redirect_status
# Default status
policy.additional_data = { "redirect_url" => "https://example.com/blocked" }
assert_equal 302, policy.redirect_status
end
test "challenge_type and challenge_message methods work" do
policy = WafPolicy.new(
policy_action: "challenge",
additional_data: {
"challenge_type" => "javascript",
"challenge_message" => "Please verify you are human"
}
)
assert_equal "javascript", policy.challenge_type
assert_equal "Please verify you are human", policy.challenge_message
# Default challenge type
policy.additional_data = {}
assert_equal "captcha", policy.challenge_type
end
# Statistics
test "generated_rules_count works" do
@policy.save!
# Initially no rules
assert_equal 0, @policy.generated_rules_count
# Create some rules
network_range = NetworkRange.create!(ip_range: "192.168.1.0/24")
@policy.create_rule_for_network_range(network_range)
assert_equal 1, @policy.generated_rules_count
end
test "effectiveness_stats returns correct data" do
@policy.save!
stats = @policy.effectiveness_stats
assert_equal 0, stats[:total_rules_generated]
assert_equal 0, stats[:active_rules]
assert_equal 0, stats[:rules_last_7_days]
assert_equal "country", stats[:policy_type]
assert_equal "deny", stats[:policy_action]
assert_equal 2, stats[:targets_count]
end
# String representations
test "to_s returns name" do
assert_equal @policy.name, @policy.to_s
end
test "to_param parameterizes name" do
@policy.name = "Block Brazil & China"
expected = "block-brazil-china"
assert_equal expected, @policy.to_param
end
end