datadog 2.15.0 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -2
  3. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
  5. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  6. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  7. data/ext/libdatadog_api/crashtracker.c +1 -9
  8. data/ext/libdatadog_api/crashtracker.h +5 -0
  9. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  10. data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
  11. data/ext/libdatadog_api/init.c +15 -0
  12. data/ext/libdatadog_api/library_config.c +122 -0
  13. data/ext/libdatadog_api/library_config.h +19 -0
  14. data/ext/libdatadog_api/process_discovery.c +117 -0
  15. data/ext/libdatadog_api/process_discovery.h +5 -0
  16. data/lib/datadog/appsec/actions_handler.rb +3 -2
  17. data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
  18. data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
  19. data/lib/datadog/appsec/autoload.rb +1 -1
  20. data/lib/datadog/appsec/component.rb +11 -4
  21. data/lib/datadog/appsec/configuration/settings.rb +31 -18
  22. data/lib/datadog/appsec/context.rb +1 -1
  23. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  24. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  25. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  26. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
  27. data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
  28. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  29. data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
  30. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
  31. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  32. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  33. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  34. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  35. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  36. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
  38. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
  40. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  41. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  42. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  43. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  44. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  45. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  46. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  47. data/lib/datadog/appsec/event.rb +85 -95
  48. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
  49. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  50. data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
  51. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  52. data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
  53. data/lib/datadog/appsec/processor.rb +1 -1
  54. data/lib/datadog/appsec/remote.rb +14 -13
  55. data/lib/datadog/appsec/response.rb +6 -6
  56. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  57. data/lib/datadog/appsec/security_event.rb +39 -0
  58. data/lib/datadog/appsec.rb +1 -1
  59. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  60. data/lib/datadog/core/configuration/components.rb +19 -10
  61. data/lib/datadog/core/configuration/option.rb +61 -25
  62. data/lib/datadog/core/configuration/settings.rb +10 -0
  63. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  64. data/lib/datadog/core/configuration.rb +24 -0
  65. data/lib/datadog/core/crashtracking/component.rb +1 -9
  66. data/lib/datadog/core/environment/git.rb +1 -0
  67. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  68. data/lib/datadog/core/metrics/client.rb +8 -7
  69. data/lib/datadog/core/process_discovery.rb +32 -0
  70. data/lib/datadog/core/remote/client.rb +7 -0
  71. data/lib/datadog/core/runtime/metrics.rb +1 -1
  72. data/lib/datadog/core/telemetry/component.rb +60 -50
  73. data/lib/datadog/core/telemetry/emitter.rb +17 -11
  74. data/lib/datadog/core/telemetry/event.rb +7 -4
  75. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  76. data/lib/datadog/core/telemetry/request.rb +3 -3
  77. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  78. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  79. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  80. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  81. data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
  82. data/lib/datadog/core/telemetry/worker.rb +45 -0
  83. data/lib/datadog/core/utils/time.rb +12 -0
  84. data/lib/datadog/core/workers/async.rb +20 -2
  85. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  86. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  87. data/lib/datadog/core.rb +8 -0
  88. data/lib/datadog/di/boot.rb +34 -0
  89. data/lib/datadog/di/remote.rb +2 -0
  90. data/lib/datadog/di.rb +5 -32
  91. data/lib/datadog/error_tracking/collector.rb +87 -0
  92. data/lib/datadog/error_tracking/component.rb +167 -0
  93. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  94. data/lib/datadog/error_tracking/configuration.rb +11 -0
  95. data/lib/datadog/error_tracking/ext.rb +18 -0
  96. data/lib/datadog/error_tracking/extensions.rb +16 -0
  97. data/lib/datadog/error_tracking/filters.rb +77 -0
  98. data/lib/datadog/error_tracking.rb +18 -0
  99. data/lib/datadog/kit/identity.rb +1 -1
  100. data/lib/datadog/profiling/exporter.rb +1 -1
  101. data/lib/datadog/tracing/analytics.rb +1 -1
  102. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  103. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  104. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  105. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  106. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  107. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  108. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  109. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  110. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  111. data/lib/datadog/tracing/span_operation.rb +38 -14
  112. data/lib/datadog/tracing/trace_operation.rb +15 -7
  113. data/lib/datadog/tracing/tracer.rb +7 -3
  114. data/lib/datadog/tracing/utils.rb +1 -1
  115. data/lib/datadog/version.rb +1 -1
  116. data/lib/datadog.rb +2 -3
  117. metadata +34 -8
  118. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  119. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  120. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  121. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -4,7 +4,7 @@ if %w[1 true].include?((ENV['DD_APPSEC_ENABLED'] || '').downcase)
4
4
  begin
5
5
  require_relative 'contrib/auto_instrument'
6
6
  Datadog::AppSec::Contrib::AutoInstrument.patch_all
7
- rescue StandardError => e
7
+ rescue => e
8
8
  Kernel.warn(
9
9
  '[datadog] AppSec failed to instrument. No security check will be performed. error: ' \
10
10
  " #{e.class.name} #{e.message}"
@@ -13,7 +13,7 @@ module Datadog
13
13
  def build_appsec_component(settings, telemetry:)
14
14
  return if !settings.respond_to?(:appsec) || !settings.appsec.enabled
15
15
 
16
- ffi_version = Gem.loaded_specs['ffi'] && Gem.loaded_specs['ffi'].version
16
+ ffi_version = Gem.loaded_specs['ffi']&.version
17
17
  unless ffi_version
18
18
  Datadog.logger.warn('FFI gem is not loaded, AppSec will be disabled.')
19
19
  telemetry.error('AppSec: Component not loaded, due to missing FFI gem')
@@ -61,9 +61,16 @@ module Datadog
61
61
 
62
62
  exclusions = AppSec::Processor::RuleLoader.load_exclusions(ip_passlist: settings.appsec.ip_passlist)
63
63
 
64
+ # NOTE: This is a temporary solution before the RuleMerger refactoring
65
+ # with new RemoteConfig setup
66
+ processors = rules['processors']
67
+ scanners = rules['scanners']
68
+
64
69
  ruleset = AppSec::Processor::RuleMerger.merge(
65
70
  rules: [rules],
66
71
  data: data,
72
+ scanners: scanners,
73
+ processors: processors,
67
74
  exclusions: exclusions,
68
75
  telemetry: telemetry
69
76
  )
@@ -88,13 +95,13 @@ module Datadog
88
95
  @mutex.synchronize do
89
96
  new_processor = Processor.new(ruleset: ruleset, telemetry: telemetry)
90
97
 
91
- if new_processor && new_processor.ready?
98
+ if new_processor&.ready?
92
99
  old_processor = @processor
93
100
 
94
101
  @telemetry = telemetry
95
102
  @processor = new_processor
96
103
 
97
- old_processor.finalize if old_processor
104
+ old_processor&.finalize
98
105
  end
99
106
  end
100
107
  end
@@ -105,7 +112,7 @@ module Datadog
105
112
 
106
113
  def shutdown!
107
114
  @mutex.synchronize do
108
- if processor && processor.ready?
115
+ if processor&.ready?
109
116
  processor.finalize
110
117
  @processor = nil
111
118
  end
@@ -131,9 +131,12 @@ module Datadog
131
131
  o.type :string, nilable: true
132
132
  o.setter do |value|
133
133
  if value
134
- raise(ArgumentError, "appsec.templates.html: file not found: #{value}") unless File.exist?(value)
134
+ unless File.exist?(value)
135
+ raise(ArgumentError,
136
+ "appsec.templates.html: file not found: #{value}")
137
+ end
135
138
 
136
- File.open(value, 'rb', &:read) || ''
139
+ File.binread(value) || ''
137
140
  end
138
141
  end
139
142
  end
@@ -143,9 +146,12 @@ module Datadog
143
146
  o.type :string, nilable: true
144
147
  o.setter do |value|
145
148
  if value
146
- raise(ArgumentError, "appsec.templates.json: file not found: #{value}") unless File.exist?(value)
149
+ unless File.exist?(value)
150
+ raise(ArgumentError,
151
+ "appsec.templates.json: file not found: #{value}")
152
+ end
147
153
 
148
- File.open(value, 'rb', &:read) || ''
154
+ File.binread(value) || ''
149
155
  end
150
156
  end
151
157
  end
@@ -155,9 +161,12 @@ module Datadog
155
161
  o.type :string, nilable: true
156
162
  o.setter do |value|
157
163
  if value
158
- raise(ArgumentError, "appsec.templates.text: file not found: #{value}") unless File.exist?(value)
164
+ unless File.exist?(value)
165
+ raise(ArgumentError,
166
+ "appsec.templates.text: file not found: #{value}")
167
+ end
159
168
 
160
- File.open(value, 'rb', &:read) || ''
169
+ File.binread(value) || ''
161
170
  end
162
171
  end
163
172
  end
@@ -237,7 +246,7 @@ module Datadog
237
246
 
238
247
  Datadog.logger.warn(
239
248
  'The appsec.auto_user_instrumentation.mode value provided is not supported. ' \
240
- "Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(' | ')}. " \
249
+ "Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(" | ")}. " \
241
250
  "Using value: #{DISABLED_AUTO_USER_INSTRUMENTATION_MODE}."
242
251
  )
243
252
 
@@ -259,11 +268,13 @@ module Datadog
259
268
  APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES.include?(env_value.strip.downcase)
260
269
  end
261
270
  end
262
- o.after_set do
263
- Core.log_deprecation(key: :appsec_track_user_events_enabled) do
264
- 'The appsec.track_user_events.enabled setting has been deprecated for removal. ' \
265
- 'Please remove it from your Datadog.configure block and use ' \
266
- 'appsec.auto_user_instrumentation.mode instead.'
271
+ o.after_set do |_, _, precedence|
272
+ unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
273
+ Core.log_deprecation(key: :appsec_track_user_events_enabled) do
274
+ 'The appsec.track_user_events.enabled setting is deprecated. ' \
275
+ 'Please remove it from your Datadog.configure block and use ' \
276
+ 'appsec.auto_user_instrumentation.mode instead.'
277
+ end
267
278
  end
268
279
  end
269
280
  end
@@ -280,18 +291,20 @@ module Datadog
280
291
  else
281
292
  Datadog.logger.warn(
282
293
  'The appsec.track_user_events.mode value provided is not supported.' \
283
- "Supported values are: #{APPSEC_VALID_TRACK_USER_EVENTS_MODE.join(' | ')}." \
294
+ "Supported values are: #{APPSEC_VALID_TRACK_USER_EVENTS_MODE.join(" | ")}." \
284
295
  "Using default value: #{SAFE_TRACK_USER_EVENTS_MODE}."
285
296
  )
286
297
 
287
298
  SAFE_TRACK_USER_EVENTS_MODE
288
299
  end
289
300
  end
290
- o.after_set do
291
- Core.log_deprecation(key: :appsec_track_user_events_mode) do
292
- 'The appsec.track_user_events.mode setting has been deprecated for removal. ' \
293
- 'Please remove it from your Datadog.configure block and use ' \
294
- 'appsec.auto_user_instrumentation.mode instead.'
301
+ o.after_set do |_, _, precedence|
302
+ unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
303
+ Core.log_deprecation(key: :appsec_track_user_events_mode) do
304
+ 'The appsec.track_user_events.mode setting is deprecated. ' \
305
+ 'Please remove it from your Datadog.configure block and use ' \
306
+ 'appsec.auto_user_instrumentation.mode instead.'
307
+ end
295
308
  end
296
309
  end
297
310
  end
@@ -56,7 +56,7 @@ module Datadog
56
56
  end
57
57
 
58
58
  def extract_schema
59
- @waf_runner.run({ 'waf.context.processor' => { 'extract-schema' => true } }, {})
59
+ @waf_runner.run({'waf.context.processor' => {'extract-schema' => true}}, {})
60
60
  end
61
61
 
62
62
  def export_metrics
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../../event'
4
+ require_relative '../../security_event'
5
+
3
6
  module Datadog
4
7
  module AppSec
5
8
  module Contrib
@@ -28,18 +31,13 @@ module Datadog
28
31
  result = context.run_rasp(Ext::RASP_SQLI, {}, ephemeral_data, waf_timeout)
29
32
 
30
33
  if result.match?
31
- Datadog::AppSec::Event.tag_and_keep!(context, result)
32
-
33
- event = {
34
- waf_result: result,
35
- trace: context.trace,
36
- span: context.span,
37
- sql: sql,
38
- actions: result.actions
39
- }
40
- context.events << event
41
-
42
- ActionsHandler.handle(result.actions)
34
+ AppSec::Event.tag_and_keep!(context, result)
35
+
36
+ context.events.push(
37
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
38
+ )
39
+
40
+ AppSec::ActionsHandler.handle(result.actions)
43
41
  end
44
42
  end
45
43
 
@@ -16,7 +16,7 @@ module Datadog
16
16
  register_as :active_record, auto_patch: true
17
17
 
18
18
  def self.version
19
- Gem.loaded_specs['activerecord'] && Gem.loaded_specs['activerecord'].version
19
+ Gem.loaded_specs['activerecord']&.version
20
20
  end
21
21
 
22
22
  def self.loaded?
@@ -53,43 +53,43 @@ module Datadog
53
53
 
54
54
  def patch_sqlite3_adapter
55
55
  instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new('7.1')
56
- Instrumentation::InternalExecQueryAdapterPatch
57
- elsif ::ActiveRecord.gem_version.segments.first == 4
58
- Instrumentation::Rails4ExecQueryAdapterPatch
59
- else
60
- Instrumentation::ExecQueryAdapterPatch
61
- end
56
+ Instrumentation::InternalExecQueryAdapterPatch
57
+ elsif ::ActiveRecord.gem_version.segments.first == 4
58
+ Instrumentation::Rails4ExecQueryAdapterPatch
59
+ else
60
+ Instrumentation::ExecQueryAdapterPatch
61
+ end
62
62
 
63
63
  ::ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(instrumentation_module)
64
64
  end
65
65
 
66
66
  def patch_mysql2_adapter
67
67
  instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new('7.1')
68
- Instrumentation::InternalExecQueryAdapterPatch
69
- elsif ::ActiveRecord.gem_version.segments.first == 4
70
- Instrumentation::Rails4ExecQueryAdapterPatch
71
- else
72
- Instrumentation::ExecQueryAdapterPatch
73
- end
68
+ Instrumentation::InternalExecQueryAdapterPatch
69
+ elsif ::ActiveRecord.gem_version.segments.first == 4
70
+ Instrumentation::Rails4ExecQueryAdapterPatch
71
+ else
72
+ Instrumentation::ExecQueryAdapterPatch
73
+ end
74
74
 
75
75
  ::ActiveRecord::ConnectionAdapters::Mysql2Adapter.prepend(instrumentation_module)
76
76
  end
77
77
 
78
78
  def patch_postgresql_adapter
79
79
  instrumentation_module = if ::ActiveRecord.gem_version.segments.first == 4
80
- Instrumentation::Rails4ExecuteAndClearAdapterPatch
81
- else
82
- Instrumentation::ExecuteAndClearAdapterPatch
83
- end
80
+ Instrumentation::Rails4ExecuteAndClearAdapterPatch
81
+ else
82
+ Instrumentation::ExecuteAndClearAdapterPatch
83
+ end
84
84
 
85
85
  if defined?(::ActiveRecord::ConnectionAdapters::JdbcAdapter)
86
86
  instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new('7.1')
87
- Instrumentation::InternalExecQueryAdapterPatch
88
- elsif ::ActiveRecord.gem_version.segments.first == 4
89
- Instrumentation::Rails4ExecQueryAdapterPatch
90
- else
91
- Instrumentation::ExecQueryAdapterPatch
92
- end
87
+ Instrumentation::InternalExecQueryAdapterPatch
88
+ elsif ::ActiveRecord.gem_version.segments.first == 4
89
+ Instrumentation::Rails4ExecQueryAdapterPatch
90
+ else
91
+ Instrumentation::ExecQueryAdapterPatch
92
+ end
93
93
  end
94
94
 
95
95
  ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(instrumentation_module)
@@ -57,9 +57,8 @@ module Datadog
57
57
  def find_devise_scope(object)
58
58
  return if ::Devise.mappings.count == 1
59
59
 
60
- @devise_scopes[object.class.name] ||= begin
61
- ::Devise.mappings.each_value.find { |mapping| mapping.class_name == object.class.name }&.name
62
- end
60
+ @devise_scopes[object.class.name] ||= ::Devise.mappings
61
+ .each_value.find { |mapping| mapping.class_name == object.class.name }&.name
63
62
  end
64
63
 
65
64
  def transform(value)
@@ -18,6 +18,7 @@ module Datadog
18
18
  TAG_DD_LOGIN_FAILURE_MODE = '_dd.appsec.events.users.login.failure.auto.mode'
19
19
 
20
20
  TAG_USR_ID = 'usr.id'
21
+ TAG_SESSION_ID = 'usr.session_id'
21
22
  TAG_SIGNUP_TRACK = 'appsec.events.users.signup.track'
22
23
  TAG_SIGNUP_USR_ID = 'appsec.events.users.signup.usr.id'
23
24
  TAG_SIGNUP_USR_LOGIN = 'appsec.events.users.signup.usr.login'
@@ -16,7 +16,7 @@ module Datadog
16
16
  register_as :devise, auto_patch: true
17
17
 
18
18
  def self.version
19
- Gem.loaded_specs['devise'] && Gem.loaded_specs['devise'].version
19
+ Gem.loaded_specs['devise']&.version
20
20
  end
21
21
 
22
22
  def self.loaded?
@@ -30,11 +30,9 @@ module Datadog
30
30
  def patch
31
31
  ::ActiveSupport.on_load(:before_initialize) do |app|
32
32
  GUARD_ONCE_PER_APP[app].run do
33
- begin
34
- app.middleware.insert_after(Warden::Manager, TrackingMiddleware)
35
- rescue RuntimeError
36
- AppSec.telemetry.error('AppSec: unable to insert Devise TrackingMiddleware')
37
- end
33
+ app.middleware.insert_after(Warden::Manager, TrackingMiddleware)
34
+ rescue RuntimeError
35
+ AppSec.telemetry.error('AppSec: unable to insert Devise TrackingMiddleware')
38
36
  end
39
37
  end
40
38
 
@@ -10,6 +10,7 @@ module Datadog
10
10
  # A Rack middleware capable of tracking currently signed user
11
11
  class TrackingMiddleware
12
12
  WARDEN_KEY = 'warden'
13
+ SESSION_ID_KEY = 'session_id'
13
14
 
14
15
  def initialize(app)
15
16
  @app = app
@@ -32,16 +33,28 @@ module Datadog
32
33
  return @app.call(env)
33
34
  end
34
35
 
36
+ # NOTE: Rails session id will be set for unauthenticated users as well,
37
+ # so we need to make sure we are tracking only authenticated users.
35
38
  id = transform(extract_id(env[WARDEN_KEY]))
39
+ session_id = env[WARDEN_KEY].raw_session[SESSION_ID_KEY] if id
40
+
36
41
  if id
37
- unless context.span.has_tag?(Ext::TAG_USR_ID)
38
- context.span[Ext::TAG_USR_ID] = id
42
+ # NOTE: There is no option to set session id without setting user id via SDK.
43
+ unless context.span.has_tag?(Ext::TAG_USR_ID) && context.span.has_tag?(Ext::TAG_SESSION_ID)
44
+ user_id = context.span[Ext::TAG_USR_ID] || id
45
+ user_session_id = context.span[Ext::TAG_SESSION_ID] || session_id
46
+
47
+ # FIXME: The current implementation of event arguments is forsing us
48
+ # to bloat User class, and pass nil-value instead of skip
49
+ # passing them at first place.
50
+ # This is a temporary situation until we refactor events model.
39
51
  AppSec::Instrumentation.gateway.push(
40
- 'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, nil)
52
+ 'identity.set_user', AppSec::Instrumentation::Gateway::User.new(user_id, nil, user_session_id)
41
53
  )
42
54
  end
43
55
 
44
- context.span[Ext::TAG_DD_USR_ID] = id.to_s
56
+ context.span[Ext::TAG_USR_ID] ||= id
57
+ context.span[Ext::TAG_DD_USR_ID] = id
45
58
  context.span[Ext::TAG_DD_COLLECTION_MODE] ||= Configuration.auto_user_instrumentation_mode
46
59
  end
47
60
 
@@ -16,7 +16,7 @@ module Datadog
16
16
  register_as :excon
17
17
 
18
18
  def self.version
19
- Gem.loaded_specs['excon'] && Gem.loaded_specs['excon'].version
19
+ Gem.loaded_specs['excon']&.version
20
20
  end
21
21
 
22
22
  def self.loaded?
@@ -3,6 +3,9 @@
3
3
 
4
4
  require 'excon'
5
5
 
6
+ require_relative '../../event'
7
+ require_relative '../../security_event'
8
+
6
9
  module Datadog
7
10
  module AppSec
8
11
  module Contrib
@@ -15,22 +18,18 @@ module Datadog
15
18
  context = AppSec.active_context
16
19
 
17
20
  request_url = URI.join("#{data[:scheme]}://#{data[:host]}", data[:path]).to_s
18
- ephemeral_data = { 'server.io.net.url' => request_url }
21
+ ephemeral_data = {'server.io.net.url' => request_url}
19
22
 
20
23
  result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
21
24
 
22
25
  if result.match?
23
- Datadog::AppSec::Event.tag_and_keep!(context, result)
26
+ AppSec::Event.tag_and_keep!(context, result)
24
27
 
25
- context.events << {
26
- waf_result: result,
27
- trace: context.trace,
28
- span: context.span,
29
- request_url: request_url,
30
- actions: result.actions
31
- }
28
+ context.events.push(
29
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
30
+ )
32
31
 
33
- ActionsHandler.handle(result.actions)
32
+ AppSec::ActionsHandler.handle(result.actions)
34
33
  end
35
34
 
36
35
  super
@@ -17,7 +17,7 @@ module Datadog
17
17
  register_as :faraday, auto_patch: true
18
18
 
19
19
  def self.version
20
- Gem.loaded_specs['faraday'] && Gem.loaded_specs['faraday'].version
20
+ Gem.loaded_specs['faraday']&.version
21
21
  end
22
22
 
23
23
  def self.loaded?
@@ -1,6 +1,9 @@
1
1
  # rubocop:disable Naming/FileName
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative '../../event'
5
+ require_relative '../../security_event'
6
+
4
7
  module Datadog
5
8
  module AppSec
6
9
  module Contrib
@@ -19,17 +22,13 @@ module Datadog
19
22
  result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
20
23
 
21
24
  if result.match?
22
- Datadog::AppSec::Event.tag_and_keep!(context, result)
25
+ AppSec::Event.tag_and_keep!(context, result)
23
26
 
24
- context.events << {
25
- waf_result: result,
26
- trace: context.trace,
27
- span: context.span,
28
- request_url: request_env.url,
29
- actions: result.actions
30
- }
27
+ context.events.push(
28
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
29
+ )
31
30
 
32
- ActionsHandler.handle(result.actions)
31
+ AppSec::ActionsHandler.handle(result.actions)
33
32
  end
34
33
 
35
34
  @app.call(request_env)
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+
5
+ require_relative '../../../event'
6
+ require_relative '../../../security_event'
4
7
  require_relative '../../../instrumentation/gateway'
5
8
 
6
9
  module Datadog
@@ -29,17 +32,13 @@ module Datadog
29
32
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
30
33
 
31
34
  if result.match?
32
- Datadog::AppSec::Event.tag_and_keep!(context, result)
35
+ AppSec::Event.tag_and_keep!(context, result)
33
36
 
34
- context.events << {
35
- waf_result: result,
36
- trace: context.trace,
37
- span: context.span,
38
- multiplex: gateway_multiplex,
39
- actions: result.actions
40
- }
37
+ context.events.push(
38
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
39
+ )
41
40
 
42
- Datadog::AppSec::ActionsHandler.handle(result.actions)
41
+ AppSec::ActionsHandler.handle(result.actions)
43
42
  end
44
43
  end
45
44
 
@@ -23,7 +23,7 @@ module Datadog
23
23
  register_as :graphql, auto_patch: false
24
24
 
25
25
  def self.version
26
- Gem.loaded_specs['graphql'] && Gem.loaded_specs['graphql'].version
26
+ Gem.loaded_specs['graphql']&.version
27
27
  end
28
28
 
29
29
  def self.loaded?
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../ext'
4
- require_relative '../../../instrumentation/gateway'
5
4
  require_relative '../../../event'
5
+ require_relative '../../../security_event'
6
+ require_relative '../../../instrumentation/gateway'
6
7
 
7
8
  module Datadog
8
9
  module AppSec
@@ -23,7 +24,7 @@ module Datadog
23
24
 
24
25
  def watch_request(gateway = Instrumentation.gateway)
25
26
  gateway.watch('rack.request', :appsec) do |stack, gateway_request|
26
- context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
27
+ context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
27
28
 
28
29
  persistent_data = {
29
30
  'server.request.cookies' => gateway_request.cookies,
@@ -37,18 +38,15 @@ module Datadog
37
38
 
38
39
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
39
40
 
40
- if result.match?
41
- Datadog::AppSec::Event.tag_and_keep!(context, result)
42
-
43
- context.events << {
44
- waf_result: result,
45
- trace: context.trace,
46
- span: context.span,
47
- request: gateway_request,
48
- actions: result.actions
49
- }
41
+ if result.match? || !result.derivatives.empty?
42
+ context.events.push(
43
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
44
+ )
45
+ end
50
46
 
51
- Datadog::AppSec::ActionsHandler.handle(result.actions)
47
+ if result.match?
48
+ AppSec::Event.tag_and_keep!(context, result)
49
+ AppSec::ActionsHandler.handle(result.actions)
52
50
  end
53
51
 
54
52
  stack.call(gateway_request.request)
@@ -68,17 +66,13 @@ module Datadog
68
66
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
69
67
 
70
68
  if result.match?
71
- Datadog::AppSec::Event.tag_and_keep!(context, result)
69
+ AppSec::Event.tag_and_keep!(context, result)
72
70
 
73
- context.events << {
74
- waf_result: result,
75
- trace: context.trace,
76
- span: context.span,
77
- response: gateway_response,
78
- actions: result.actions
79
- }
71
+ context.events.push(
72
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
73
+ )
80
74
 
81
- Datadog::AppSec::ActionsHandler.handle(result.actions)
75
+ AppSec::ActionsHandler.handle(result.actions)
82
76
  end
83
77
 
84
78
  stack.call(gateway_response.response)
@@ -87,7 +81,7 @@ module Datadog
87
81
 
88
82
  def watch_request_body(gateway = Instrumentation.gateway)
89
83
  gateway.watch('rack.request.body', :appsec) do |stack, gateway_request|
90
- context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
84
+ context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
91
85
 
92
86
  persistent_data = {
93
87
  'server.request.body' => gateway_request.form_hash
@@ -96,17 +90,13 @@ module Datadog
96
90
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
97
91
 
98
92
  if result.match?
99
- Datadog::AppSec::Event.tag_and_keep!(context, result)
93
+ AppSec::Event.tag_and_keep!(context, result)
100
94
 
101
- context.events << {
102
- waf_result: result,
103
- trace: context.trace,
104
- span: context.span,
105
- request: gateway_request,
106
- actions: result.actions
107
- }
95
+ context.events.push(
96
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
97
+ )
108
98
 
109
- Datadog::AppSec::ActionsHandler.handle(result.actions)
99
+ AppSec::ActionsHandler.handle(result.actions)
110
100
  end
111
101
 
112
102
  stack.call(gateway_request.request)
@@ -19,7 +19,7 @@ module Datadog
19
19
  register_as :rack, auto_patch: false
20
20
 
21
21
  def self.version
22
- Gem.loaded_specs['rack'] && Gem.loaded_specs['rack'].version
22
+ Gem.loaded_specs['rack']&.version
23
23
  end
24
24
 
25
25
  def self.loaded?