diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/action_controller_subscriber.rb b/sentry-rails/lib/sentry/rails/log_subscribers/action_controller_subscriber.rb index 4b317e564..0ed8b5d5c 100644 --- a/sentry-rails/lib/sentry/rails/log_subscribers/action_controller_subscriber.rb +++ b/sentry-rails/lib/sentry/rails/log_subscribers/action_controller_subscriber.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "sentry/rails/log_subscriber" -require "sentry/rails/log_subscribers/parameter_filter" module Sentry module Rails @@ -21,8 +20,6 @@ module LogSubscribers # config.rails.structured_logging.subscribers = { action_controller: Sentry::Rails::LogSubscribers::ActionControllerSubscriber } # end class ActionControllerSubscriber < Sentry::Rails::LogSubscriber - include ParameterFilter - # Handle process_action.action_controller events # # @param event [ActiveSupport::Notifications::Event] The controller action event @@ -55,9 +52,9 @@ def process_action(event) attributes[:db_runtime_ms] = payload[:db_runtime].round(2) end - if Sentry.configuration.send_default_pii && payload[:params] - filtered_params = filter_sensitive_params(payload[:params]) - attributes[:params] = filtered_params unless filtered_params.empty? + if payload[:params] + params = Sentry.configuration.data_collection.url_query_params.filter(payload[:params]) + attributes[:params] = params unless params.empty? end level = level_for_request(payload) diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/action_mailer_subscriber.rb b/sentry-rails/lib/sentry/rails/log_subscribers/action_mailer_subscriber.rb index 2d8237fb7..17f624030 100644 --- a/sentry-rails/lib/sentry/rails/log_subscribers/action_mailer_subscriber.rb +++ b/sentry-rails/lib/sentry/rails/log_subscribers/action_mailer_subscriber.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "sentry/rails/log_subscriber" -require "sentry/rails/log_subscribers/parameter_filter" module Sentry module Rails @@ -20,8 +19,6 @@ module LogSubscribers # config.rails.structured_logging.subscribers = { action_mailer: Sentry::Rails::LogSubscribers::ActionMailerSubscriber } # end class ActionMailerSubscriber < Sentry::Rails::LogSubscriber - include ParameterFilter - # Handle deliver.action_mailer events # # @param event [ActiveSupport::Notifications::Event] The email delivery event @@ -41,8 +38,8 @@ def deliver(event) attributes[:delivery_method] = payload[:delivery_method] if payload[:delivery_method] attributes[:date] = payload[:date].to_s if payload[:date] - if Sentry.configuration.send_default_pii - attributes[:message_id] = payload[:message_id] if payload[:message_id] + if Sentry.configuration.data_collection.user_info && payload[:message_id] + attributes[:message_id] = payload[:message_id] end message = "Email delivered via #{mailer}" @@ -73,9 +70,9 @@ def process(event) duration_ms: duration } - if Sentry.configuration.send_default_pii && payload[:params] - filtered_params = filter_sensitive_params(payload[:params]) - attributes[:params] = filtered_params unless filtered_params.empty? + if payload[:params] + params = Sentry.configuration.data_collection.url_query_params.filter(payload[:params]) + attributes[:params] = params unless params.empty? end message = "#{mailer}##{action}" diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/active_job_subscriber.rb b/sentry-rails/lib/sentry/rails/log_subscribers/active_job_subscriber.rb index da3353894..03e7adbc5 100644 --- a/sentry-rails/lib/sentry/rails/log_subscribers/active_job_subscriber.rb +++ b/sentry-rails/lib/sentry/rails/log_subscribers/active_job_subscriber.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "sentry/rails/log_subscriber" -require "sentry/rails/log_subscribers/parameter_filter" module Sentry module Rails @@ -20,8 +19,6 @@ module LogSubscribers # config.rails.structured_logging.subscribers = { active_job: Sentry::Rails::LogSubscribers::ActiveJobSubscriber } # end class ActiveJobSubscriber < Sentry::Rails::LogSubscriber - include ParameterFilter - # Handle perform.active_job events # # @param event [ActiveSupport::Notifications::Event] The job performance event @@ -47,7 +44,7 @@ def perform(event) attributes[:delay_ms] = ((Time.current - job.scheduled_at) * 1000).round(2) end - if Sentry.configuration.send_default_pii && job.arguments.present? + if Sentry.configuration.data_collection.queues && job.arguments.present? filtered_args = filter_sensitive_arguments(job.arguments) attributes[:arguments] = filtered_args unless filtered_args.empty? end @@ -149,9 +146,11 @@ def filter_sensitive_arguments(arguments) arguments.map do |arg| case arg when Hash - filter_sensitive_params(arg) + # we're using url_query_params here since rails filter_parameters end up there + # and we don't have a dedicated queue params config yet + Sentry.configuration.data_collection.url_query_params.filter(arg, cookie: false) when String - arg.length > 100 ? "[FILTERED: #{arg.length} chars]" : arg + arg.length > 100 ? "[Filtered: #{arg.length} chars]" : arg else arg end diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb b/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb index ad0f7d642..f1437c2af 100644 --- a/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb +++ b/sentry-rails/lib/sentry/rails/log_subscribers/active_record_subscriber.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "sentry/rails/log_subscriber" -require "sentry/rails/log_subscribers/parameter_filter" module Sentry module Rails @@ -21,8 +20,6 @@ module LogSubscribers # config.rails.structured_logging.subscribers = { active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber } # end class ActiveRecordSubscriber < Sentry::Rails::LogSubscriber - include ParameterFilter - EXCLUDED_NAMES = ["SCHEMA", "TRANSACTION"].freeze EMPTY_ARRAY = [].freeze @@ -49,7 +46,7 @@ def sql(event) binds = event.payload[:binds] - if Sentry.configuration.send_default_pii && (binds && !binds.empty?) + if Sentry.configuration.data_collection.database_query_data && (binds && !binds.empty?) type_casted_binds = type_casted_binds(event) type_casted_binds.each_with_index do |value, index| diff --git a/sentry-rails/lib/sentry/rails/log_subscribers/parameter_filter.rb b/sentry-rails/lib/sentry/rails/log_subscribers/parameter_filter.rb deleted file mode 100644 index 8f20cf3ed..000000000 --- a/sentry-rails/lib/sentry/rails/log_subscribers/parameter_filter.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -module Sentry - module Rails - module LogSubscribers - # Shared utility module for filtering sensitive parameters in log subscribers. - # - # This module provides consistent parameter filtering across all Sentry Rails - # log subscribers, leveraging Rails' built-in parameter filtering when available. - # It automatically detects the correct Rails parameter filtering API based on - # the Rails version and includes the appropriate implementation module. - # - # @example Usage in a log subscriber - # class MySubscriber < Sentry::Rails::LogSubscriber - # include Sentry::Rails::LogSubscribers::ParameterFilter - # - # def my_event(event) - # if Sentry.configuration.send_default_pii && event.payload[:params] - # filtered_params = filter_sensitive_params(event.payload[:params]) - # attributes[:params] = filtered_params unless filtered_params.empty? - # end - # end - # end - module ParameterFilter - EMPTY_HASH = {}.freeze - - if ::Rails.version.to_f >= 6.0 - def self.backend - ActiveSupport::ParameterFilter - end - else - def self.backend - ActionDispatch::Http::ParameterFilter - end - end - - # Filter sensitive parameters from a hash, respecting Rails configuration. - # - # @param params [Hash] The parameters to filter - # @return [Hash] Filtered parameters with sensitive data removed - def filter_sensitive_params(params) - return EMPTY_HASH unless params.is_a?(Hash) - - filter_parameters = ::Rails.application.config.filter_parameters - parameter_filter = ParameterFilter.backend.new(filter_parameters) - - parameter_filter.filter(params) - end - end - end - end -end diff --git a/sentry-rails/spec/sentry/rails/log_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscriber_spec.rb index 7b0844a09..ea40c4b65 100644 --- a/sentry-rails/spec/sentry/rails/log_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscriber_spec.rb @@ -3,7 +3,6 @@ require "spec_helper" require "sentry/rails/log_subscriber" -require "sentry/rails/log_subscribers/parameter_filter" RSpec.describe Sentry::Rails::LogSubscriber, type: :request do let!(:test_subscriber) { test_subscriber_class.new } @@ -215,11 +214,9 @@ def temp_event(event) end end - context "parameter filtering integration" do + context "data collection integration" do let(:test_subscriber_class) do Class.new(described_class) do - include Sentry::Rails::LogSubscribers::ParameterFilter - attach_to :filtering_test def filtering_event(event) @@ -228,9 +225,9 @@ def filtering_event(event) component: "filtering_test" } - if Sentry.configuration.send_default_pii && event.payload[:params] - filtered_params = filter_sensitive_params(event.payload[:params]) - attributes[:params] = filtered_params unless filtered_params.empty? + if event.payload[:params] + params = Sentry.configuration.data_collection.url_query_params.filter(event.payload[:params]) + attributes[:params] = params unless params.empty? end log_structured_event( @@ -245,12 +242,47 @@ def filtering_event(event) make_basic_app do |config, app| config.enable_logs = true config.structured_logging.logger_class = Sentry::DebugStructuredLogger - config.send_default_pii = true + config.data_collection.url_query_params.mode = :deny_list end end - it_behaves_like "parameter filtering" do - let(:test_instance) { test_subscriber } + it "filters sensitive top-level parameters" do + ActiveSupport::Notifications.instrument( + "filtering_event.filtering_test", + params: { + "name" => "Ada", + "password" => "secret", + "api_token" => "token", + "nested" => { "password" => "nested secret" } + } + ) do + sleep(0.01) + end + + log_event = Sentry.logger.logged_events.find { |event| event["message"] == "Filtering event occurred" } + params = log_event["attributes"]["params"] + + expect(params).to include( + "name" => "Ada", + "password" => "[Filtered]", + "api_token" => "[Filtered]", + "nested" => { "password" => "nested secret" } + ) + end + + it "does not include parameters when collection is off" do + Sentry.configuration.data_collection.url_query_params.mode = :off + + ActiveSupport::Notifications.instrument( + "filtering_event.filtering_test", + params: { "name" => "Ada" } + ) do + sleep(0.01) + end + + log_event = Sentry.logger.logged_events.find { |event| event["message"] == "Filtering event occurred" } + + expect(log_event["attributes"]).not_to have_key("params") end end end diff --git a/sentry-rails/spec/sentry/rails/log_subscribers/action_controller_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscribers/action_controller_subscriber_spec.rb index 19de73b28..48747dd4c 100644 --- a/sentry-rails/spec/sentry/rails/log_subscribers/action_controller_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscribers/action_controller_subscriber_spec.rb @@ -4,9 +4,12 @@ RSpec.describe Sentry::Rails::LogSubscribers::ActionControllerSubscriber, type: :request do context "when logging is enabled" do + let(:send_default_pii) { false } + before do make_basic_app do |config, app| config.enable_logs = true + config.send_default_pii = send_default_pii config.rails.structured_logging.enabled = true config.rails.structured_logging.subscribers = { action_controller: Sentry::Rails::LogSubscribers::ActionControllerSubscriber } @@ -257,13 +260,7 @@ end context "when send_default_pii is enabled" do - before do - Sentry.configuration.send_default_pii = true - end - - after do - Sentry.configuration.send_default_pii = false - end + let(:send_default_pii) { true } it "includes filtered request parameters" do get "/world", params: { safe_param: "value", password: "secret" } @@ -278,7 +275,7 @@ params = JSON.parse(log_event[:attributes][:params][:value]) expect(params).to include("safe_param" => "value") - expect(params).to include("password" => "[FILTERED]") + expect(params).to include("password" => "[Filtered]") end it "filters sensitive parameter names" do @@ -299,10 +296,10 @@ params = JSON.parse(log_event[:attributes][:params][:value]) expect(params).to include("normal_param" => "value") - expect(params).to include("password" => "[FILTERED]") - expect(params).to include("api_key" => "[FILTERED]") - expect(params).to include("credit_card" => "[FILTERED]") - expect(params).to include("authorization" => "[FILTERED]") + expect(params).to include("password" => "[Filtered]") + expect(params).to include("api_key" => "[Filtered]") + expect(params).to include("credit_card" => "[Filtered]") + expect(params).to include("authorization" => "[Filtered]") end it "handles nested parameters correctly" do @@ -399,8 +396,4 @@ expect(sentry_logs.count).to eq(initial_log_count) end end - - describe "ParameterFilter functionality" do - include_examples "parameter filtering", described_class - end end diff --git a/sentry-rails/spec/sentry/rails/log_subscribers/action_mailer_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscribers/action_mailer_subscriber_spec.rb index 2ac0c1de5..4623f685e 100644 --- a/sentry-rails/spec/sentry/rails/log_subscribers/action_mailer_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscribers/action_mailer_subscriber_spec.rb @@ -4,9 +4,12 @@ RSpec.describe Sentry::Rails::LogSubscribers::ActionMailerSubscriber do context "when logging is enabled" do + let(:send_default_pii) { false } + before do make_basic_app do |config| config.enable_logs = true + config.send_default_pii = send_default_pii config.rails.structured_logging.enabled = true config.rails.structured_logging.subscribers = { action_mailer: Sentry::Rails::LogSubscribers::ActionMailerSubscriber } @@ -133,13 +136,7 @@ end context "when send_default_pii is enabled" do - before do - Sentry.configuration.send_default_pii = true - end - - after do - Sentry.configuration.send_default_pii = false - end + let(:send_default_pii) { true } it "includes message_id for deliver events" do ActiveSupport::Notifications.instrument("deliver.action_mailer", @@ -182,8 +179,8 @@ params = JSON.parse(log_event[:attributes][:params][:value]) expect(params).to include("user_id" => 123, "safe_param" => "value") - expect(params["password"]).to eq("[FILTERED]") - expect(params["api_key"]).to eq("[FILTERED]") + expect(params["password"]).to eq("[Filtered]") + expect(params["api_key"]).to eq("[Filtered]") expect(params).to include("email_address" => "user@example.com", "subject" => "Welcome!") end end @@ -250,6 +247,4 @@ expect(sentry_logs.count).to eq(initial_log_count) end end - - include_examples "parameter filtering", described_class end diff --git a/sentry-rails/spec/sentry/rails/log_subscribers/active_job_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscribers/active_job_subscriber_spec.rb index d65f85780..cce750c58 100644 --- a/sentry-rails/spec/sentry/rails/log_subscribers/active_job_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscribers/active_job_subscriber_spec.rb @@ -4,9 +4,12 @@ RSpec.describe Sentry::Rails::LogSubscribers::ActiveJobSubscriber, skip: Rails.version.to_f < 5.1 do context "when logging is enabled" do + let(:send_default_pii) { false } + before do make_basic_app do |config| config.enable_logs = true + config.send_default_pii = send_default_pii config.rails.structured_logging.enabled = true config.rails.structured_logging.subscribers = { active_job: Sentry::Rails::LogSubscribers::ActiveJobSubscriber } @@ -96,13 +99,7 @@ describe "argument filtering" do context "when send_default_pii is enabled" do - before do - Sentry.configuration.send_default_pii = true - end - - after do - Sentry.configuration.send_default_pii = false - end + let(:send_default_pii) { true } it "includes filtered job arguments" do test_job_class = Class.new(ActiveJob::Base) do @@ -136,11 +133,16 @@ def self.name "TestJobWithSensitiveArgs" end - def perform(password:, token:, safe_data:) + def perform(password:, token:, credit_card:, safe_data:) end end - test_job_class.perform_now(password: "secret123", token: "abc123", safe_data: "public") + test_job_class.perform_now( + password: "secret123", + token: "abc123", + credit_card: "4111111111111111", + safe_data: "public" + ) Sentry.get_current_client.flush @@ -151,8 +153,9 @@ def perform(password:, token:, safe_data:) arguments = JSON.parse(attributes[:arguments][:value]) expect(arguments.first).to include("safe_data" => "public") - expect(arguments.first).to include("password" => "[FILTERED]") - expect(arguments.first).to include("token" => "[FILTERED]") + expect(arguments.first).to include("password" => "[Filtered]") + expect(arguments.first).to include("token" => "[Filtered]") + expect(arguments.first).to include("credit_card" => "[Filtered]") Rails.application.config.filter_parameters = original_filter_params end @@ -179,7 +182,7 @@ def perform(short_string, long_string) arguments = JSON.parse(attributes[:arguments][:value]) expect(arguments).to include("short") - expect(arguments).to include("[FILTERED: 150 chars]") + expect(arguments).to include("[Filtered: 150 chars]") end it "handles mixed argument types" do @@ -194,7 +197,7 @@ def perform(string_arg, hash_arg, number_arg, array_arg) test_job_class.perform_now( "string_value", - { safe_key: "value", password: "secret" }, + { safe_var: "value", password: "secret" }, 42, [1, 2, 3] ) @@ -208,19 +211,31 @@ def perform(string_arg, hash_arg, number_arg, array_arg) arguments = JSON.parse(attributes[:arguments][:value]) expect(arguments[0]).to eq("string_value") - expect(arguments[1]).to include("safe_key" => "value") - expect(arguments[1]).to include("password" => "[FILTERED]") + expect(arguments[1]).to include("safe_var" => "value") + expect(arguments[1]).to include("password" => "[Filtered]") expect(arguments[2]).to eq(42) expect(arguments[3]).to eq([1, 2, 3]) end - it "handles non-array arguments gracefully" do - subscriber = described_class.new - result = subscriber.send(:filter_sensitive_arguments, "not_an_array") - expect(result).to eq([]) + it "handles mixed argument types gracefully" do + test_job_class = Class.new(ActiveJob::Base) do + def self.name + "TestJobWithMixedArgumentTypes" + end - result = subscriber.send(:filter_sensitive_arguments, nil) - expect(result).to eq([]) + def perform(*args) + end + end + + test_job_class.perform_now("short", 42, [1, 2, 3], { safe_data: "public" }) + + Sentry.get_current_client.flush + + log_event = sentry_logs.find { |log| log[:body]&.include?("Job performed") } + expect(log_event).not_to be_nil + + arguments = JSON.parse(log_event[:attributes][:arguments][:value]) + expect(arguments).to eq(["short", 42, [1, 2, 3], { "safe_data" => "public" }]) end end @@ -348,6 +363,4 @@ def perform(*args, **kwargs) expect(sentry_logs.count).to eq(initial_log_count) end end - - include_examples "parameter filtering", described_class end diff --git a/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb b/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb index 680492e97..d6f333588 100644 --- a/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb +++ b/sentry-rails/spec/sentry/rails/log_subscribers/active_record_subscriber_spec.rb @@ -4,9 +4,12 @@ RSpec.describe Sentry::Rails::LogSubscribers::ActiveRecordSubscriber do context "when logging is enabled" do + let(:send_default_pii) { false } + before do make_basic_app do |config| config.enable_logs = true + config.send_default_pii = send_default_pii config.rails.structured_logging.enabled = true config.rails.structured_logging.subscribers = { active_record: Sentry::Rails::LogSubscribers::ActiveRecordSubscriber } @@ -47,13 +50,7 @@ end context "when send_default_pii is enabled" do - before do - Sentry.configuration.send_default_pii = true - end - - after do - Sentry.configuration.send_default_pii = false - end + let(:send_default_pii) { true } it "logs SELECT queries with binds in attributes" do post = Post.create!(title: "test") @@ -77,7 +74,7 @@ expect(log_event[:attributes]["db.query.parameter.title"][:value]).to eql(post.title) expect(log_event[:attributes]["db.query.parameter.title"][:type]).to eql("string") - expect(log_event[:attributes]["db.query.parameter.created_at"][:value]).to include("2025-10-28 13:11:44") + expect(log_event[:attributes]["db.query.parameter.created_at"][:value]).to include(created_at.utc.strftime("%Y-%m-%d %H:%M:%S")) expect(log_event[:attributes]["db.query.parameter.created_at"][:type]).to eql("string") end @@ -397,6 +394,4 @@ expect(sentry_logs.count).to eq(initial_log_count) end end - - include_examples "parameter filtering", described_class end diff --git a/sentry-rails/spec/sentry/rails_spec.rb b/sentry-rails/spec/sentry/rails_spec.rb index 762c6d59c..366e2859a 100644 --- a/sentry-rails/spec/sentry/rails_spec.rb +++ b/sentry-rails/spec/sentry/rails_spec.rb @@ -109,7 +109,7 @@ before do make_basic_app do |config| config.data_collection.url_query_params.mode = :deny_list - Rails.application.config.filter_parameters << proc { |_key, _value| } + app.config.filter_parameters << proc { |_key, _value| } end end diff --git a/sentry-rails/spec/support/shared_examples_for_parameter_filter.rb b/sentry-rails/spec/support/shared_examples_for_parameter_filter.rb deleted file mode 100644 index 52f3f9d13..000000000 --- a/sentry-rails/spec/support/shared_examples_for_parameter_filter.rb +++ /dev/null @@ -1,154 +0,0 @@ -# frozen_string_literal: true - -RSpec.shared_examples "parameter filtering" do |subscriber_class| - let(:test_instance) { subscriber_class.new } - - describe "#filter_sensitive_params" do - around do |example| - original_filter_params = Rails.application.config.filter_parameters.dup - - Rails.application.config.filter_parameters.concat([ - :password, :secret, :custom_secret, :api_key, - :credit_card, :authorization, :token, :session_token - ]).uniq! - - example.run - - Rails.application.config.filter_parameters = original_filter_params - end - - context "when params is not a hash" do - it "returns empty hash for nil" do - result = test_instance.filter_sensitive_params(nil) - expect(result).to eq({}) - end - - it "returns empty hash for non-hash objects" do - result = test_instance.filter_sensitive_params("not a hash") - expect(result).to eq({}) - end - - it "returns empty hash for arrays" do - result = test_instance.filter_sensitive_params([1, 2, 3]) - expect(result).to eq({}) - end - end - - context "when params is a valid hash" do - it "preserves non-sensitive parameters" do - params = { - "name" => "John Doe", - "email" => "john@example.com", - "age" => 30, - "preferences" => { "theme" => "dark" } - } - - result = test_instance.filter_sensitive_params(params) - - expect(result).to include("name" => "John Doe") - expect(result).to include("email" => "john@example.com") - expect(result).to include("age" => 30) - expect(result).to include("preferences" => { "theme" => "dark" }) - end - - it "filters default sensitive parameters" do - params = { - "name" => "John Doe", - "password" => "secret123", - "password_confirmation" => "secret123", - "normal_param" => "safe_value" - } - - result = test_instance.filter_sensitive_params(params) - - expect(result).to include("name" => "John Doe") - expect(result).to include("normal_param" => "safe_value") - expect(result).to include("password" => "[FILTERED]") - expect(result).to include("password_confirmation" => "[FILTERED]") - end - - it "filters custom configured sensitive parameters" do - params = { - "name" => "John Doe", - "custom_secret" => "top_secret", - "api_key" => "abc123xyz", - "credit_card" => "1234-5678-9012-3456", - "authorization" => "Bearer token123", - "normal_param" => "safe_value" - } - - result = test_instance.filter_sensitive_params(params) - - expect(result).to include("name" => "John Doe") - expect(result).to include("normal_param" => "safe_value") - expect(result).to include("custom_secret" => "[FILTERED]") - expect(result).to include("api_key" => "[FILTERED]") - expect(result).to include("credit_card" => "[FILTERED]") - expect(result).to include("authorization" => "[FILTERED]") - end - - it "handles mixed sensitive and non-sensitive parameters" do - params = { - "user_id" => 123, - "username" => "johndoe", - "password" => "secret", - "session_token" => "abc123", - "preferences" => { - "notifications" => true, - "api_key" => "sensitive_key" - } - } - - result = test_instance.filter_sensitive_params(params) - - expect(result).to include("user_id" => 123) - expect(result).to include("username" => "johndoe") - expect(result).to include("password" => "[FILTERED]") - expect(result).to include("session_token" => "[FILTERED]") - expect(result).to have_key("preferences") - end - - it "returns a new hash and doesn't modify the original" do - original_params = { - "name" => "John", - "password" => "secret" - } - original_copy = original_params.dup - - result = test_instance.filter_sensitive_params(original_params) - - expect(original_params).to eq(original_copy) - expect(result).not_to equal(original_params) - end - - it "handles empty hash" do - result = test_instance.filter_sensitive_params({}) - expect(result).to eq({}) - end - end - - context "with Rails filter_parameters configuration" do - it "respects dynamically added filter parameters" do - original_filter_params = Rails.application.config.filter_parameters.dup - - begin - Rails.application.config.filter_parameters += [:dynamic_secret] - - params = { - "name" => "John", - "dynamic_secret" => "should_be_filtered", - "normal_param" => "value" - } - - result = test_instance.filter_sensitive_params(params) - - expect(result).to include("name" => "John") - expect(result).to include("normal_param" => "value") - expect(result).to include("dynamic_secret" => "[FILTERED]") - ensure - Rails.application.config.filter_parameters = original_filter_params - end - end - end - end -end diff --git a/sentry-ruby/lib/sentry/data_collection.rb b/sentry-ruby/lib/sentry/data_collection.rb index 88250a351..3c18afa04 100644 --- a/sentry-ruby/lib/sentry/data_collection.rb +++ b/sentry-ruby/lib/sentry/data_collection.rb @@ -108,7 +108,7 @@ def initialize(document:, variables:) # Filters key-value data using the default sensitive denylist. def self.filter(values) - KeyValueCollection.new(mode: :deny_list, terms: nil).filter(values) + KeyValueCollection.new(mode: :deny_list, terms: nil).filter(values, cookie: false) end # Builds data collection settings compatible with the legacy send_default_pii diff --git a/sentry-ruby/lib/sentry/data_collection/key_value_collection.rb b/sentry-ruby/lib/sentry/data_collection/key_value_collection.rb index ed911c887..658cca174 100644 --- a/sentry-ruby/lib/sentry/data_collection/key_value_collection.rb +++ b/sentry-ruby/lib/sentry/data_collection/key_value_collection.rb @@ -82,6 +82,7 @@ def terms=(terms) # @return [Hash] a new filtered hash, or an empty hash when collection is off def filter(values, cookie: false) return {} if mode == :off + return {} unless values.is_a?(Hash) values.each_with_object({}) do |(key, value), filtered| filtered[key] = safe_value?(key, cookie: cookie) ? value : FILTERED_VALUE