Accepts incoming events and correctly parses them into events. GeoLite2 integration complete"

This commit is contained in:
Dan Milne
2025-11-04 00:11:10 +11:00
parent 0cbd462e7c
commit 5ff166613e
49 changed files with 4489 additions and 322 deletions

View File

@@ -0,0 +1,138 @@
# frozen_string_literal: true
require "test_helper"
class ExpiredRulesCleanupJobTest < ActiveJob::TestCase
test "disables expired rules" do
expired_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
expires_at: 1.hour.ago,
enabled: true
)
active_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "192.168.0.0/16" },
expires_at: 1.hour.from_now,
enabled: true
)
count = ExpiredRulesCleanupJob.perform_now
assert_equal 1, count
assert_not expired_rule.reload.enabled?
assert active_rule.reload.enabled?
end
test "does not affect rules without expiration" do
permanent_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
expires_at: nil,
enabled: true
)
ExpiredRulesCleanupJob.perform_now
assert permanent_rule.reload.enabled?
end
test "does not affect already disabled rules" do
disabled_expired_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
expires_at: 1.hour.ago,
enabled: false
)
count = ExpiredRulesCleanupJob.perform_now
assert_equal 0, count
assert_not disabled_expired_rule.reload.enabled?
end
test "updates updated_at timestamp when disabling" do
expired_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
expires_at: 1.hour.ago,
enabled: true
)
original_updated_at = expired_rule.updated_at
sleep 0.01 # Ensure time passes
ExpiredRulesCleanupJob.perform_now
assert expired_rule.reload.updated_at > original_updated_at
end
test "deletes old disabled rules when running at 1am" do
old_disabled_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
enabled: false
)
old_disabled_rule.update_column(:updated_at, 31.days.ago)
recent_disabled_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "192.168.0.0/16" },
enabled: false
)
Time.stub :current, Time.current.change(hour: 1) do
ExpiredRulesCleanupJob.perform_now
end
assert_raises(ActiveRecord::RecordNotFound) { old_disabled_rule.reload }
assert_nothing_raised { recent_disabled_rule.reload }
end
test "does not delete old rules when not running at 1am" do
old_disabled_rule = Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.0.0.0/8" },
enabled: false
)
old_disabled_rule.update_column(:updated_at, 31.days.ago)
Time.stub :current, Time.current.change(hour: 10) do
ExpiredRulesCleanupJob.perform_now
end
assert_nothing_raised { old_disabled_rule.reload }
end
test "returns count of disabled rules" do
3.times do |i|
Rule.create!(
rule_type: "network_v4",
action: "deny",
conditions: { cidr: "10.#{i}.0.0/16" },
expires_at: 1.hour.ago,
enabled: true
)
end
count = ExpiredRulesCleanupJob.perform_now
assert_equal 3, count
end
test "returns zero when no expired rules" do
count = ExpiredRulesCleanupJob.perform_now
assert_equal 0, count
end
end

View 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