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
@@ -2,11 +2,9 @@
2
2
 
3
3
  require_relative '../../../tracing/contrib'
4
4
 
5
- require_relative '../patcher'
6
5
  require_relative '../../response'
7
6
  require_relative '../rack/request_middleware'
8
7
  require_relative 'framework'
9
- require_relative 'ext'
10
8
  require_relative 'gateway/watcher'
11
9
  require_relative 'gateway/route_params'
12
10
  require_relative 'gateway/request'
@@ -54,7 +52,7 @@ module Datadog
54
52
  def dispatch!
55
53
  env = @request.env
56
54
 
57
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
55
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
58
56
 
59
57
  return super unless context
60
58
 
@@ -62,17 +60,8 @@ module Datadog
62
60
 
63
61
  gateway_request = Gateway::Request.new(env)
64
62
 
65
- request_return, request_response = Instrumentation.gateway.push('sinatra.request.dispatch', gateway_request) do
66
- # handle process_route interruption
67
- catch(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT) { super }
68
- end
69
-
70
- if request_response
71
- blocked_event = request_response.find { |action, _options| action == :block }
72
- if blocked_event
73
- self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response
74
- request_return = nil
75
- end
63
+ request_return, _gateway_request = Instrumentation.gateway.push('sinatra.request.dispatch', gateway_request) do
64
+ super
76
65
  end
77
66
 
78
67
  request_return
@@ -86,7 +75,7 @@ module Datadog
86
75
  def process_route(*)
87
76
  env = @request.env
88
77
 
89
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
78
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
90
79
 
91
80
  return super unless context
92
81
 
@@ -103,20 +92,7 @@ module Datadog
103
92
  gateway_request = Gateway::Request.new(env)
104
93
  gateway_route_params = Gateway::RouteParams.new(route_params)
105
94
 
106
- _, request_response = Instrumentation.gateway.push(
107
- 'sinatra.request.routed',
108
- [gateway_request, gateway_route_params]
109
- )
110
-
111
- if request_response
112
- blocked_event = request_response.find { |action, _options| action == :block }
113
- if blocked_event
114
- self.response = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_sinatra_response
115
-
116
- # interrupt request and return response to dispatch! for consistency
117
- throw(Datadog::AppSec::Contrib::Sinatra::Ext::ROUTE_INTERRUPT, response)
118
- end
119
- end
95
+ Instrumentation.gateway.push('sinatra.request.routed', [gateway_request, gateway_route_params])
120
96
 
121
97
  yield(*args)
122
98
  end
@@ -125,8 +101,6 @@ module Datadog
125
101
 
126
102
  # Patcher for AppSec on Sinatra
127
103
  module Patcher
128
- include Datadog::AppSec::Contrib::Patcher
129
-
130
104
  module_function
131
105
 
132
106
  def patched?
@@ -1,181 +1,142 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'zlib'
5
-
6
4
  require_relative 'rate_limiter'
7
- require_relative '../core/utils/base64'
5
+ require_relative 'compressed_json'
8
6
 
9
7
  module Datadog
10
8
  module AppSec
11
9
  # AppSec event
12
10
  module Event
11
+ DERIVATIVE_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
12
+ DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE = 25000
13
13
  ALLOWED_REQUEST_HEADERS = %w[
14
- X-Forwarded-For
15
- X-Client-IP
16
- X-Real-IP
17
- X-Forwarded
18
- X-Cluster-Client-IP
19
- Forwarded-For
20
- Forwarded
21
- Via
22
- True-Client-IP
23
- Content-Length
24
- Content-Type
25
- Content-Encoding
26
- Content-Language
27
- Host
28
- User-Agent
29
- Accept
30
- Accept-Encoding
31
- Accept-Language
32
- ].map!(&:downcase).freeze
14
+ x-forwarded-for
15
+ x-client-ip
16
+ x-real-ip
17
+ x-forwarded
18
+ x-cluster-client-ip
19
+ forwarded-for
20
+ forwarded
21
+ via
22
+ true-client-ip
23
+ content-length
24
+ content-type
25
+ content-encoding
26
+ content-language
27
+ host
28
+ user-agent
29
+ accept
30
+ accept-encoding
31
+ accept-language
32
+ ].freeze
33
33
 
34
34
  ALLOWED_RESPONSE_HEADERS = %w[
35
- Content-Length
36
- Content-Type
37
- Content-Encoding
38
- Content-Language
39
- ].map!(&:downcase).freeze
40
-
41
- MAX_ENCODED_SCHEMA_SIZE = 25000
42
- # For more information about this number
43
- # please check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082
44
- MIN_SCHEMA_SIZE_FOR_COMPRESSION = 260
45
-
46
- # Record events for a trace
47
- #
48
- # This is expected to be called only once per trace for the rate limiter
49
- # to properly apply
50
- class << self
51
- def record(span, *events)
52
- # ensure rate limiter is called only when there are events to record
53
- return if events.empty? || span.nil?
35
+ content-length
36
+ content-type
37
+ content-encoding
38
+ content-language
39
+ ].freeze
54
40
 
55
- Datadog::AppSec::RateLimiter.thread_local.limit do
56
- record_via_span(span, *events)
57
- end
58
- end
41
+ class << self
42
+ def tag_and_keep!(context, waf_result)
43
+ # We want to keep the trace in case of security event
44
+ context.trace&.keep!
59
45
 
60
- def record_via_span(span, *events)
61
- events.group_by { |e| e[:trace] }.each do |trace, event_group|
62
- unless trace
63
- Datadog.logger.debug { "{ error: 'no trace: cannot record', event_group: #{event_group.inspect}}" }
64
- next
46
+ if context.span
47
+ if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
48
+ context.span.set_tag('appsec.blocked', 'true')
65
49
  end
66
50
 
67
- trace.keep!
68
- trace.set_tag(
69
- Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
70
- Datadog::Tracing::Sampling::Ext::Decision::ASM
71
- )
72
-
73
- # prepare and gather tags to apply
74
- service_entry_tags = build_service_entry_tags(event_group)
75
-
76
- # apply tags to service entry span
77
- service_entry_tags.each do |key, value|
78
- span.set_tag(key, value)
79
- end
51
+ context.span.set_tag('appsec.event', 'true')
80
52
  end
53
+
54
+ add_distributed_tags(context.trace)
81
55
  end
82
56
 
83
- # rubocop:disable Metrics/MethodLength
84
- def build_service_entry_tags(event_group)
85
- waf_events = []
86
- entry_tags = event_group.each_with_object({ '_dd.origin' => 'appsec' }) do |event, tags|
87
- # TODO: assume HTTP request context for now
88
- if (request = event[:request])
89
- request.headers.each do |header, value|
90
- tags["http.request.headers.#{header}"] = value if ALLOWED_REQUEST_HEADERS.include?(header.downcase)
57
+ def record(context, request: nil, response: nil)
58
+ return if context.events.empty? || context.span.nil?
59
+
60
+ Datadog::AppSec::RateLimiter.thread_local.limit do
61
+ context.events.group_by(&:trace).each do |trace, event_group|
62
+ unless trace
63
+ next Datadog.logger.debug do
64
+ "AppSec: Cannot record event group with #{event_group.count} events because it has no trace"
65
+ end
91
66
  end
92
67
 
93
- tags['http.host'] = request.host
94
- tags['http.useragent'] = request.user_agent
95
- tags['network.client.ip'] = request.remote_addr
96
- end
68
+ if event_group.any? { |event| event.attack? || event.schema? }
69
+ trace.keep!
70
+ trace[Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER] = Tracing::Sampling::Ext::Decision::ASM
97
71
 
98
- if (response = event[:response])
99
- response.headers.each do |header, value|
100
- tags["http.response.headers.#{header}"] = value if ALLOWED_RESPONSE_HEADERS.include?(header.downcase)
72
+ context.span['_dd.origin'] = 'appsec'
73
+ context.span.set_tags(request_tags(request)) if request
74
+ context.span.set_tags(response_tags(response)) if response
101
75
  end
76
+
77
+ context.span.set_tags(waf_tags(event_group))
102
78
  end
79
+ end
80
+ end
103
81
 
104
- waf_result = event[:waf_result]
105
- # accumulate triggers
106
- waf_events += waf_result.events
82
+ private
107
83
 
108
- waf_result.derivatives.each do |key, value|
109
- parsed_value = json_parse(value)
110
- next unless parsed_value
84
+ def request_tags(request)
85
+ tags = {}
111
86
 
112
- parsed_value_size = parsed_value.size
87
+ tags['http.host'] = request.host if request.host
88
+ tags['http.useragent'] = request.user_agent if request.user_agent
89
+ tags['network.client.ip'] = request.remote_addr if request.remote_addr
113
90
 
114
- schema_value = if parsed_value_size >= MIN_SCHEMA_SIZE_FOR_COMPRESSION
115
- compressed_and_base64_encoded(parsed_value)
116
- else
117
- parsed_value
118
- end
119
- next unless schema_value
91
+ request.headers.each_with_object(tags) do |(name, value), memo|
92
+ next unless ALLOWED_REQUEST_HEADERS.include?(name)
120
93
 
121
- if schema_value.size >= MAX_ENCODED_SCHEMA_SIZE
122
- Datadog.logger.debug do
123
- "Schema key: #{key} exceeds the max size value. It will not be included as part of the span tags"
124
- end
125
- next
126
- end
94
+ memo["http.request.headers.#{name}"] = value
95
+ end
96
+ end
127
97
 
128
- tags[key] = schema_value
129
- end
98
+ def response_tags(response)
99
+ response.headers.each_with_object({}) do |(name, value), memo|
100
+ next unless ALLOWED_RESPONSE_HEADERS.include?(name)
130
101
 
131
- tags
102
+ memo["http.response.headers.#{name}"] = value
132
103
  end
133
-
134
- appsec_events = json_parse({ triggers: waf_events })
135
- entry_tags['_dd.appsec.json'] = appsec_events if appsec_events
136
- entry_tags
137
104
  end
138
- # rubocop:enable Metrics/MethodLength
139
105
 
140
- def tag_and_keep!(scope, waf_result)
141
- # We want to keep the trace in case of security event
142
- scope.trace.keep! if scope.trace
106
+ def waf_tags(security_events)
107
+ triggers = []
143
108
 
144
- if scope.service_entry_span
145
- scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.include?('block')
146
- scope.service_entry_span.set_tag('appsec.event', 'true')
147
- end
109
+ tags = security_events.each_with_object({}) do |security_event, memo|
110
+ triggers.concat(security_event.waf_result.events)
148
111
 
149
- add_distributed_tags(scope.trace)
150
- end
112
+ security_event.waf_result.derivatives.each do |key, value|
113
+ next memo[key] = value unless key.start_with?(DERIVATIVE_SCHEMA_KEY_PREFIX)
151
114
 
152
- private
115
+ value = CompressedJson.dump(value)
116
+ next if value.nil?
153
117
 
154
- def compressed_and_base64_encoded(value)
155
- Datadog::Core::Utils::Base64.strict_encode64(gzip(value))
156
- rescue TypeError => e
157
- Datadog.logger.debug do
158
- "Failed to compress and encode value when populating AppSec::Event. Error: #{e.message}"
118
+ if value.size >= DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE
119
+ Datadog.logger.debug { "AppSec: Schema key '#{key}' will not be included into span tags due to it's size" }
120
+ next
121
+ end
122
+
123
+ memo[key] = value
124
+ end
159
125
  end
160
- nil
126
+
127
+ tags['_dd.appsec.json'] = json_parse({triggers: triggers}) unless triggers.empty?
128
+ tags
161
129
  end
162
130
 
131
+ # NOTE: Handling of Encoding::UndefinedConversionError is added as a quick fix to
132
+ # the issue between Ruby encoded strings and libddwaf produced events and now
133
+ # is under investigation.
163
134
  def json_parse(value)
164
135
  JSON.dump(value)
165
- rescue ArgumentError => e
166
- Datadog.logger.debug do
167
- "Failed to parse value to JSON when populating AppSec::Event. Error: #{e.message}"
168
- end
169
- nil
170
- end
136
+ rescue ArgumentError, Encoding::UndefinedConversionError, JSON::JSONError => e
137
+ AppSec.telemetry.report(e, description: 'AppSec: Failed to convert value into JSON')
171
138
 
172
- def gzip(value)
173
- sio = StringIO.new
174
- # For an in depth comparison of Zlib options check https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747215473
175
- gz = Zlib::GzipWriter.new(sio, Zlib::BEST_SPEED, Zlib::DEFAULT_STRATEGY)
176
- gz.write(value)
177
- gz.close
178
- sio.string
139
+ nil
179
140
  end
180
141
 
181
142
  # Propagate to downstream services the information that the current distributed trace is
@@ -187,7 +148,7 @@ module Datadog
187
148
  Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
188
149
  Datadog::Tracing::Sampling::Ext::Decision::ASM
189
150
  )
190
- trace.set_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT, '1')
151
+ trace.set_distributed_source(Datadog::AppSec::Ext::PRODUCT_BIT)
191
152
  end
192
153
  end
193
154
  end
@@ -3,12 +3,21 @@
3
3
  module Datadog
4
4
  module AppSec
5
5
  module Ext
6
+ RASP_SQLI = 'sql_injection'
7
+ RASP_LFI = 'lfi'
8
+ RASP_SSRF = 'ssrf'
9
+
10
+ PRODUCT_BIT = 0b00000010
11
+
6
12
  INTERRUPT = :datadog_appsec_interrupt
7
- SCOPE_KEY = 'datadog.appsec.scope'
13
+ CONTEXT_KEY = 'datadog.appsec.context'
14
+ ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
15
+ EXPLOIT_PREVENTION_EVENT_CATEGORY = 'exploit'
8
16
 
9
17
  TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
10
- TAG_APM_ENABLED = '_dd.apm.enabled'
11
- TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec'
18
+ TAG_METASTRUCT_STACK_TRACE = '_dd.stack'
19
+
20
+ TELEMETRY_METRICS_NAMESPACE = 'appsec'
12
21
  end
13
22
  end
14
23
  end
@@ -8,12 +8,17 @@ module Datadog
8
8
  class Argument; end # rubocop:disable Lint/EmptyClass
9
9
 
10
10
  # Gateway User argument
11
+ # NOTE: This class is a subject of elimination and will be removed when
12
+ # the event system is refactored.
11
13
  class User < Argument
12
- attr_reader :id
14
+ attr_reader :id, :login, :session_id
13
15
 
14
- def initialize(id)
16
+ def initialize(id, login = nil, session_id = nil)
15
17
  super()
18
+
16
19
  @id = id
20
+ @login = login
21
+ @session_id = session_id
17
22
  end
18
23
  end
19
24
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Instrumentation
6
+ class Gateway
7
+ # NOTE: This class extracted as-is and will be deprecated
8
+ # Instrumentation gateway middleware
9
+ class Middleware
10
+ attr_reader :key, :block
11
+
12
+ def initialize(key, &block)
13
+ @key = key
14
+ @block = block
15
+ end
16
+
17
+ def call(stack, env)
18
+ @block.call(stack, env)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,35 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'gateway/middleware'
4
+
3
5
  module Datadog
4
6
  module AppSec
5
7
  # Instrumentation for AppSec
6
8
  module Instrumentation
7
9
  # Instrumentation gateway implementation
8
10
  class Gateway
9
- # Instrumentation gateway middleware
10
- class Middleware
11
- attr_reader :key, :block
12
-
13
- def initialize(key, &block)
14
- @key = key
15
- @block = block
16
- end
17
-
18
- def call(stack, env)
19
- @block.call(stack, env)
20
- end
21
- end
22
-
23
- private_constant :Middleware
24
-
25
11
  def initialize
26
12
  @middlewares = Hash.new { |h, k| h[k] = [] }
13
+ @pushed_events = {}
27
14
  end
28
15
 
16
+ # NOTE: Be careful with pushed names because every pushed event name
17
+ # is recorded in order to provide an ability to any subscriber
18
+ # to check wether an arbitrary event had happened.
19
+ #
20
+ # WARNING: If we start pushing generated names we should consider
21
+ # limiting the storage of pushed names.
29
22
  def push(name, env, &block)
30
- block ||= -> {}
23
+ @pushed_events[name] = true
31
24
 
32
- middlewares_for_name = middlewares[name]
25
+ block ||= -> {}
26
+ middlewares_for_name = @middlewares[name]
33
27
 
34
28
  return [block.call, nil] if middlewares_for_name.empty?
35
29
 
@@ -48,14 +42,15 @@ module Datadog
48
42
  end
49
43
 
50
44
  def watch(name, key, &block)
51
- @middlewares[name] << Middleware.new(key, &block) unless middlewares[name].any? { |m| m.key == key }
45
+ @middlewares[name] << Middleware.new(key, &block) unless @middlewares[name].any? { |m| m.key == key }
52
46
  end
53
47
 
54
- private
55
-
56
- attr_reader :middlewares
48
+ def pushed?(name)
49
+ @pushed_events.key?(name)
50
+ end
57
51
  end
58
52
 
53
+ # NOTE: This left as-is and will be depricated soon.
59
54
  def self.gateway
60
55
  @gateway ||= Gateway.new # TODO: not thread safe
61
56
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Metrics
6
+ # A class responsible for collecting WAF and RASP call metrics.
7
+ class Collector
8
+ Store = Struct.new(:evals, :timeouts, :duration_ns, :duration_ext_ns, keyword_init: true)
9
+
10
+ attr_reader :waf, :rasp
11
+
12
+ def initialize
13
+ @mutex = Mutex.new
14
+ @waf = Store.new(evals: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
15
+ @rasp = Store.new(evals: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
16
+ end
17
+
18
+ def record_waf(result)
19
+ @mutex.synchronize do
20
+ @waf.evals += 1
21
+ @waf.timeouts += 1 if result.timeout?
22
+ @waf.duration_ns += result.duration_ns
23
+ @waf.duration_ext_ns += result.duration_ext_ns
24
+ end
25
+ end
26
+
27
+ def record_rasp(result)
28
+ @mutex.synchronize do
29
+ @rasp.evals += 1
30
+ @rasp.timeouts += 1 if result.timeout?
31
+ @rasp.duration_ns += result.duration_ns
32
+ @rasp.duration_ext_ns += result.duration_ext_ns
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Metrics
6
+ # A class responsible for exporting WAF and RASP call metrics.
7
+ module Exporter
8
+ module_function
9
+
10
+ def export_waf_metrics(metrics, span)
11
+ return if metrics.evals.zero?
12
+
13
+ span.set_tag('_dd.appsec.waf.timeouts', metrics.timeouts)
14
+ span.set_tag('_dd.appsec.waf.duration', convert_ns_to_us(metrics.duration_ns))
15
+ span.set_tag('_dd.appsec.waf.duration_ext', convert_ns_to_us(metrics.duration_ext_ns))
16
+ end
17
+
18
+ def export_rasp_metrics(metrics, span)
19
+ return if metrics.evals.zero?
20
+
21
+ span.set_tag('_dd.appsec.rasp.rule.eval', metrics.evals)
22
+ span.set_tag('_dd.appsec.rasp.timeout', 1) unless metrics.timeouts.zero?
23
+ span.set_tag('_dd.appsec.rasp.duration', convert_ns_to_us(metrics.duration_ns))
24
+ span.set_tag('_dd.appsec.rasp.duration_ext', convert_ns_to_us(metrics.duration_ext_ns))
25
+ end
26
+
27
+ # private
28
+
29
+ def convert_ns_to_us(value)
30
+ value / 1000.0
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Metrics
6
+ # A class responsible for reporting WAF and RASP telemetry metrics.
7
+ module Telemetry
8
+ module_function
9
+
10
+ def report_rasp(type, result)
11
+ return if result.is_a?(SecurityEngine::Result::Error)
12
+
13
+ tags = {rule_type: type, waf_version: Datadog::AppSec::WAF::VERSION::BASE_STRING}
14
+ namespace = Ext::TELEMETRY_METRICS_NAMESPACE
15
+
16
+ AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
17
+ AppSec.telemetry.inc(namespace, 'rasp.rule.match', 1, tags: tags) if result.match?
18
+ AppSec.telemetry.inc(namespace, 'rasp.timeout', 1, tags: tags) if result.timeout?
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ # This namespace contains classes related to metrics collection and exportation.
6
+ module Metrics
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative 'metrics/collector'
12
+ require_relative 'metrics/exporter'
13
+ require_relative 'metrics/telemetry'