Files
baffle-hub/test/jobs/path_scanner_detector_job_test.rb
Dan Milne 6433f6c5bb Updates
2025-11-14 16:35:49 +11:00

252 lines
5.8 KiB
Ruby

# frozen_string_literal: true
require "test_helper"
class PathScannerDetectorJobTest < ActiveJob::TestCase
setup do
@project = Project.first || #Project.create!(
name: "Test Project",
slug: "test-project",
public_key: SecureRandom.hex(16)
)
end
test "creates ban rule for IP hitting scanner paths" do
ip = "192.168.1.100"
# Create events hitting scanner paths
["/.env", "/.git", "/wp-admin"].each do |path|
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: path,
waf_action: "allow"
)
end
count = PathScannerDetectorJob.perform_now
assert_equal 1, count
rule = Rule.where(source: "auto:scanner_detected").last
assert_not_nil rule
assert_equal "network", rule.waf_rule_type
assert_equal "deny", rule.waf_action
assert_equal "#{ip}/32", rule.cidr
assert_equal 32, rule.priority
assert rule.enabled?
end
test "sets 24 hour expiration on ban rules" do
ip = "192.168.1.100"
3.times do |i|
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
PathScannerDetectorJob.perform_now
rule = Rule.where(source: "auto:scanner_detected").last
assert_not_nil rule.expires_at
# Should expire in approximately 24 hours
time_until_expiry = rule.expires_at - Time.current
assert time_until_expiry > 23.hours
assert time_until_expiry < 25.hours
end
test "includes metadata about detected paths" do
ip = "192.168.1.100"
paths = ["/.env", "/.git", "/wp-admin"]
paths.each do |path|
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: path,
waf_action: "allow"
)
end
PathScannerDetectorJob.perform_now
rule = Rule.where(source: "auto:scanner_detected").last
assert_equal 3, rule.metadata["hit_count"]
assert_equal paths.sort, rule.metadata["paths"].sort
assert rule.metadata["reason"].include?("Scanner detected")
assert rule.metadata["auto_generated"]
end
test "does not create rule for insufficient hits" do
ip = "192.168.1.100"
# Only 2 hits, minimum is 3
2.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
count = PathScannerDetectorJob.perform_now
assert_equal 0, count
end
test "only considers recent events" do
ip = "192.168.1.100"
# Old event (outside lookback window)
old_event = Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: 10.minutes.ago,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
# Recent events
2.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.git",
waf_action: "allow"
)
end
count = PathScannerDetectorJob.perform_now
# Should not find sufficient hits (only 2 recent, 1 old)
assert_equal 0, count
end
test "does not create duplicate rules for existing IP" do
ip = "192.168.1.100"
# Create existing rule
Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "#{ip}/32" },
enabled: true
)
# Create scanner events
3.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
count = PathScannerDetectorJob.perform_now
assert_equal 0, count
end
test "handles IPv6 addresses" do
ip = "2001:db8::1"
3.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
count = PathScannerDetectorJob.perform_now
assert_equal 1, count
rule = Rule.where(source: "auto:scanner_detected").last
assert_equal "network", rule.waf_rule_type
assert_equal "#{ip}/32", rule.cidr
end
test "creates separate rules for different IPs" do
ip1 = "192.168.1.100"
ip2 = "192.168.1.101"
[ip1, ip2].each do |ip|
3.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
end
count = PathScannerDetectorJob.perform_now
assert_equal 2, count
end
test "handles invalid IP addresses gracefully" do
# Create event with invalid IP
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: "invalid-ip",
request_path: "/.env",
waf_action: "allow"
)
assert_nothing_raised do
PathScannerDetectorJob.perform_now
end
end
test "returns count of created rules" do
3.times do |i|
ip = "192.168.1.#{100 + i}"
3.times do
Event.create!(
project: @project,
request_id: SecureRandom.uuid,
timestamp: Time.current,
ip_address: ip,
request_path: "/.env",
waf_action: "allow"
)
end
end
count = PathScannerDetectorJob.perform_now
assert_equal 3, count
end
end