Many updates
This commit is contained in:
474
test/models/waf_policy_test.rb
Normal file
474
test/models/waf_policy_test.rb
Normal file
@@ -0,0 +1,474 @@
|
||||
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
|
||||
Reference in New Issue
Block a user