Files
baffle-hub/test/controllers/api/events_controller_test.rb
2025-11-13 14:42:43 +11:00

229 lines
7.3 KiB
Ruby

# frozen_string_literal: true
require "test_helper"
class Api::EventsControllerTest < ActionDispatch::IntegrationTest
def setup
@dsn = Dsn.create!(name: "Test DSN", key: "test-api-key-1234567890abcdef")
@disabled_dsn = Dsn.create!(name: "Disabled DSN", key: "disabled-key-1234567890abcdef", enabled: false)
@sample_event_data = {
"timestamp" => Time.current.iso8601,
"method" => "GET",
"path" => "/api/test",
"status" => 200,
"ip" => "192.168.1.100",
"user_agent" => "TestAgent/1.0"
}
end
test "should create event with valid DSN via query parameter" do
post api_events_path,
params: @sample_event_data.merge(baffle_key: @dsn.key),
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
assert_not_nil json_response["rule_version"]
assert_not_nil response.headers['X-Rule-Version']
end
test "should create event with valid DSN via Authorization header" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
end
test "should create event with valid DSN via X-Baffle-Auth header" do
post api_events_path,
headers: { "X-Baffle-Auth" => "Baffle baffle_key=#{@dsn.key}, baffle_version=1" },
params: @sample_event_data,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
end
test "should create event with valid DSN via Basic auth" do
credentials = Base64.strict_encode64("#{@dsn.key}:password")
post api_events_path,
headers: { "Authorization" => "Basic #{credentials}" },
params: @sample_event_data,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
end
test "should create event with form encoded data" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :url_encoded
assert_response :success
end
test "should include rules in response when agent has no version" do
# Create some test rules
Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Test rule")
Rule.create!(action: "allow", pattern_type: "ip", pattern: "10.0.0.0/8", reason: "Allow internal")
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
assert json_response["rules_changed"]
assert_not_nil json_response["rules"]
assert_equal 2, json_response["rules"].length
end
test "should include only new rules when agent has old version" do
# Create rules with different versions
old_rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Old rule", version: 1)
new_rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "203.0.113.0/24", reason: "New rule", version: 2)
event_data_with_version = @sample_event_data.merge("last_rule_sync" => 1)
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: event_data_with_version,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
assert json_response["rules_changed"]
assert_equal 1, json_response["rules"].length
assert_equal "203.0.113.0/24", json_response["rules"].first["pattern"]
end
test "should not include rules when agent has latest version" do
# Create a rule and get its version
rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Test rule")
latest_version = Rule.latest_version
event_data_with_latest_version = @sample_event_data.merge("last_rule_sync" => latest_version)
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: event_data_with_latest_version,
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
assert_not json_response["rules_changed"]
assert_nil json_response["rules"]
end
test "should return unauthorized with invalid DSN key" do
post api_events_path,
headers: { "Authorization" => "Bearer invalid-key-1234567890abcdef" },
params: @sample_event_data,
as: :json
assert_response :unauthorized
end
test "should return unauthorized with disabled DSN" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@disabled_dsn.key}" },
params: @sample_event_data,
as: :json
assert_response :unauthorized
end
test "should return unauthorized with no authentication" do
post api_events_path,
params: @sample_event_data,
as: :json
assert_response :unauthorized
end
test "should return bad request with invalid JSON" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: "invalid json {",
as: :json
assert_response :bad_request
end
test "should handle empty request body gracefully" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: {},
as: :json
assert_response :success
json_response = JSON.parse(response.body)
assert json_response["success"]
end
test "should set sampling headers in response" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :json
assert_response :success
assert_not_nil response.headers['X-Sample-Rate']
assert_not_nil response.headers['X-Sample-Until']
end
test "should set rule version header in response" do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :json
assert_response :success
assert_not_nil response.headers['X-Rule-Version']
assert_match /^\d+$/, response.headers['X-Rule-Version']
end
test "should handle large event payloads" do
large_payload = @sample_event_data.merge(
"large_field" => "x" * 10000, # 10KB of data
"headers" => { "user-agent" => "TestAgent", "accept" => "*/*" },
"custom_data" => Hash[*(1..100).map { |i| ["key#{i}", "value#{i}"] }.flatten]
)
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: large_payload,
as: :json
assert_response :success
end
test "should process event asynchronously" do
# Clear any existing jobs
ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = false
assert_difference 'ProcessWafEventJob.jobs.count', 1 do
post api_events_path,
headers: { "Authorization" => "Bearer #{@dsn.key}" },
params: @sample_event_data,
as: :json
end
assert_response :success
end
end