Accepts incoming events and correctly parses them into events. GeoLite2 integration complete"
This commit is contained in:
251
test/jobs/path_scanner_detector_job_test.rb
Normal file
251
test/jobs/path_scanner_detector_job_test.rb
Normal file
@@ -0,0 +1,251 @@
|
||||
# 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,
|
||||
event_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_v4", rule.rule_type
|
||||
assert_equal "deny", rule.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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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_v6", rule.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,
|
||||
event_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,
|
||||
event_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,
|
||||
event_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
|
||||
Reference in New Issue
Block a user