diff --git a/gemfiles/ruby_3.3_rails_app.gemfile.lock b/gemfiles/ruby_3.3_rails_app.gemfile.lock index e4d110d54e6..acca9a22e4c 100644 --- a/gemfiles/ruby_3.3_rails_app.gemfile.lock +++ b/gemfiles/ruby_3.3_rails_app.gemfile.lock @@ -370,4 +370,4 @@ DEPENDENCIES webrick (>= 1.7.0) BUNDLED WITH - 2.6.3 + 2.5.21 diff --git a/lib/datadog/appsec/contrib/devise/configuration.rb b/lib/datadog/appsec/contrib/devise/configuration.rb index 852409c37bf..678f0897dd9 100644 --- a/lib/datadog/appsec/contrib/devise/configuration.rb +++ b/lib/datadog/appsec/contrib/devise/configuration.rb @@ -7,10 +7,26 @@ module Devise # A temporary configuration module to accomodate new RFC changes. # NOTE: DEV-3 Remove module module Configuration + MODES_CONVERSION_RULES = { + track_user_into_auto_instrumentation: { + AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE => + AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE, + AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE => + AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE + }.freeze, + auto_instrumentation_into_track_user: { + AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE => + AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE, + AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE => + AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE + }.freeze + }.freeze + module_function # NOTE: DEV-3 Replace method use with `auto_user_instrumentation.enabled?` def auto_user_instrumentation_enabled? + Datadog.configuration.appsec.auto_user_instrumentation.mode unless Datadog.configuration.appsec.auto_user_instrumentation.options[:mode].default_precedence? return Datadog.configuration.appsec.auto_user_instrumentation.enabled? end @@ -20,18 +36,41 @@ def auto_user_instrumentation_enabled? # NOTE: DEV-3 Replace method use with `auto_user_instrumentation.mode` def auto_user_instrumentation_mode - unless Datadog.configuration.appsec.auto_user_instrumentation.options[:mode].default_precedence? - return Datadog.configuration.appsec.auto_user_instrumentation.mode + configuration = Datadog.configuration.appsec + + # NOTE: Reading both to trigger precedence set + configuration.auto_user_instrumentation.mode + configuration.track_user_events.mode + + if !configuration.auto_user_instrumentation.options[:mode].default_precedence? && + configuration.track_user_events.options[:mode].default_precedence? + return configuration.auto_user_instrumentation.mode end - case Datadog.configuration.appsec.track_user_events.mode - when AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE - AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE - when AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE - AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE - else - Datadog.configuration.appsec.auto_user_instrumentation.mode + if !configuration.track_user_events.options[:mode].default_precedence? && + configuration.auto_user_instrumentation.options[:mode].default_precedence? + return MODES_CONVERSION_RULES[:track_user_into_auto_instrumentation].fetch( + configuration.track_user_events.mode, configuration.auto_user_instrumentation.mode + ) end + + if configuration.auto_user_instrumentation.options[:mode].default_precedence? && + configuration.track_user_events.options[:mode].default_precedence? + return configuration.auto_user_instrumentation.mode + end + + if configuration.auto_user_instrumentation.mode == AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE || + configuration.track_user_events.mode == AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE + return AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE + end + + AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE + end + + # NOTE: Remove in next version of tracking + def track_user_events_mode + MODES_CONVERSION_RULES[:auto_instrumentation_into_track_user] + .fetch(auto_user_instrumentation_mode, Datadog.configuration.appsec.auto_user_instrumentation.mode) end end end diff --git a/lib/datadog/appsec/contrib/devise/tracking.rb b/lib/datadog/appsec/contrib/devise/tracking.rb index 620ab0fd8b3..ffd27b4e8c6 100644 --- a/lib/datadog/appsec/contrib/devise/tracking.rb +++ b/lib/datadog/appsec/contrib/devise/tracking.rb @@ -40,7 +40,7 @@ def self.track(event, trace, span, **others) return if trace.nil? || span.nil? span.set_tag("appsec.events.#{event}.track", 'true') - span.set_tag("_dd.appsec.events.#{event}.auto.mode", Configuration.auto_user_instrumentation_mode) + span.set_tag("_dd.appsec.events.#{event}.auto.mode", Configuration.track_user_events_mode) others.each do |k, v| raise ArgumentError, 'key cannot be :track' if k.to_sym == :track diff --git a/sig/datadog/appsec/contrib/devise/configuration.rbs b/sig/datadog/appsec/contrib/devise/configuration.rbs index c7f9be9643c..21ffd8a6455 100644 --- a/sig/datadog/appsec/contrib/devise/configuration.rbs +++ b/sig/datadog/appsec/contrib/devise/configuration.rbs @@ -6,6 +6,8 @@ module Datadog def self?.auto_user_instrumentation_enabled?: () -> bool def self?.auto_user_instrumentation_mode: () -> ::String + + def self?.track_user_events_mode_mode: () -> ::String end end end diff --git a/spec/datadog/appsec/contrib/devise/configuration_spec.rb b/spec/datadog/appsec/contrib/devise/configuration_spec.rb index 02dbc6c2de4..f1d3131b8d4 100644 --- a/spec/datadog/appsec/contrib/devise/configuration_spec.rb +++ b/spec/datadog/appsec/contrib/devise/configuration_spec.rb @@ -12,21 +12,13 @@ describe '.auto_user_instrumentation_enabled?' do context 'when auto_user_instrumentation is explicitly disabled and track_user_events is default' do - before do - settings.appsec.auto_user_instrumentation.mode = 'disabled' - # NOTE: triggering default value - settings.appsec.track_user_events.enabled - end + before { settings.appsec.auto_user_instrumentation.mode = 'disabled' } it { expect(described_class).not_to be_auto_user_instrumentation_enabled } end context 'when track_user_events is explicitly set and auto_user_instrumentation is default' do - before do - settings.appsec.track_user_events.enabled = false - # NOTE: triggering default value - settings.appsec.auto_user_instrumentation.mode - end + before { settings.appsec.track_user_events.enabled = false } it { expect(described_class).not_to be_auto_user_instrumentation_enabled } end @@ -70,26 +62,18 @@ describe '.auto_user_instrumentation_mode' do context 'when auto_user_instrumentation is explicitly set and track_user_events is default' do - before do - settings.appsec.auto_user_instrumentation.mode = 'identification' - # NOTE: triggering default value - settings.appsec.track_user_events.mode - end + before { settings.appsec.auto_user_instrumentation.mode = 'identification' } it { expect(described_class.auto_user_instrumentation_mode).to eq('identification') } end context 'when track_user_events is explicitly set and auto_user_instrumentation is default' do - before do - settings.appsec.track_user_events.mode = 'safe' - # NOTE: triggering default value - settings.appsec.auto_user_instrumentation.mode - end + before { settings.appsec.track_user_events.mode = 'safe' } it { expect(described_class.auto_user_instrumentation_mode).to eq('anonymization') } end - context 'when auto_user_instrumentation is identification and track_user_events is extended' do + context 'when auto_user_instrumentation is ident and track_user_events is extended' do before do settings.appsec.auto_user_instrumentation.mode = 'identification' settings.appsec.track_user_events.mode = 'extended' @@ -98,7 +82,7 @@ it { expect(described_class.auto_user_instrumentation_mode).to eq('identification') } end - context 'when auto_user_instrumentation is identification and track_user_events is safe' do + context 'when auto_user_instrumentation is ident and track_user_events is safe' do before do settings.appsec.auto_user_instrumentation.mode = 'identification' settings.appsec.track_user_events.mode = 'safe' @@ -107,16 +91,16 @@ it { expect(described_class.auto_user_instrumentation_mode).to eq('identification') } end - context 'when auto_user_instrumentation is anonymization and track_user_events is extended' do + context 'when auto_user_instrumentation is anon and track_user_events is extended' do before do settings.appsec.auto_user_instrumentation.mode = 'anonymization' settings.appsec.track_user_events.mode = 'extended' end - it { expect(described_class.auto_user_instrumentation_mode).to eq('anonymization') } + it { expect(described_class.auto_user_instrumentation_mode).to eq('identification') } end - context 'when auto_user_instrumentation is anonymization and track_user_events is safe' do + context 'when auto_user_instrumentation is anon and track_user_events is safe' do before do settings.appsec.auto_user_instrumentation.mode = 'anonymization' settings.appsec.track_user_events.mode = 'safe' @@ -125,7 +109,7 @@ it { expect(described_class.auto_user_instrumentation_mode).to eq('anonymization') } end - context 'when auto_user_instrumentation is identification and track_user_events is invalid' do + context 'when auto_user_instrumentation is ident and track_user_events is invalid' do before do settings.appsec.auto_user_instrumentation.mode = 'anonymization' settings.appsec.track_user_events.mode = 'unknown' @@ -134,4 +118,37 @@ it { expect(described_class.auto_user_instrumentation_mode).to eq('anonymization') } end end + + describe '.track_user_events_mode' do + context 'when track_user_events is default and auto_user_instrumentation is default' do + it { expect(described_class.track_user_events_mode).to eq('extended') } + end + + context 'when track_user_events is explicitly set to safe and auto_user_instrumentation is set to ident' do + before do + settings.appsec.auto_user_instrumentation.mode = 'identification' + settings.appsec.track_user_events.mode = 'safe' + end + + it { expect(described_class.track_user_events_mode).to eq('extended') } + end + + context 'when auto_user_instrumentation is explicitly set to ident and track_user_events is default' do + before { settings.appsec.auto_user_instrumentation.mode = 'identification' } + + it { expect(described_class.track_user_events_mode).to eq('extended') } + end + + context 'when auto_user_instrumentation is explicitly set to anon and track_user_events is default' do + before { settings.appsec.auto_user_instrumentation.mode = 'anonymization' } + + it { expect(described_class.track_user_events_mode).to eq('safe') } + end + + context 'when track_user_events is explicitly set and auto_user_instrumentation is default' do + before { settings.appsec.track_user_events.mode = 'safe' } + + it { expect(described_class.track_user_events_mode).to eq('safe') } + end + end end diff --git a/spec/datadog/appsec/contrib/integration/devise_auto_login_signup_events_spec.rb b/spec/datadog/appsec/contrib/integration/devise_auto_login_signup_events_spec.rb index e8ec05694ea..76a6f7fecc5 100644 --- a/spec/datadog/appsec/contrib/integration/devise_auto_login_signup_events_spec.rb +++ b/spec/datadog/appsec/contrib/integration/devise_auto_login_signup_events_spec.rb @@ -203,7 +203,7 @@ def index expect(http_service_entry_trace.sampling_priority).to eq(Datadog::Tracing::Sampling::Ext::Priority::USER_KEEP) expect(http_service_entry_span.tags['appsec.events.users.login.success.track']).to eq('true') - expect(http_service_entry_span.tags['_dd.appsec.events.users.login.success.auto.mode']).to eq('identification') + expect(http_service_entry_span.tags['_dd.appsec.events.users.login.success.auto.mode']).to eq('extended') expect(http_service_entry_span.tags['usr.id']).to eq('1') # NOTE: not implemented yet @@ -223,7 +223,7 @@ def index expect(http_service_entry_trace.sampling_priority).to eq(Datadog::Tracing::Sampling::Ext::Priority::USER_KEEP) expect(http_service_entry_span.tags['appsec.events.users.login.failure.track']).to eq('true') - expect(http_service_entry_span.tags['_dd.appsec.events.users.login.failure.auto.mode']).to eq('identification') + expect(http_service_entry_span.tags['_dd.appsec.events.users.login.failure.auto.mode']).to eq('extended') expect(http_service_entry_span.tags['appsec.events.users.login.failure.usr.exists']).to eq('false') # NOTE: not implemented yet @@ -255,7 +255,7 @@ def index expect(http_service_entry_trace.sampling_priority).to eq(Datadog::Tracing::Sampling::Ext::Priority::USER_KEEP) expect(http_service_entry_span.tags['appsec.events.users.signup.track']).to eq('true') - expect(http_service_entry_span.tags['_dd.appsec.events.users.signup.auto.mode']).to eq('identification') + expect(http_service_entry_span.tags['_dd.appsec.events.users.signup.auto.mode']).to eq('extended') # NOTE: not implemented yet # expect(http_service_entry_span.tags['appsec.events.users.signup.usr.login']).to eq('john.doe@example.com')