datadog 2.10.0 → 2.12.2

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +44 -1
  5. data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
  6. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  7. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  8. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  9. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -0
  10. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
  11. data/ext/datadog_profiling_native_extension/profiling.c +7 -0
  12. data/ext/libdatadog_api/crashtracker.c +4 -4
  13. data/ext/libdatadog_extconf_helpers.rb +1 -1
  14. data/lib/datadog/appsec/configuration/settings.rb +64 -11
  15. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +23 -6
  16. data/lib/datadog/appsec/contrib/active_record/patcher.rb +63 -15
  17. data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
  18. data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
  19. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
  20. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
  21. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
  22. data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
  23. data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
  24. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  25. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  26. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
  27. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  28. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  29. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  30. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  31. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
  32. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +10 -12
  33. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  34. data/lib/datadog/appsec/contrib/rack/ext.rb +20 -0
  35. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +84 -72
  36. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  37. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -0
  38. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -25
  39. data/lib/datadog/appsec/contrib/rails/patcher.rb +0 -3
  40. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  41. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  42. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
  43. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -49
  44. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +0 -3
  45. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  46. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  47. data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -25
  48. data/lib/datadog/appsec/processor/rule_merger.rb +2 -1
  49. data/lib/datadog/appsec/remote.rb +11 -0
  50. data/lib/datadog/appsec.rb +3 -0
  51. data/lib/datadog/core/configuration/components.rb +17 -10
  52. data/lib/datadog/core/configuration/ext.rb +1 -1
  53. data/lib/datadog/core/configuration/option_definition.rb +2 -0
  54. data/lib/datadog/core/configuration/settings.rb +22 -6
  55. data/lib/datadog/core/encoding.rb +16 -0
  56. data/lib/datadog/core/environment/agent_info.rb +77 -0
  57. data/lib/datadog/core/metrics/client.rb +9 -8
  58. data/lib/datadog/core/remote/client.rb +5 -4
  59. data/lib/datadog/core/remote/component.rb +14 -12
  60. data/lib/datadog/core/remote/negotiation.rb +1 -1
  61. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  62. data/lib/datadog/core/remote/transport/http/config.rb +0 -18
  63. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
  64. data/lib/datadog/core/remote/transport/http.rb +6 -40
  65. data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
  66. data/lib/datadog/core/remote/worker.rb +10 -7
  67. data/lib/datadog/core/telemetry/component.rb +5 -1
  68. data/lib/datadog/core/telemetry/event.rb +5 -0
  69. data/lib/datadog/core/telemetry/worker.rb +9 -5
  70. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  71. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
  72. data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
  73. data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
  74. data/lib/datadog/core/transport/http.rb +38 -0
  75. data/lib/datadog/core/transport/response.rb +4 -0
  76. data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
  77. data/lib/datadog/di/code_tracker.rb +15 -8
  78. data/lib/datadog/di/component.rb +2 -3
  79. data/lib/datadog/di/configuration/settings.rb +14 -0
  80. data/lib/datadog/di/contrib.rb +2 -0
  81. data/lib/datadog/di/logger.rb +30 -0
  82. data/lib/datadog/di/probe.rb +3 -6
  83. data/lib/datadog/di/probe_manager.rb +5 -2
  84. data/lib/datadog/di/probe_notifier_worker.rb +35 -8
  85. data/lib/datadog/di/remote.rb +3 -3
  86. data/lib/datadog/di/transport/diagnostics.rb +61 -0
  87. data/lib/datadog/di/transport/http/api.rb +52 -0
  88. data/lib/datadog/di/transport/http/client.rb +46 -0
  89. data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
  90. data/lib/datadog/di/transport/http/input.rb +94 -0
  91. data/lib/datadog/di/transport/http.rb +105 -0
  92. data/lib/datadog/di/transport/input.rb +61 -0
  93. data/lib/datadog/di/utils.rb +91 -0
  94. data/lib/datadog/di.rb +5 -1
  95. data/lib/datadog/profiling/component.rb +2 -8
  96. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  97. data/lib/datadog/tracing/component.rb +1 -0
  98. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  99. data/lib/datadog/tracing/contrib/extensions.rb +14 -0
  100. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  101. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  102. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  103. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  104. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  105. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  106. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  107. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  108. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  109. data/lib/datadog/tracing/metadata.rb +2 -0
  110. data/lib/datadog/tracing/span.rb +10 -1
  111. data/lib/datadog/tracing/span_operation.rb +6 -1
  112. data/lib/datadog/tracing/sync_writer.rb +9 -4
  113. data/lib/datadog/tracing/tracer.rb +15 -7
  114. data/lib/datadog/tracing/transport/http/api.rb +11 -2
  115. data/lib/datadog/tracing/transport/http/traces.rb +0 -3
  116. data/lib/datadog/tracing/transport/http.rb +7 -31
  117. data/lib/datadog/tracing/transport/serializable_trace.rb +11 -5
  118. data/lib/datadog/tracing/transport/traces.rb +25 -8
  119. data/lib/datadog/tracing/workers/trace_writer.rb +10 -3
  120. data/lib/datadog/tracing/workers.rb +5 -4
  121. data/lib/datadog/tracing/writer.rb +12 -4
  122. data/lib/datadog/version.rb +2 -2
  123. metadata +37 -29
  124. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  125. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  126. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  127. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  128. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  129. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  130. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  131. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  132. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  133. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  134. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  135. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  136. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  137. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  138. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  139. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  140. data/lib/datadog/di/transport.rb +0 -79
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../patcher'
4
3
  require_relative 'instrumentation'
5
4
 
6
5
  module Datadog
@@ -9,8 +8,6 @@ module Datadog
9
8
  module ActiveRecord
10
9
  # AppSec patcher module for ActiveRecord
11
10
  module Patcher
12
- include Datadog::AppSec::Contrib::Patcher
13
-
14
11
  module_function
15
12
 
16
13
  def patched?
@@ -22,30 +19,81 @@ module Datadog
22
19
  end
23
20
 
24
21
  def patch
22
+ # Rails 7.0 intruduced new on-load hooks for sqlite3 and postgresql adapters
23
+ # The load hook for mysql2 adapter was introduced in Rails 7.1
24
+ #
25
+ # If the adapter is not loaded when the :active_record load hook is called,
26
+ # we need to add a load hook for the adapter
25
27
  ActiveSupport.on_load :active_record do
26
- instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new('7.1')
27
- Instrumentation::InternalExecQueryAdapterPatch
28
- else
29
- Instrumentation::ExecQueryAdapterPatch
30
- end
31
-
32
28
  if defined?(::ActiveRecord::ConnectionAdapters::SQLite3Adapter)
33
- ::ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(instrumentation_module)
29
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_sqlite3_adapter
30
+ else
31
+ ActiveSupport.on_load :active_record_sqlite3adapter do
32
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_sqlite3_adapter
33
+ end
34
34
  end
35
35
 
36
36
  if defined?(::ActiveRecord::ConnectionAdapters::Mysql2Adapter)
37
- ::ActiveRecord::ConnectionAdapters::Mysql2Adapter.prepend(instrumentation_module)
37
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_mysql2_adapter
38
+ else
39
+ ActiveSupport.on_load :active_record_mysql2adapter do
40
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_mysql2_adapter
41
+ end
38
42
  end
39
43
 
40
44
  if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
41
- unless defined?(::ActiveRecord::ConnectionAdapters::JdbcAdapter)
42
- instrumentation_module = Instrumentation::ExecuteAndClearAdapterPatch
45
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_postgresql_adapter
46
+ else
47
+ ActiveSupport.on_load :active_record_postgresqladapter do
48
+ ::Datadog::AppSec::Contrib::ActiveRecord::Patcher.patch_postgresql_adapter
43
49
  end
44
-
45
- ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(instrumentation_module)
46
50
  end
47
51
  end
48
52
  end
53
+
54
+ def patch_sqlite3_adapter
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
62
+
63
+ ::ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(instrumentation_module)
64
+ end
65
+
66
+ def patch_mysql2_adapter
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
74
+
75
+ ::ActiveRecord::ConnectionAdapters::Mysql2Adapter.prepend(instrumentation_module)
76
+ end
77
+
78
+ def patch_postgresql_adapter
79
+ instrumentation_module = if ::ActiveRecord.gem_version.segments.first == 4
80
+ Instrumentation::Rails4ExecuteAndClearAdapterPatch
81
+ else
82
+ Instrumentation::ExecuteAndClearAdapterPatch
83
+ end
84
+
85
+ if defined?(::ActiveRecord::ConnectionAdapters::JdbcAdapter)
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
93
+ end
94
+
95
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(instrumentation_module)
96
+ end
49
97
  end
50
98
  end
51
99
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Contrib
6
+ module Devise
7
+ # A temporary configuration module to accomodate new RFC changes.
8
+ # NOTE: DEV-3 Remove module
9
+ module Configuration
10
+ MODES_CONVERSION_RULES = {
11
+ track_user_to_auto_instrumentation: {
12
+ AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE =>
13
+ AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
14
+ AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE =>
15
+ AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
16
+ }.freeze,
17
+ auto_instrumentation_to_track_user: {
18
+ AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE =>
19
+ AppSec::Configuration::Settings::SAFE_TRACK_USER_EVENTS_MODE,
20
+ AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE =>
21
+ AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE
22
+ }.freeze
23
+ }.freeze
24
+
25
+ module_function
26
+
27
+ # NOTE: DEV-3 Replace method use with `auto_user_instrumentation.enabled?`
28
+ def auto_user_instrumentation_enabled?
29
+ appsec = Datadog.configuration.appsec
30
+ appsec.auto_user_instrumentation.mode
31
+
32
+ unless appsec.auto_user_instrumentation.options[:mode].default_precedence?
33
+ return appsec.auto_user_instrumentation.enabled?
34
+ end
35
+
36
+ appsec.track_user_events.enabled
37
+ end
38
+
39
+ # NOTE: DEV-3 Replace method use with `auto_user_instrumentation.mode`
40
+ def auto_user_instrumentation_mode
41
+ appsec = Datadog.configuration.appsec
42
+
43
+ # NOTE: Reading both to trigger precedence set
44
+ appsec.auto_user_instrumentation.mode
45
+ appsec.track_user_events.mode
46
+
47
+ if !appsec.auto_user_instrumentation.options[:mode].default_precedence? &&
48
+ appsec.track_user_events.options[:mode].default_precedence?
49
+ return appsec.auto_user_instrumentation.mode
50
+ end
51
+
52
+ if appsec.auto_user_instrumentation.options[:mode].default_precedence?
53
+ return MODES_CONVERSION_RULES[:track_user_to_auto_instrumentation].fetch(
54
+ appsec.track_user_events.mode, appsec.auto_user_instrumentation.mode
55
+ )
56
+ end
57
+
58
+ identification_mode = AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
59
+ if appsec.auto_user_instrumentation.mode == identification_mode ||
60
+ appsec.track_user_events.mode == AppSec::Configuration::Settings::EXTENDED_TRACK_USER_EVENTS_MODE
61
+ return identification_mode
62
+ end
63
+
64
+ AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
65
+ end
66
+
67
+ # NOTE: Remove in next version of tracking
68
+ def track_user_events_mode
69
+ MODES_CONVERSION_RULES[:auto_instrumentation_to_track_user]
70
+ .fetch(auto_user_instrumentation_mode, Datadog.configuration.appsec.track_user_events.mode)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -8,9 +8,6 @@ module Datadog
8
8
  class Event
9
9
  UUID_REGEX = /^\h{8}-\h{4}-\h{4}-\h{4}-\h{12}$/.freeze
10
10
 
11
- SAFE_MODE = 'safe'
12
- EXTENDED_MODE = 'extended'
13
-
14
11
  attr_reader :user_id
15
12
 
16
13
  def initialize(resource, mode)
@@ -38,15 +35,15 @@ module Datadog
38
35
  @user_id = @resource.id
39
36
 
40
37
  case @mode
41
- when EXTENDED_MODE
38
+ when AppSec::Configuration::Settings::IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
42
39
  @email = @resource.email
43
40
  @username = @resource.username
44
- when SAFE_MODE
41
+ when AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
45
42
  @user_id = nil unless @user_id && @user_id.to_s =~ UUID_REGEX
46
43
  else
47
44
  Datadog.logger.warn(
48
- "Invalid automated user evenst mode: `#{@mode}`. "\
49
- 'Supported modes are: `safe` and `extended`.'
45
+ "Invalid auto_user_instrumentation.mode: `#{@mode}`. " \
46
+ "Supported modes are: #{AppSec::Configuration::Settings::AUTO_USER_INSTRUMENTATION_MODES.join(' | ')}."
50
47
  )
51
48
  end
52
49
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../configuration'
3
4
  require_relative '../tracking'
4
5
  require_relative '../resource'
5
6
  require_relative '../event'
@@ -14,33 +15,27 @@ module Datadog
14
15
  # rubocop:disable Metrics/MethodLength
15
16
  def validate(resource, &block)
16
17
  result = super
17
- return result unless AppSec.enabled?
18
- return result if @_datadog_skip_track_login_event
19
-
20
- track_user_events_configuration = Datadog.configuration.appsec.track_user_events
21
-
22
- return result unless track_user_events_configuration.enabled
23
-
24
- automated_track_user_events_mode = track_user_events_configuration.mode
25
18
 
26
- appsec_context = Datadog::AppSec.active_context
27
-
28
- return result unless appsec_context
19
+ return result unless AppSec.enabled?
20
+ return result if @_datadog_appsec_skip_track_login_event
21
+ return result unless Configuration.auto_user_instrumentation_enabled?
22
+ return result unless AppSec.active_context
29
23
 
30
24
  devise_resource = resource ? Resource.new(resource) : nil
31
-
32
- event_information = Event.new(devise_resource, automated_track_user_events_mode)
25
+ event_information = Event.new(devise_resource, Configuration.auto_user_instrumentation_mode)
33
26
 
34
27
  if result
35
28
  if event_information.user_id
36
- Datadog.logger.debug { 'User Login Event success' }
29
+ Datadog.logger.debug { 'AppSec: User successful login event' }
37
30
  else
38
- Datadog.logger.debug { 'User Login Event success, but can\'t extract user ID. Tracking empty event' }
31
+ Datadog.logger.debug do
32
+ "AppSec: User successful login event, but can't extract user ID. Tracking empty event"
33
+ end
39
34
  end
40
35
 
41
36
  Tracking.track_login_success(
42
- appsec_context.trace,
43
- appsec_context.span,
37
+ AppSec.active_context.trace,
38
+ AppSec.active_context.span,
44
39
  user_id: event_information.user_id,
45
40
  **event_information.to_h
46
41
  )
@@ -52,15 +47,15 @@ module Datadog
52
47
 
53
48
  if resource
54
49
  user_exists = true
55
- Datadog.logger.debug { 'User Login Event failure users exists' }
50
+ Datadog.logger.debug { 'AppSec: User failed login event, but user exists' }
56
51
  else
57
52
  user_exists = false
58
- Datadog.logger.debug { 'User Login Event failure user do not exists' }
53
+ Datadog.logger.debug { 'AppSec: User failed login event and user does not exist' }
59
54
  end
60
55
 
61
56
  Tracking.track_login_failure(
62
- appsec_context.trace,
63
- appsec_context.span,
57
+ AppSec.active_context.trace,
58
+ AppSec.active_context.span,
64
59
  user_id: event_information.user_id,
65
60
  user_exists: user_exists,
66
61
  **event_information.to_h
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../configuration'
3
4
  require_relative '../tracking'
4
5
  require_relative '../resource'
5
6
  require_relative '../event'
@@ -13,31 +14,23 @@ module Datadog
13
14
  module RegistrationControllerPatch
14
15
  def create
15
16
  return super unless AppSec.enabled?
16
-
17
- track_user_events_configuration = Datadog.configuration.appsec.track_user_events
18
-
19
- return super unless track_user_events_configuration.enabled
20
-
21
- automated_track_user_events_mode = track_user_events_configuration.mode
22
-
23
- appsec_context = Datadog::AppSec.active_context
24
- return super unless appsec_context
17
+ return super unless Configuration.auto_user_instrumentation_enabled?
18
+ return super unless AppSec.active_context
25
19
 
26
20
  super do |resource|
27
21
  if resource.persisted?
28
22
  devise_resource = Resource.new(resource)
29
-
30
- event_information = Event.new(devise_resource, automated_track_user_events_mode)
23
+ event_information = Event.new(devise_resource, Configuration.auto_user_instrumentation_mode)
31
24
 
32
25
  if event_information.user_id
33
- Datadog.logger.debug { 'User Signup Event' }
26
+ Datadog.logger.debug { 'AppSec: User signup event' }
34
27
  else
35
- Datadog.logger.warn { 'User Signup Event, but can\'t extract user ID. Tracking empty event' }
28
+ Datadog.logger.warn { "AppSec: User signup event, but can't extract user ID. Tracking empty event" }
36
29
  end
37
30
 
38
31
  Tracking.track_signup(
39
- appsec_context.trace,
40
- appsec_context.span,
32
+ AppSec.active_context.trace,
33
+ AppSec.active_context.span,
41
34
  user_id: event_information.user_id,
42
35
  **event_information.to_h
43
36
  )
@@ -9,7 +9,7 @@ module Datadog
9
9
  # Rememberable strategy as Login Success events.
10
10
  module RememberablePatch
11
11
  def validate(*args)
12
- @_datadog_skip_track_login_event = true
12
+ @_datadog_appsec_skip_track_login_event = true
13
13
 
14
14
  super
15
15
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../patcher'
4
3
  require_relative 'patcher/authenticatable_patch'
5
4
  require_relative 'patcher/rememberable_patch'
6
5
  require_relative 'patcher/registration_controller_patch'
@@ -11,8 +10,6 @@ module Datadog
11
10
  module Devise
12
11
  # Patcher for AppSec on Devise
13
12
  module Patcher
14
- include Datadog::AppSec::Contrib::Patcher
15
-
16
13
  module_function
17
14
 
18
15
  def patched?
@@ -40,7 +40,7 @@ module Datadog
40
40
  return if trace.nil? || span.nil?
41
41
 
42
42
  span.set_tag("appsec.events.#{event}.track", 'true')
43
- span.set_tag("_dd.appsec.events.#{event}.auto.mode", Datadog.configuration.appsec.track_user_events.mode)
43
+ span.set_tag("_dd.appsec.events.#{event}.auto.mode", Configuration.track_user_events_mode)
44
44
 
45
45
  others.each do |k, v|
46
46
  raise ArgumentError, 'key cannot be :track' if k.to_sym == :track
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../integration'
4
+ require_relative 'patcher'
5
+
6
+ module Datadog
7
+ module AppSec
8
+ module Contrib
9
+ module Excon
10
+ # This class provides helper methods that are used when patching Excon
11
+ class Integration
12
+ include Datadog::AppSec::Contrib::Integration
13
+
14
+ MINIMUM_VERSION = Gem::Version.new('0.50.0')
15
+
16
+ register_as :excon
17
+
18
+ def self.version
19
+ Gem.loaded_specs['excon'] && Gem.loaded_specs['excon'].version
20
+ end
21
+
22
+ def self.loaded?
23
+ !defined?(::Excon).nil?
24
+ end
25
+
26
+ def self.compatible?
27
+ super && version >= MINIMUM_VERSION
28
+ end
29
+
30
+ def self.auto_instrument?
31
+ false
32
+ end
33
+
34
+ def patcher
35
+ Patcher
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Contrib
6
+ module Excon
7
+ # AppSec patcher module for Excon
8
+ module Patcher
9
+ module_function
10
+
11
+ def patched?
12
+ Patcher.instance_variable_get(:@patched)
13
+ end
14
+
15
+ def target_version
16
+ Integration.version
17
+ end
18
+
19
+ def patch
20
+ require_relative 'ssrf_detection_middleware'
21
+
22
+ ::Excon.defaults[:middlewares].insert(0, SSRFDetectionMiddleware)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
4
+ require 'excon'
5
+
6
+ module Datadog
7
+ module AppSec
8
+ module Contrib
9
+ module Excon
10
+ # AppSec Middleware for Excon
11
+ class SSRFDetectionMiddleware < ::Excon::Middleware::Base
12
+ def request_call(data)
13
+ return super unless AppSec.rasp_enabled? && AppSec.active_context
14
+
15
+ context = AppSec.active_context
16
+
17
+ request_url = URI.join("#{data[:scheme]}://#{data[:host]}", data[:path]).to_s
18
+ ephemeral_data = { 'server.io.net.url' => request_url }
19
+
20
+ result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
21
+
22
+ if result.match?
23
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
24
+
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
+ }
32
+
33
+ ActionsHandler.handle(result.actions)
34
+ end
35
+
36
+ super
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ # rubocop:enable Naming/FileName
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Contrib
6
+ module Faraday
7
+ # Handles installation of our middleware if the user has *not*
8
+ # already explicitly configured our middleware for this correction.
9
+ #
10
+ # Wraps Faraday::Connection#initialize:
11
+ # https://github.com/lostisland/faraday/blob/ff9dc1d1219a1bbdba95a9a4cf5d135b97247ee2/lib/faraday/connection.rb#L62-L92
12
+ module ConnectionPatch
13
+ def initialize(*args, &block)
14
+ super.tap do
15
+ use(:datadog_appsec) unless builder.handlers.any? { |h| h.klass == SSRFDetectionMiddleware }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../integration'
4
+
5
+ require_relative 'patcher'
6
+
7
+ module Datadog
8
+ module AppSec
9
+ module Contrib
10
+ module Faraday
11
+ # This class provides helper methods that are used when patching Faraday
12
+ class Integration
13
+ include Datadog::AppSec::Contrib::Integration
14
+
15
+ MINIMUM_VERSION = Gem::Version.new('0.14.0')
16
+
17
+ register_as :faraday, auto_patch: true
18
+
19
+ def self.version
20
+ Gem.loaded_specs['faraday'] && Gem.loaded_specs['faraday'].version
21
+ end
22
+
23
+ def self.loaded?
24
+ !defined?(::Faraday).nil?
25
+ end
26
+
27
+ def self.compatible?
28
+ super && version >= MINIMUM_VERSION
29
+ end
30
+
31
+ def self.auto_instrument?
32
+ true
33
+ end
34
+
35
+ def patcher
36
+ Patcher
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Contrib
6
+ module Faraday
7
+ # Patcher for Faraday
8
+ module Patcher
9
+ module_function
10
+
11
+ def patched?
12
+ Patcher.instance_variable_get(:@patched)
13
+ end
14
+
15
+ def target_version
16
+ Integration.version
17
+ end
18
+
19
+ def patch
20
+ require_relative 'ssrf_detection_middleware'
21
+ require_relative 'connection_patch'
22
+ require_relative 'rack_builder_patch'
23
+
24
+ ::Faraday::Middleware.register_middleware(datadog_appsec: SSRFDetectionMiddleware)
25
+ configure_default_faraday_connection
26
+
27
+ Patcher.instance_variable_set(:@patched, true)
28
+ end
29
+
30
+ def configure_default_faraday_connection
31
+ if target_version >= Gem::Version.new('1.0.0')
32
+ # Patch the default connection (e.g. +Faraday.get+)
33
+ ::Faraday.default_connection.use(:datadog_appsec)
34
+
35
+ # Patch new connection instances (e.g. +Faraday.new+)
36
+ ::Faraday::Connection.prepend(ConnectionPatch)
37
+ else
38
+ # Patch the default connection (e.g. +Faraday.get+)
39
+ #
40
+ # We insert our middleware before the 'adapter', which is
41
+ # always the last handler.
42
+ idx = ::Faraday.default_connection.builder.handlers.size - 1
43
+ ::Faraday.default_connection.builder.insert(idx, SSRFDetectionMiddleware)
44
+
45
+ # Patch new connection instances (e.g. +Faraday.new+)
46
+ ::Faraday::RackBuilder.prepend(RackBuilderPatch)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Contrib
6
+ module Faraday
7
+ # Handles installation of our middleware if the user has *not*
8
+ # already explicitly configured it for this correction.
9
+ #
10
+ # RackBuilder class was introduced in faraday 0.9.0:
11
+ # https://github.com/lostisland/faraday/commit/77d7546d6d626b91086f427c56bc2cdd951353b3
12
+ module RackBuilderPatch
13
+ def adapter(*args)
14
+ use(:datadog_appsec) unless @handlers.any? { |h| h.klass == SSRFDetectionMiddleware }
15
+
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
4
+ module Datadog
5
+ module AppSec
6
+ module Contrib
7
+ module Faraday
8
+ # AppSec SSRF detection Middleware for Faraday
9
+ class SSRFDetectionMiddleware < ::Faraday::Middleware
10
+ def call(request_env)
11
+ context = AppSec.active_context
12
+
13
+ return @app.call(request_env) unless context && AppSec.rasp_enabled?
14
+
15
+ ephemeral_data = {
16
+ 'server.io.net.url' => request_env.url.to_s
17
+ }
18
+
19
+ result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
20
+
21
+ if result.match?
22
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
23
+
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
+ }
31
+
32
+ ActionsHandler.handle(result.actions)
33
+ end
34
+
35
+ @app.call(request_env)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ # rubocop:enable Naming/FileName