Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 157982b

Browse files
authored
Merge pull request #4552 from DataDog/appsec-handle-usr-login-in-kit-events
* Add handling of string keys for `Kit:AppSec::Events` * Add `ruby: <condition>` filter to scope out tests for specific Ruby version
2 parents 7014021 + 2c399f5 commit 157982b

File tree

5 files changed

+99
-6
lines changed

5 files changed

+99
-6
lines changed

lib/datadog/kit/appsec/events.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Events
1010
LOGIN_SUCCESS_EVENT = 'users.login.success'
1111
LOGIN_FAILURE_EVENT = 'users.login.failure'
1212
SIGNUP_EVENT = 'users.signup'
13+
USER_LOGIN_KEYS = ['usr.login', :'usr.login'].freeze
1314

1415
class << self
1516
# Attach login success event information to the trace
@@ -30,10 +31,11 @@ def track_login_success(trace = nil, span = nil, user:, **others)
3031
set_trace_and_span_context('track_login_success', trace, span) do |active_trace, active_span|
3132
user_options = user.dup
3233
user_id = user_options.delete(:id)
33-
user_login = user_options[:login] || others[:'usr.login'] || user_id
34+
user_login = user_options[:login] || others[:'usr.login'] || others['usr.login'] || user_id
3435

3536
raise ArgumentError, 'missing required key: :user => { :id }' if user_id.nil?
3637

38+
others = others.reject { |key, _| USER_LOGIN_KEYS.include?(key) }
3739
others[:'usr.login'] = user_login
3840
track(LOGIN_SUCCESS_EVENT, active_trace, active_span, **others)
3941

@@ -58,7 +60,7 @@ def track_login_success(trace = nil, span = nil, user:, **others)
5860
# event information to attach to the trace.
5961
def track_login_failure(trace = nil, span = nil, user_exists:, user_id: nil, **others)
6062
set_trace_and_span_context('track_login_failure', trace, span) do |active_trace, active_span|
61-
others[:'usr.login'] = user_id if user_id && !others.key?(:'usr.login')
63+
others[:'usr.login'] = user_id if user_id && !others.key?(:'usr.login') && !others.key?('usr.login')
6264
track(LOGIN_FAILURE_EVENT, active_trace, active_span, **others)
6365

6466
active_span.set_tag('appsec.events.users.login.failure.usr.id', user_id) if user_id
@@ -84,10 +86,11 @@ def track_signup(trace = nil, span = nil, user:, **others)
8486
set_trace_and_span_context('track_signup', trace, span) do |active_trace, active_span|
8587
user_options = user.dup
8688
user_id = user_options.delete(:id)
87-
user_login = user_options[:login] || others[:'usr.login'] || user_id
89+
user_login = user_options[:login] || others[:'usr.login'] || others['usr.login'] || user_id
8890

8991
raise ArgumentError, 'missing required key: :user => { :id }' if user_id.nil?
9092

93+
others = others.reject { |key, _| USER_LOGIN_KEYS.include?(key) }
9194
others[:'usr.login'] = user_login
9295
track(SIGNUP_EVENT, active_trace, active_span, **others)
9396

sig/datadog/kit/appsec/events.rbs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,26 @@ module Datadog
33
module AppSec
44
module Events
55
LOGIN_SUCCESS_EVENT: ::String
6+
67
LOGIN_FAILURE_EVENT: ::String
78

8-
def self.track_login_success: (Datadog::Tracing::TraceOperation trace, user: Hash[::Symbol, ::String | nil], **::Hash[::Symbol, ::String | nil] others) -> void
9+
SIGNUP_EVENT: ::String
10+
11+
USER_LOGIN_KEYS: Array[String | Symbol]
12+
13+
def self.track_login_success: (?Tracing::TraceOperation? trace, ?Tracing::SpanOperation? span, user: Hash[Symbol, String], **Hash[Symbol | String, String] others) -> void
14+
15+
def self.track_login_failure: (?Tracing::TraceOperation? trace, ?Tracing::SpanOperation? span, user_exists: bool, ?user_id: String?, **Hash[Symbol | String, String] others) -> void
16+
17+
def self.track_signup: (?Tracing::TraceOperation? trace, ?Tracing::SpanOperation? span, user: Hash[Symbol, String], **Hash[Symbol | String, String] others) -> void
18+
19+
def self.track: (String event, ?Tracing::TraceOperation? trace, ?Tracing::SpanOperation? span, **Hash[Symbol, String] others) -> void
20+
21+
private
922

10-
def self.track_login_failure: (Datadog::Tracing::TraceOperation trace, user_id: ::String, user_exists: bool, **::Hash[::Symbol, ::String | nil] others) -> void
23+
def self.set_trace_and_span_context: (String method, ?Tracing::TraceOperation? trace, ?Tracing::SpanOperation? span) { (Tracing::TraceOperation, Tracing::SpanOperation) -> void } -> void
1124

12-
def self.track: (::String | ::Symbol event, Datadog::Tracing::TraceOperation trace, **::Hash[::Symbol, ::String | nil] others) -> void
25+
def self.check_trace_span_integrity: (Tracing::TraceOperation trace, Tracing::SpanOperation span) -> void
1326
end
1427
end
1528
end

spec/datadog/kit/appsec/events_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@
9393
end
9494
end
9595

96+
it 'sets additional user login data from other string keys as tags', ruby: '>= 2.7' do
97+
trace_op.measure('root') do |span, _|
98+
expect { described_class.track_login_success(trace_op, user: { id: '42' }, 'usr.login' => 'hey') }
99+
.to change { span.tags }.to include(
100+
'usr.id' => '42',
101+
'usr.login' => 'hey',
102+
'appsec.events.users.login.success.usr.login' => 'hey'
103+
)
104+
end
105+
end
106+
96107
it 'sets event tracking key on trace' do
97108
trace_op.measure('root') do |span, _|
98109
expect { described_class.track_login_success(trace_op, user: { id: '42' }) }
@@ -181,6 +192,13 @@
181192
end
182193
end
183194

195+
it 'sets additional user login data from other string keys as tags', ruby: '>= 2.7' do
196+
trace_op.measure('root') do |span, _|
197+
expect { described_class.track_login_failure(trace_op, user_id: '42', user_exists: true, 'usr.login' => 'hey') }
198+
.to change { span.tags }.to include('appsec.events.users.login.failure.usr.login' => 'hey')
199+
end
200+
end
201+
184202
it 'sets event tracking key on trace' do
185203
trace_op.measure('root') do |span, _trace|
186204
described_class.track_login_failure(trace_op, user_id: '42', user_exists: true)
@@ -286,6 +304,17 @@
286304
end
287305
end
288306

307+
it 'sets additional user login data from other string keys as tags', ruby: '>= 2.7' do
308+
trace_op.measure('root') do |span, _|
309+
expect { described_class.track_signup(trace_op, user: { id: '42' }, 'usr.login' => 'hey') }
310+
.to change { span.tags }.to include(
311+
'usr.id' => '42',
312+
'usr.login' => 'hey',
313+
'appsec.events.users.signup.usr.login' => 'hey'
314+
)
315+
end
316+
end
317+
289318
it 'sets additional user login data as tags with user data priority' do
290319
trace_op.measure('root') do |span, _|
291320
expect { described_class.track_signup(trace_op, user: { id: '42', login: 'hey' }, 'usr.login': 'extra') }

spec/spec_helper.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,29 @@
103103
config.pending_failure_output = :full
104104
end
105105

106+
# Guard-clause to skip tests that require a specific Ruby version.
107+
# Should work on anything that supports filters, i.e it/describe/context.
108+
#
109+
# Examples:
110+
#
111+
# 1. Guard with explicit matcher `>` (greater than)
112+
# Supported operators: `>`, `>=`, `==`, `!=`, `<`, `<=`
113+
#
114+
# WARNING: Space between operator and version is required.
115+
#
116+
# it 'runs only for specific Ruby version', ruby: '> 2.7' do
117+
# expect(something).to be_good
118+
# end
119+
#
120+
# 2. Guard with implicit matcher `==` (equal to)
121+
#
122+
# it 'runs only for Ruby 2.7.x', ruby: '2.7' do
123+
# expect(something).to be_good
124+
# end
125+
config.before(:each, ruby: ->(value) { !PlatformHelpers.ruby_version_matches?(value) }) do |example|
126+
skip "Test requires Ruby #{example.metadata[:ruby]}"
127+
end
128+
106129
config.before(:example, ractors: true) do
107130
unless config.filter_manager.inclusions[:ractors]
108131
skip 'Skipping ractor tests. Use rake spec:profiling:ractors or pass -t ractors to rspec to run.'

spec/support/platform_helpers.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
require 'os'
44

55
module PlatformHelpers
6+
EQUALITY_OPERATOR = '=='
7+
ALLOWED_COMPARISON_OPERATORS = %w[> >= == != < <=].freeze
8+
69
module_function
710

811
# Ruby runtime engines
@@ -24,6 +27,28 @@ def engine_version
2427
Gem::Version.new(version)
2528
end
2629

30+
def ruby_version_matches?(matcher_with_ruby_version)
31+
ruby_version = Gem::Version.new(RUBY_VERSION)
32+
operator, guard_version = matcher_with_ruby_version.split(' ', 2).tap { |array| array.unshift('==') if array.size == 1 }
33+
34+
unless ALLOWED_COMPARISON_OPERATORS.include?(operator)
35+
message = "Unsupported operator: #{operator}. Supported operators: #{ALLOWED_COMPARISON_OPERATORS.join(', ')}"
36+
raise ArgumentError, message
37+
end
38+
39+
unless Gem::Version.correct?(guard_version)
40+
message = "Invalid version: #{guard_version}. Make sure to add space between operator and version."
41+
raise ArgumentError, message
42+
end
43+
44+
if operator == EQUALITY_OPERATOR && guard_version.count('.') < 3
45+
version = Gem::Version.new("#{guard_version}.0")
46+
(version...version.bump).cover?(ruby_version)
47+
else
48+
ruby_version.send(operator, Gem::Version.new(guard_version))
49+
end
50+
end
51+
2752
# Operating systems
2853

2954
def linux?

0 commit comments

Comments
 (0)