datadog 2.7.1 → 2.17.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 (417) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +310 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +66 -56
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +10 -10
  9. data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +314 -145
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  12. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  13. data/ext/datadog_profiling_native_extension/encoded_profile.c +79 -0
  14. data/ext/datadog_profiling_native_extension/encoded_profile.h +8 -0
  15. data/ext/datadog_profiling_native_extension/extconf.rb +7 -8
  16. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  17. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  18. data/ext/datadog_profiling_native_extension/heap_recorder.c +61 -174
  19. data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
  20. data/ext/datadog_profiling_native_extension/http_transport.c +64 -98
  21. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +68 -1
  22. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +10 -1
  23. data/ext/datadog_profiling_native_extension/profiling.c +19 -8
  24. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  25. data/ext/datadog_profiling_native_extension/stack_recorder.c +84 -131
  26. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
  27. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  28. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  29. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  30. data/ext/libdatadog_api/crashtracker.c +17 -15
  31. data/ext/libdatadog_api/crashtracker.h +5 -0
  32. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  33. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  34. data/ext/libdatadog_api/init.c +15 -0
  35. data/ext/libdatadog_api/library_config.c +122 -0
  36. data/ext/libdatadog_api/library_config.h +19 -0
  37. data/ext/libdatadog_api/macos_development.md +3 -3
  38. data/ext/libdatadog_api/process_discovery.c +117 -0
  39. data/ext/libdatadog_api/process_discovery.h +5 -0
  40. data/ext/libdatadog_extconf_helpers.rb +1 -1
  41. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
  42. data/lib/datadog/appsec/actions_handler.rb +49 -0
  43. data/lib/datadog/appsec/anonymizer.rb +16 -0
  44. data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
  45. data/lib/datadog/appsec/api_security.rb +9 -0
  46. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  47. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  48. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  49. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  50. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  51. data/lib/datadog/appsec/autoload.rb +1 -1
  52. data/lib/datadog/appsec/component.rb +41 -33
  53. data/lib/datadog/appsec/compressed_json.rb +40 -0
  54. data/lib/datadog/appsec/configuration/settings.rb +152 -25
  55. data/lib/datadog/appsec/context.rb +74 -0
  56. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +92 -0
  57. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  58. data/lib/datadog/appsec/contrib/active_record/patcher.rb +101 -0
  59. data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
  60. data/lib/datadog/appsec/contrib/devise/configuration.rb +52 -0
  61. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +78 -0
  62. data/lib/datadog/appsec/contrib/devise/ext.rb +22 -0
  63. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -2
  64. data/lib/datadog/appsec/contrib/devise/patcher.rb +33 -25
  65. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
  66. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
  67. data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +3 -3
  68. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +106 -0
  69. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  70. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  71. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +42 -0
  72. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  73. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  74. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  75. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  76. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +41 -0
  77. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  78. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +17 -30
  79. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  80. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  81. data/lib/datadog/appsec/contrib/rack/ext.rb +34 -0
  82. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  83. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +78 -98
  84. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  85. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  86. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  87. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +52 -68
  88. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +16 -33
  89. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  90. data/lib/datadog/appsec/contrib/rails/patcher.rb +25 -38
  91. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  92. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  93. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +38 -0
  94. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +31 -68
  95. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  96. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -31
  97. data/lib/datadog/appsec/event.rb +96 -135
  98. data/lib/datadog/appsec/ext.rb +12 -3
  99. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +7 -2
  100. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  101. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  102. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  103. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  104. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  105. data/lib/datadog/appsec/metrics.rb +13 -0
  106. data/lib/datadog/appsec/monitor/gateway/watcher.rb +52 -32
  107. data/lib/datadog/appsec/processor/rule_loader.rb +26 -31
  108. data/lib/datadog/appsec/processor/rule_merger.rb +7 -6
  109. data/lib/datadog/appsec/processor.rb +5 -4
  110. data/lib/datadog/appsec/remote.rb +26 -12
  111. data/lib/datadog/appsec/response.rb +19 -85
  112. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  113. data/lib/datadog/appsec/security_engine/runner.rb +88 -0
  114. data/lib/datadog/appsec/security_engine.rb +9 -0
  115. data/lib/datadog/appsec/security_event.rb +39 -0
  116. data/lib/datadog/appsec/utils.rb +0 -2
  117. data/lib/datadog/appsec.rb +23 -10
  118. data/lib/datadog/auto_instrument.rb +3 -0
  119. data/lib/datadog/core/buffer/random.rb +18 -2
  120. data/lib/datadog/core/configuration/agent_settings_resolver.rb +42 -14
  121. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  122. data/lib/datadog/core/configuration/components.rb +76 -32
  123. data/lib/datadog/core/configuration/components_state.rb +23 -0
  124. data/lib/datadog/core/configuration/ext.rb +5 -1
  125. data/lib/datadog/core/configuration/option.rb +79 -43
  126. data/lib/datadog/core/configuration/option_definition.rb +6 -4
  127. data/lib/datadog/core/configuration/options.rb +3 -3
  128. data/lib/datadog/core/configuration/settings.rb +100 -41
  129. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  130. data/lib/datadog/core/configuration.rb +43 -11
  131. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  132. data/lib/datadog/core/crashtracking/component.rb +4 -13
  133. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  134. data/lib/datadog/core/encoding.rb +17 -1
  135. data/lib/datadog/core/environment/agent_info.rb +78 -0
  136. data/lib/datadog/core/environment/cgroup.rb +10 -12
  137. data/lib/datadog/core/environment/container.rb +38 -40
  138. data/lib/datadog/core/environment/ext.rb +6 -6
  139. data/lib/datadog/core/environment/git.rb +1 -0
  140. data/lib/datadog/core/environment/identity.rb +3 -3
  141. data/lib/datadog/core/environment/platform.rb +3 -3
  142. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  143. data/lib/datadog/core/error.rb +11 -9
  144. data/lib/datadog/core/logger.rb +2 -2
  145. data/lib/datadog/core/metrics/client.rb +27 -27
  146. data/lib/datadog/core/metrics/logging.rb +5 -5
  147. data/lib/datadog/core/process_discovery.rb +32 -0
  148. data/lib/datadog/core/rate_limiter.rb +4 -2
  149. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  150. data/lib/datadog/core/remote/client.rb +107 -92
  151. data/lib/datadog/core/remote/component.rb +18 -19
  152. data/lib/datadog/core/remote/configuration/digest.rb +7 -7
  153. data/lib/datadog/core/remote/configuration/path.rb +1 -1
  154. data/lib/datadog/core/remote/configuration/repository.rb +2 -1
  155. data/lib/datadog/core/remote/negotiation.rb +9 -9
  156. data/lib/datadog/core/remote/transport/config.rb +4 -3
  157. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  158. data/lib/datadog/core/remote/transport/http/client.rb +5 -4
  159. data/lib/datadog/core/remote/transport/http/config.rb +27 -55
  160. data/lib/datadog/core/remote/transport/http/negotiation.rb +8 -51
  161. data/lib/datadog/core/remote/transport/http.rb +25 -94
  162. data/lib/datadog/core/remote/transport/negotiation.rb +17 -4
  163. data/lib/datadog/core/remote/worker.rb +10 -7
  164. data/lib/datadog/core/runtime/metrics.rb +12 -5
  165. data/lib/datadog/core/telemetry/component.rb +84 -49
  166. data/lib/datadog/core/telemetry/emitter.rb +23 -11
  167. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
  168. data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
  169. data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
  170. data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
  171. data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
  172. data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
  173. data/lib/datadog/core/telemetry/event/base.rb +40 -0
  174. data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
  175. data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
  176. data/lib/datadog/core/telemetry/event/log.rb +76 -0
  177. data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
  178. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
  179. data/lib/datadog/core/telemetry/event.rb +17 -383
  180. data/lib/datadog/core/telemetry/ext.rb +1 -0
  181. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  182. data/lib/datadog/core/telemetry/logger.rb +1 -1
  183. data/lib/datadog/core/telemetry/logging.rb +2 -2
  184. data/lib/datadog/core/telemetry/metric.rb +28 -6
  185. data/lib/datadog/core/telemetry/request.rb +4 -4
  186. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  187. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  188. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  189. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  190. data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
  191. data/lib/datadog/core/telemetry/worker.rb +128 -25
  192. data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
  193. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  194. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +18 -1
  195. data/lib/datadog/core/transport/http/api/spec.rb +36 -0
  196. data/lib/datadog/{tracing → core}/transport/http/builder.rb +53 -31
  197. data/lib/datadog/core/transport/http.rb +75 -0
  198. data/lib/datadog/core/transport/response.rb +4 -0
  199. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
  200. data/lib/datadog/core/utils/duration.rb +32 -32
  201. data/lib/datadog/core/utils/forking.rb +2 -2
  202. data/lib/datadog/core/utils/network.rb +6 -6
  203. data/lib/datadog/core/utils/only_once_successful.rb +16 -5
  204. data/lib/datadog/core/utils/time.rb +20 -0
  205. data/lib/datadog/core/utils/truncation.rb +21 -0
  206. data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
  207. data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
  208. data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
  209. data/lib/datadog/core/worker.rb +1 -1
  210. data/lib/datadog/core/workers/async.rb +29 -12
  211. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  212. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  213. data/lib/datadog/core.rb +8 -0
  214. data/lib/datadog/di/base.rb +115 -0
  215. data/lib/datadog/di/boot.rb +34 -0
  216. data/lib/datadog/di/code_tracker.rb +26 -15
  217. data/lib/datadog/di/component.rb +23 -14
  218. data/lib/datadog/di/configuration/settings.rb +25 -1
  219. data/lib/datadog/di/contrib/active_record.rb +1 -0
  220. data/lib/datadog/di/contrib/railtie.rb +15 -0
  221. data/lib/datadog/di/contrib.rb +28 -0
  222. data/lib/datadog/di/error.rb +5 -0
  223. data/lib/datadog/di/instrumenter.rb +111 -20
  224. data/lib/datadog/di/logger.rb +30 -0
  225. data/lib/datadog/di/preload.rb +18 -0
  226. data/lib/datadog/di/probe.rb +14 -7
  227. data/lib/datadog/di/probe_builder.rb +1 -0
  228. data/lib/datadog/di/probe_manager.rb +11 -5
  229. data/lib/datadog/di/probe_notification_builder.rb +34 -8
  230. data/lib/datadog/di/probe_notifier_worker.rb +52 -26
  231. data/lib/datadog/di/redactor.rb +0 -1
  232. data/lib/datadog/di/remote.rb +147 -0
  233. data/lib/datadog/di/serializer.rb +14 -7
  234. data/lib/datadog/di/transport/diagnostics.rb +62 -0
  235. data/lib/datadog/di/transport/http/api.rb +42 -0
  236. data/lib/datadog/di/transport/http/client.rb +47 -0
  237. data/lib/datadog/di/transport/http/diagnostics.rb +65 -0
  238. data/lib/datadog/di/transport/http/input.rb +67 -0
  239. data/lib/datadog/di/transport/http.rb +57 -0
  240. data/lib/datadog/di/transport/input.rb +62 -0
  241. data/lib/datadog/di/utils.rb +103 -0
  242. data/lib/datadog/di.rb +14 -76
  243. data/lib/datadog/error_tracking/collector.rb +87 -0
  244. data/lib/datadog/error_tracking/component.rb +167 -0
  245. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  246. data/lib/datadog/error_tracking/configuration.rb +11 -0
  247. data/lib/datadog/error_tracking/ext.rb +18 -0
  248. data/lib/datadog/error_tracking/extensions.rb +16 -0
  249. data/lib/datadog/error_tracking/filters.rb +77 -0
  250. data/lib/datadog/error_tracking.rb +18 -0
  251. data/lib/datadog/kit/appsec/events.rb +15 -3
  252. data/lib/datadog/kit/identity.rb +9 -5
  253. data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
  254. data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
  255. data/lib/datadog/opentelemetry/api/context.rb +16 -2
  256. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  257. data/lib/datadog/opentelemetry.rb +2 -1
  258. data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
  259. data/lib/datadog/profiling/collectors/info.rb +3 -0
  260. data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
  261. data/lib/datadog/profiling/component.rb +60 -76
  262. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  263. data/lib/datadog/profiling/exporter.rb +3 -4
  264. data/lib/datadog/profiling/ext.rb +0 -2
  265. data/lib/datadog/profiling/flush.rb +5 -8
  266. data/lib/datadog/profiling/http_transport.rb +6 -85
  267. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  268. data/lib/datadog/profiling/scheduler.rb +8 -1
  269. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  270. data/lib/datadog/profiling/tag_builder.rb +1 -5
  271. data/lib/datadog/profiling.rb +6 -2
  272. data/lib/datadog/tracing/analytics.rb +1 -1
  273. data/lib/datadog/tracing/component.rb +16 -12
  274. data/lib/datadog/tracing/configuration/ext.rb +8 -1
  275. data/lib/datadog/tracing/configuration/settings.rb +22 -10
  276. data/lib/datadog/tracing/context_provider.rb +1 -1
  277. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  278. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  279. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  280. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  281. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  282. data/lib/datadog/tracing/contrib/active_record/integration.rb +7 -3
  283. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +7 -2
  284. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +36 -1
  285. data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
  286. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +14 -4
  287. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  288. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  289. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  290. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
  291. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  292. data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
  293. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  294. data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
  295. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  296. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  297. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
  298. data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
  299. data/lib/datadog/tracing/contrib/ext.rb +1 -0
  300. data/lib/datadog/tracing/contrib/extensions.rb +29 -3
  301. data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
  302. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  303. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  304. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  305. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  306. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
  307. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
  308. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
  309. data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
  310. data/lib/datadog/tracing/contrib/http/instrumentation.rb +6 -10
  311. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  312. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -16
  313. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +7 -15
  314. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  315. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  316. data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
  317. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +48 -0
  318. data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
  319. data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
  320. data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
  321. data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
  322. data/lib/datadog/tracing/contrib/karafka.rb +37 -0
  323. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  324. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  325. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  326. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  327. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  328. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  329. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  330. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  331. data/lib/datadog/tracing/contrib/patcher.rb +5 -2
  332. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  333. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  334. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  335. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  336. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  337. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  338. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  339. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  340. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
  341. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
  342. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
  343. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  344. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  345. data/lib/datadog/tracing/contrib/support.rb +28 -0
  346. data/lib/datadog/tracing/contrib.rb +1 -0
  347. data/lib/datadog/tracing/correlation.rb +9 -2
  348. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  349. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  350. data/lib/datadog/tracing/distributed/baggage.rb +131 -0
  351. data/lib/datadog/tracing/distributed/datadog.rb +4 -2
  352. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  353. data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
  354. data/lib/datadog/tracing/metadata/errors.rb +4 -4
  355. data/lib/datadog/tracing/metadata/ext.rb +5 -0
  356. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  357. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  358. data/lib/datadog/tracing/metadata.rb +2 -0
  359. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  360. data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
  361. data/lib/datadog/tracing/span.rb +22 -5
  362. data/lib/datadog/tracing/span_event.rb +124 -4
  363. data/lib/datadog/tracing/span_operation.rb +52 -16
  364. data/lib/datadog/tracing/sync_writer.rb +9 -5
  365. data/lib/datadog/tracing/trace_digest.rb +9 -2
  366. data/lib/datadog/tracing/trace_operation.rb +44 -24
  367. data/lib/datadog/tracing/trace_segment.rb +6 -4
  368. data/lib/datadog/tracing/tracer.rb +60 -12
  369. data/lib/datadog/tracing/transport/http/api.rb +5 -4
  370. data/lib/datadog/tracing/transport/http/client.rb +5 -4
  371. data/lib/datadog/tracing/transport/http/traces.rb +13 -44
  372. data/lib/datadog/tracing/transport/http.rb +13 -70
  373. data/lib/datadog/tracing/transport/serializable_trace.rb +31 -7
  374. data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
  375. data/lib/datadog/tracing/transport/traces.rb +47 -13
  376. data/lib/datadog/tracing/utils.rb +1 -1
  377. data/lib/datadog/tracing/workers/trace_writer.rb +8 -5
  378. data/lib/datadog/tracing/workers.rb +5 -4
  379. data/lib/datadog/tracing/writer.rb +10 -6
  380. data/lib/datadog/tracing.rb +16 -3
  381. data/lib/datadog/version.rb +2 -2
  382. data/lib/datadog.rb +2 -0
  383. metadata +143 -50
  384. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  385. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  386. data/lib/datadog/appsec/contrib/devise/event.rb +0 -57
  387. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -77
  388. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -54
  389. data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
  390. data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
  391. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  392. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  393. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  394. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  395. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  396. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  397. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  398. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  399. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  400. data/lib/datadog/appsec/processor/actions.rb +0 -49
  401. data/lib/datadog/appsec/processor/context.rb +0 -107
  402. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  403. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  404. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  405. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  406. data/lib/datadog/appsec/scope.rb +0 -58
  407. data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
  408. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
  409. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  410. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  411. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  412. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  413. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  414. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  415. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
  416. data/lib/datadog/di/transport.rb +0 -81
  417. data/lib/datadog/tracing/transport/http/api/spec.rb +0 -19
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../anonymizer'
4
+
5
+ module Datadog
6
+ module AppSec
7
+ module Contrib
8
+ module Devise
9
+ # Extracts user identification data from Devise resources.
10
+ # Supports both regular and anonymized data extraction modes.
11
+ class DataExtractor
12
+ PRIORITY_ORDERED_ID_KEYS = [:id, 'id', :uuid, 'uuid'].freeze
13
+ PRIORITY_ORDERED_LOGIN_KEYS = [:email, 'email', :username, 'username', :login, 'login'].freeze
14
+
15
+ def initialize(mode:)
16
+ @mode = mode
17
+ @devise_scopes = {}
18
+ end
19
+
20
+ def extract_id(object)
21
+ return if object.nil?
22
+
23
+ if object.respond_to?(:[])
24
+ id = object[PRIORITY_ORDERED_ID_KEYS.find { |key| object[key] }]
25
+ scope = find_devise_scope(object)
26
+
27
+ id = "#{scope}:#{id}" if id && scope
28
+ return transform(id)
29
+ end
30
+
31
+ id = object.id if object.respond_to?(:id)
32
+ id ||= object.uuid if object.respond_to?(:uuid)
33
+
34
+ scope = find_devise_scope(object)
35
+ id = "#{scope}:#{id}" if id && scope
36
+
37
+ transform(id)
38
+ end
39
+
40
+ def extract_login(object)
41
+ return if object.nil?
42
+
43
+ if object.respond_to?(:[])
44
+ login = object[PRIORITY_ORDERED_LOGIN_KEYS.find { |key| object[key] }]
45
+ return transform(login)
46
+ end
47
+
48
+ login = object.email if object.respond_to?(:email)
49
+ login ||= object.username if object.respond_to?(:username)
50
+ login ||= object.login if object.respond_to?(:login)
51
+
52
+ transform(login)
53
+ end
54
+
55
+ private
56
+
57
+ def find_devise_scope(object)
58
+ return if ::Devise.mappings.count == 1
59
+
60
+ @devise_scopes[object.class.name] ||= ::Devise.mappings
61
+ .each_value.find { |mapping| mapping.class_name == object.class.name }&.name
62
+ end
63
+
64
+ def transform(value)
65
+ return if value.nil?
66
+ return value.to_s unless anonymize?
67
+
68
+ Anonymizer.anonymize(value.to_s)
69
+ end
70
+
71
+ def anonymize?
72
+ @mode == AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -6,6 +6,28 @@ module Datadog
6
6
  module Devise
7
7
  # Devise integration constants
8
8
  module Ext
9
+ EVENT_LOGIN_SUCCESS = 'users.login.success'
10
+ EVENT_LOGIN_FAILURE = 'users.login.failure'
11
+ EVENT_SIGNUP = 'users.signup'
12
+
13
+ TAG_DD_USR_ID = '_dd.appsec.usr.id'
14
+ TAG_DD_USR_LOGIN = '_dd.appsec.usr.login'
15
+ TAG_DD_SIGNUP_MODE = '_dd.appsec.events.users.signup.auto.mode'
16
+ TAG_DD_COLLECTION_MODE = '_dd.appsec.user.collection_mode'
17
+ TAG_DD_LOGIN_SUCCESS_MODE = '_dd.appsec.events.users.login.success.auto.mode'
18
+ TAG_DD_LOGIN_FAILURE_MODE = '_dd.appsec.events.users.login.failure.auto.mode'
19
+
20
+ TAG_USR_ID = 'usr.id'
21
+ TAG_SESSION_ID = 'usr.session_id'
22
+ TAG_SIGNUP_TRACK = 'appsec.events.users.signup.track'
23
+ TAG_SIGNUP_USR_ID = 'appsec.events.users.signup.usr.id'
24
+ TAG_SIGNUP_USR_LOGIN = 'appsec.events.users.signup.usr.login'
25
+ TAG_LOGIN_FAILURE_TRACK = 'appsec.events.users.login.failure.track'
26
+ TAG_LOGIN_FAILURE_USR_ID = 'appsec.events.users.login.failure.usr.id'
27
+ TAG_LOGIN_FAILURE_USR_LOGIN = 'appsec.events.users.login.failure.usr.login'
28
+ TAG_LOGIN_FAILURE_USR_EXISTS = 'appsec.events.users.login.failure.usr.exists'
29
+ TAG_LOGIN_SUCCESS_TRACK = 'appsec.events.users.login.success.track'
30
+ TAG_LOGIN_SUCCESS_USR_LOGIN = 'appsec.events.users.login.success.usr.login'
9
31
  end
10
32
  end
11
33
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../integration'
4
-
5
4
  require_relative 'patcher'
6
5
 
7
6
  module Datadog
@@ -17,7 +16,7 @@ module Datadog
17
16
  register_as :devise, auto_patch: true
18
17
 
19
18
  def self.version
20
- Gem.loaded_specs['devise'] && Gem.loaded_specs['devise'].version
19
+ Gem.loaded_specs['devise']&.version
21
20
  end
22
21
 
23
22
  def self.loaded?
@@ -1,17 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../patcher'
4
- require_relative 'patcher/authenticatable_patch'
5
- require_relative 'patcher/rememberable_patch'
6
- require_relative 'patcher/registration_controller_patch'
3
+ require_relative '../../../core/utils/only_once'
4
+
5
+ require_relative 'tracking_middleware'
6
+ require_relative 'patches/signup_tracking_patch'
7
+ require_relative 'patches/signin_tracking_patch'
8
+ require_relative 'patches/skip_signin_tracking_patch'
7
9
 
8
10
  module Datadog
9
11
  module AppSec
10
12
  module Contrib
11
13
  module Devise
12
- # Patcher for AppSec on Devise
14
+ # Devise patcher
13
15
  module Patcher
14
- include Datadog::AppSec::Contrib::Patcher
16
+ GUARD_ONCE_PER_APP = Hash.new do |hash, key|
17
+ hash[key] = Datadog::Core::Utils::OnlyOnce.new
18
+ end
15
19
 
16
20
  module_function
17
21
 
@@ -24,29 +28,33 @@ module Datadog
24
28
  end
25
29
 
26
30
  def patch
27
- patch_authenticatable_strategy
28
- patch_rememberable_strategy
29
- patch_registration_controller
30
-
31
- Patcher.instance_variable_set(:@patched, true)
32
- end
33
-
34
- def patch_authenticatable_strategy
35
- ::Devise::Strategies::Authenticatable.prepend(AuthenticatablePatch)
36
- end
31
+ ::ActiveSupport.on_load(:before_initialize) do |app|
32
+ GUARD_ONCE_PER_APP[app].run do
33
+ app.middleware.insert_after(Warden::Manager, TrackingMiddleware)
34
+ rescue RuntimeError
35
+ AppSec.telemetry.error('AppSec: unable to insert Devise TrackingMiddleware')
36
+ end
37
+ end
37
38
 
38
- def patch_rememberable_strategy
39
- return unless ::Devise::STRATEGIES.include?(:rememberable)
39
+ ::ActiveSupport.on_load(:after_initialize) do
40
+ if ::Devise::RegistrationsController.descendants.empty?
41
+ ::Devise::RegistrationsController.prepend(Patches::SignupTrackingPatch)
42
+ else
43
+ ::Devise::RegistrationsController.descendants.each do |controller|
44
+ controller.prepend(Patches::SignupTrackingPatch)
45
+ end
46
+ end
47
+ end
40
48
 
41
- # Rememberable strategy is required in autoloaded Rememberable model
42
- ::Devise::Models::Rememberable # rubocop:disable Lint/Void
43
- ::Devise::Strategies::Rememberable.prepend(RememberablePatch)
44
- end
49
+ ::Devise::Strategies::Authenticatable.prepend(Patches::SigninTrackingPatch)
45
50
 
46
- def patch_registration_controller
47
- ::ActiveSupport.on_load(:after_initialize) do
48
- ::Devise::RegistrationsController.prepend(RegistrationControllerPatch)
51
+ if ::Devise::STRATEGIES.include?(:rememberable)
52
+ # Rememberable strategy is required in autoloaded Rememberable model
53
+ require 'devise/models/rememberable'
54
+ ::Devise::Strategies::Rememberable.prepend(Patches::SkipSigninTrackingPatch)
49
55
  end
56
+
57
+ Patcher.instance_variable_set(:@patched, true)
50
58
  end
51
59
  end
52
60
  end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../ext'
4
+ require_relative '../configuration'
5
+ require_relative '../data_extractor'
6
+
7
+ module Datadog
8
+ module AppSec
9
+ module Contrib
10
+ module Devise
11
+ module Patches
12
+ # A patch for Devise::Authenticatable strategy with tracking functionality
13
+ module SigninTrackingPatch
14
+ def validate(resource, &block)
15
+ result = super
16
+
17
+ return result unless AppSec.enabled?
18
+ return result if @_datadog_appsec_skip_track_login_event
19
+ return result unless Configuration.auto_user_instrumentation_enabled?
20
+ return result unless AppSec.active_context
21
+
22
+ context = AppSec.active_context
23
+ if context.trace.nil? || context.span.nil?
24
+ Datadog.logger.debug { 'AppSec: unable to track signin events, due to missing trace or span' }
25
+ return result
26
+ end
27
+
28
+ context.trace.keep!
29
+
30
+ if result
31
+ record_successful_signin(context, resource)
32
+ Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_LOGIN_SUCCESS)
33
+
34
+ return result
35
+ end
36
+
37
+ record_failed_signin(context, resource)
38
+ Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_LOGIN_FAILURE)
39
+
40
+ result
41
+ end
42
+
43
+ private
44
+
45
+ def record_successful_signin(context, resource)
46
+ extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
47
+
48
+ id = extractor.extract_id(resource)
49
+ login = extractor.extract_login(authentication_hash) || extractor.extract_login(resource)
50
+
51
+ if id
52
+ context.span[Ext::TAG_USR_ID] ||= id
53
+ context.span[Ext::TAG_DD_USR_ID] = id
54
+ end
55
+
56
+ context.span[Ext::TAG_LOGIN_SUCCESS_USR_LOGIN] ||= login
57
+ context.span[Ext::TAG_LOGIN_SUCCESS_TRACK] = 'true'
58
+ context.span[Ext::TAG_DD_USR_LOGIN] = login
59
+ context.span[Ext::TAG_DD_LOGIN_SUCCESS_MODE] = Configuration.auto_user_instrumentation_mode
60
+
61
+ # NOTE: We don't have a way to make one-shot receivers for events,
62
+ # and because of that we will trigger an additional event even
63
+ # if it was already done via the SDK
64
+ AppSec::Instrumentation.gateway.push(
65
+ 'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, login)
66
+ )
67
+ end
68
+
69
+ def record_failed_signin(context, resource)
70
+ extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
71
+
72
+ context.span[Ext::TAG_LOGIN_FAILURE_TRACK] = 'true'
73
+ context.span[Ext::TAG_DD_LOGIN_FAILURE_MODE] = Configuration.auto_user_instrumentation_mode
74
+
75
+ unless resource
76
+ login = extractor.extract_login(authentication_hash)
77
+
78
+ context.span[Ext::TAG_DD_USR_LOGIN] = login
79
+ context.span[Ext::TAG_LOGIN_FAILURE_USR_LOGIN] ||= login
80
+ context.span[Ext::TAG_LOGIN_FAILURE_USR_EXISTS] ||= 'false'
81
+
82
+ return
83
+ end
84
+
85
+ id = extractor.extract_id(resource)
86
+ login = extractor.extract_login(authentication_hash) || extractor.extract_login(resource)
87
+
88
+ if id
89
+ context.span[Ext::TAG_DD_USR_ID] = id
90
+ context.span[Ext::TAG_LOGIN_FAILURE_USR_ID] ||= id
91
+ end
92
+
93
+ context.span[Ext::TAG_DD_USR_LOGIN] = login
94
+ context.span[Ext::TAG_LOGIN_FAILURE_USR_LOGIN] ||= login
95
+ context.span[Ext::TAG_LOGIN_FAILURE_USR_EXISTS] ||= 'true'
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../ext'
4
+ require_relative '../configuration'
5
+ require_relative '../data_extractor'
6
+
7
+ module Datadog
8
+ module AppSec
9
+ module Contrib
10
+ module Devise
11
+ module Patches
12
+ # A patch for Devise::RegistrationsController with tracking functionality
13
+ module SignupTrackingPatch
14
+ def create
15
+ return super unless AppSec.enabled?
16
+ return super unless Configuration.auto_user_instrumentation_enabled?
17
+ return super unless AppSec.active_context
18
+
19
+ super do |resource|
20
+ context = AppSec.active_context
21
+
22
+ if context.trace.nil? || context.span.nil?
23
+ Datadog.logger.debug { 'AppSec: unable to track signup events, due to missing trace or span' }
24
+ next yield(resource) if block_given?
25
+ end
26
+
27
+ next yield(resource) if resource.new_record? && block_given?
28
+
29
+ context.trace.keep!
30
+ record_successful_signup(context, resource)
31
+ Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_SIGNUP)
32
+
33
+ yield(resource) if block_given?
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def record_successful_signup(context, resource)
40
+ extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
41
+
42
+ id = extractor.extract_id(resource)
43
+ login = extractor.extract_login(resource_params) || extractor.extract_login(resource)
44
+
45
+ context.span[Ext::TAG_SIGNUP_TRACK] = 'true'
46
+ context.span[Ext::TAG_DD_USR_LOGIN] = login
47
+ context.span[Ext::TAG_SIGNUP_USR_LOGIN] ||= login
48
+ context.span[Ext::TAG_DD_SIGNUP_MODE] = Configuration.auto_user_instrumentation_mode
49
+
50
+ if id
51
+ context.span[Ext::TAG_DD_USR_ID] = id
52
+
53
+ id_tag = resource.active_for_authentication? ? Ext::TAG_USR_ID : Ext::TAG_SIGNUP_USR_ID
54
+ context.span[id_tag] ||= id
55
+ end
56
+
57
+ # NOTE: We don't have a way to make one-shot receivers for events,
58
+ # and because of that we will trigger an additional event even
59
+ # if it was already done via the SDK
60
+ AppSec::Instrumentation.gateway.push(
61
+ 'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, login)
62
+ )
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -4,12 +4,12 @@ module Datadog
4
4
  module AppSec
5
5
  module Contrib
6
6
  module Devise
7
- module Patcher
7
+ module Patches
8
8
  # To avoid tracking new sessions that are created by
9
9
  # Rememberable strategy as Login Success events.
10
- module RememberablePatch
10
+ module SkipSigninTrackingPatch
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
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ext'
4
+ require_relative '../../anonymizer'
5
+
6
+ module Datadog
7
+ module AppSec
8
+ module Contrib
9
+ module Devise
10
+ # A Rack middleware capable of tracking currently signed user
11
+ class TrackingMiddleware
12
+ WARDEN_KEY = 'warden'
13
+ SESSION_ID_KEY = 'session_id'
14
+
15
+ def initialize(app)
16
+ @app = app
17
+ @devise_session_scope_keys = {}
18
+ end
19
+
20
+ def call(env)
21
+ return @app.call(env) unless AppSec.enabled?
22
+ return @app.call(env) unless Configuration.auto_user_instrumentation_enabled?
23
+ return @app.call(env) unless AppSec.active_context
24
+
25
+ unless env.key?(WARDEN_KEY)
26
+ Datadog.logger.debug { 'AppSec: unable to track requests, due to missing warden manager' }
27
+ return @app.call(env)
28
+ end
29
+
30
+ context = AppSec.active_context
31
+ if context.trace.nil? || context.span.nil?
32
+ Datadog.logger.debug { 'AppSec: unable to track requests, due to missing trace or span' }
33
+ return @app.call(env)
34
+ end
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.
38
+ id = transform(extract_id(env[WARDEN_KEY]))
39
+ session_id = env[WARDEN_KEY].raw_session[SESSION_ID_KEY] if id
40
+
41
+ if 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.
51
+ AppSec::Instrumentation.gateway.push(
52
+ 'identity.set_user', AppSec::Instrumentation::Gateway::User.new(user_id, nil, user_session_id)
53
+ )
54
+ end
55
+
56
+ context.span[Ext::TAG_USR_ID] ||= id
57
+ context.span[Ext::TAG_DD_USR_ID] = id
58
+ context.span[Ext::TAG_DD_COLLECTION_MODE] ||= Configuration.auto_user_instrumentation_mode
59
+ end
60
+
61
+ @app.call(env)
62
+ end
63
+
64
+ private
65
+
66
+ def extract_id(warden)
67
+ session_serializer = warden.session_serializer
68
+
69
+ key = session_key_for(session_serializer, ::Devise.default_scope)
70
+ id = session_serializer.session[key]&.dig(0, 0)
71
+
72
+ return id if ::Devise.mappings.size == 1
73
+ return "#{::Devise.default_scope}:#{id}" if id
74
+
75
+ ::Devise.mappings.each_key do |scope|
76
+ next if scope == ::Devise.default_scope
77
+
78
+ key = session_key_for(session_serializer, scope)
79
+ id = session_serializer.session[key]&.dig(0, 0)
80
+
81
+ return "#{scope}:#{id}" if id
82
+ end
83
+
84
+ nil
85
+ end
86
+
87
+ def session_key_for(session_serializer, scope)
88
+ @devise_session_scope_keys[scope] ||= session_serializer.key_for(scope)
89
+ end
90
+
91
+ def transform(value)
92
+ return if value.nil?
93
+ return value.to_s unless anonymize?
94
+
95
+ Anonymizer.anonimyze(value.to_s)
96
+ end
97
+
98
+ def anonymize?
99
+ Configuration.auto_user_instrumentation_mode ==
100
+ AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -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']&.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,42 @@
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
4
+ require 'excon'
5
+
6
+ require_relative '../../event'
7
+ require_relative '../../security_event'
8
+
9
+ module Datadog
10
+ module AppSec
11
+ module Contrib
12
+ module Excon
13
+ # AppSec Middleware for Excon
14
+ class SSRFDetectionMiddleware < ::Excon::Middleware::Base
15
+ def request_call(data)
16
+ return super unless AppSec.rasp_enabled? && AppSec.active_context
17
+
18
+ context = AppSec.active_context
19
+
20
+ request_url = URI.join("#{data[:scheme]}://#{data[:host]}", data[:path]).to_s
21
+ ephemeral_data = {'server.io.net.url' => request_url}
22
+
23
+ result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
24
+
25
+ if result.match?
26
+ AppSec::Event.tag_and_keep!(context, result)
27
+
28
+ context.events.push(
29
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
30
+ )
31
+
32
+ AppSec::ActionsHandler.handle(result.actions)
33
+ end
34
+
35
+ super
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ # 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']&.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