datadog 2.46.0 → 2.48.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 (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -2
  3. data/LICENSE-3rdparty.csv +1 -0
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +143 -86
  5. data/ext/datadog_profiling_native_extension/collectors_stack.h +9 -1
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +6 -1
  7. data/ext/datadog_profiling_native_extension/extconf.rb +7 -13
  8. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -3
  9. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +67 -14
  10. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +8 -1
  11. data/ext/datadog_profiling_native_extension/profiling.c +1 -1
  12. data/ext/libdatadog_api/extconf.rb +9 -7
  13. data/ext/libdatadog_api/trace_exporter.c +34 -7
  14. data/ext/libdatadog_extconf_helpers.rb +2 -2
  15. data/lib/datadog/ai_guard/component.rb +1 -1
  16. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +1 -9
  17. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +1 -1
  18. data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +1 -1
  19. data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +3 -3
  20. data/lib/datadog/ai_guard/evaluation/client.rb +3 -3
  21. data/lib/datadog/ai_guard/evaluation.rb +2 -2
  22. data/lib/datadog/ai_guard/http_client.rb +3 -2
  23. data/lib/datadog/ai_guard/redaction.rb +1 -1
  24. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +1 -1
  25. data/lib/datadog/appsec/assets/waf_rules/README.md +3 -3
  26. data/lib/datadog/appsec/assets/waf_rules/recommended.json +5366 -1517
  27. data/lib/datadog/appsec/assets/waf_rules/strict.json +2 -2
  28. data/lib/datadog/appsec/autoload.rb +1 -1
  29. data/lib/datadog/appsec/component.rb +1 -1
  30. data/lib/datadog/appsec/compressed_json.rb +1 -1
  31. data/lib/datadog/appsec/configuration.rb +3 -3
  32. data/lib/datadog/appsec/context.rb +1 -1
  33. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +11 -1
  34. data/lib/datadog/appsec/contrib/active_record/patcher.rb +12 -4
  35. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +2 -2
  36. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +1 -1
  37. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  38. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +1 -1
  39. data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +1 -1
  40. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +1 -1
  41. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +1 -1
  42. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +1 -1
  43. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +7 -7
  44. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +3 -3
  46. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -5
  47. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +31 -4
  48. data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
  49. data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
  50. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +1 -1
  51. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -5
  52. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
  53. data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
  54. data/lib/datadog/appsec/metrics/collector.rb +5 -5
  55. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +3 -3
  56. data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -2
  57. data/lib/datadog/appsec/processor/rule_loader.rb +1 -1
  58. data/lib/datadog/appsec/response.rb +1 -1
  59. data/lib/datadog/appsec/security_engine/engine.rb +8 -7
  60. data/lib/datadog/appsec/security_engine/runner.rb +2 -2
  61. data/lib/datadog/appsec/trace_keeper.rb +1 -1
  62. data/lib/datadog/appsec.rb +1 -1
  63. data/lib/datadog/core/configuration/agent_settings_resolver.rb +14 -13
  64. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +2 -2
  65. data/lib/datadog/core/configuration/components.rb +12 -11
  66. data/lib/datadog/core/configuration/components_state.rb +8 -1
  67. data/lib/datadog/core/configuration/settings.rb +5 -2
  68. data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
  69. data/lib/datadog/core/configuration.rb +2 -2
  70. data/lib/datadog/core/crashtracking/component.rb +1 -1
  71. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  72. data/lib/datadog/core/environment/cgroup.rb +2 -2
  73. data/lib/datadog/core/environment/container.rb +3 -3
  74. data/lib/datadog/core/metrics/client.rb +6 -6
  75. data/lib/datadog/core/process_discovery.rb +1 -1
  76. data/lib/datadog/core/remote/client.rb +44 -3
  77. data/lib/datadog/core/remote/dispatcher.rb +34 -3
  78. data/lib/datadog/core/remote/tie/tracing.rb +4 -3
  79. data/lib/datadog/core/remote/transport/http.rb +2 -2
  80. data/lib/datadog/core/runtime/metrics.rb +14 -14
  81. data/lib/datadog/core/semaphore.rb +3 -1
  82. data/lib/datadog/core/telemetry/event/app_started.rb +9 -9
  83. data/lib/datadog/core/telemetry/logger.rb +1 -1
  84. data/lib/datadog/core/telemetry/logging.rb +1 -1
  85. data/lib/datadog/core/telemetry/request.rb +9 -3
  86. data/lib/datadog/core/telemetry/transport/http.rb +2 -2
  87. data/lib/datadog/core/telemetry/worker.rb +1 -1
  88. data/lib/datadog/core/transport/http/adapters/net.rb +1 -1
  89. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  90. data/lib/datadog/core/transport/http/builder.rb +1 -1
  91. data/lib/datadog/core/transport/http.rb +3 -3
  92. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +2 -2
  93. data/lib/datadog/core/workers/async.rb +1 -1
  94. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  95. data/lib/datadog/data_streams/pathway_context.rb +1 -1
  96. data/lib/datadog/data_streams/processor.rb +48 -27
  97. data/lib/datadog/data_streams/transport/http.rb +1 -1
  98. data/lib/datadog/data_streams.rb +16 -0
  99. data/lib/datadog/di/capture_expression_evaluator.rb +48 -11
  100. data/lib/datadog/di/component.rb +73 -2
  101. data/lib/datadog/di/configuration.rb +19 -0
  102. data/lib/datadog/di/contrib/active_record.rb +1 -1
  103. data/lib/datadog/di/el/compiler.rb +4 -4
  104. data/lib/datadog/di/el/evaluator.rb +247 -43
  105. data/lib/datadog/di/el/expression.rb +36 -6
  106. data/lib/datadog/di/error.rb +16 -0
  107. data/lib/datadog/di/guardrails_telemetry/reason.rb +3 -2
  108. data/lib/datadog/di/instrumenter.rb +39 -10
  109. data/lib/datadog/di/probe_notification_builder.rb +58 -10
  110. data/lib/datadog/di/probe_notifier_worker.rb +1 -1
  111. data/lib/datadog/di/remote.rb +46 -2
  112. data/lib/datadog/di/serializer.rb +47 -13
  113. data/lib/datadog/di.rb +27 -0
  114. data/lib/datadog/error_tracking/component.rb +1 -1
  115. data/lib/datadog/error_tracking/configuration.rb +1 -1
  116. data/lib/datadog/kit/appsec/events/v2.rb +6 -6
  117. data/lib/datadog/kit/appsec/events.rb +1 -1
  118. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  119. data/lib/datadog/kit/identity.rb +1 -1
  120. data/lib/datadog/open_feature/activation.rb +26 -1
  121. data/lib/datadog/open_feature/agentless/configuration_source.rb +94 -15
  122. data/lib/datadog/open_feature/component.rb +22 -2
  123. data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +6 -0
  124. data/lib/datadog/open_feature/configuration.rb +10 -4
  125. data/lib/datadog/open_feature/evaluation_engine.rb +62 -4
  126. data/lib/datadog/open_feature/exposures/buffer.rb +4 -0
  127. data/lib/datadog/open_feature/exposures/reporter.rb +17 -4
  128. data/lib/datadog/open_feature/exposures/worker.rb +37 -6
  129. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +5 -5
  130. data/lib/datadog/open_feature/flag_evaluation/writer.rb +1 -1
  131. data/lib/datadog/open_feature/hooks/debug_logging_hook.rb +56 -0
  132. data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
  133. data/lib/datadog/open_feature/hooks/span_enrichment_hook.rb +2 -2
  134. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +1 -1
  135. data/lib/datadog/open_feature/native_evaluator.rb +1 -1
  136. data/lib/datadog/open_feature/noop_evaluator.rb +1 -1
  137. data/lib/datadog/open_feature/provider.rb +69 -12
  138. data/lib/datadog/open_feature/remote.rb +8 -1
  139. data/lib/datadog/open_feature/resolution_details.rb +2 -2
  140. data/lib/datadog/open_feature/transport.rb +6 -6
  141. data/lib/datadog/opentelemetry/api/context.rb +3 -3
  142. data/lib/datadog/opentelemetry/logs.rb +5 -5
  143. data/lib/datadog/opentelemetry/metrics.rb +3 -3
  144. data/lib/datadog/opentelemetry/sdk/propagator.rb +3 -3
  145. data/lib/datadog/opentelemetry/sdk/span_processor.rb +2 -2
  146. data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
  147. data/lib/datadog/profiling/collectors/code_provenance.rb +3 -3
  148. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +4 -4
  149. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
  150. data/lib/datadog/profiling/collectors/info.rb +37 -6
  151. data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
  152. data/lib/datadog/profiling/component.rb +41 -39
  153. data/lib/datadog/profiling/exporter.rb +4 -6
  154. data/lib/datadog/profiling/http_transport.rb +3 -3
  155. data/lib/datadog/profiling/profiler.rb +2 -2
  156. data/lib/datadog/profiling/scheduler.rb +2 -2
  157. data/lib/datadog/profiling/tag_builder.rb +1 -1
  158. data/lib/datadog/symbol_database/extractor.rb +8 -8
  159. data/lib/datadog/symbol_database/uploader.rb +1 -1
  160. data/lib/datadog/tracing/buffer.rb +3 -3
  161. data/lib/datadog/tracing/client_ip.rb +1 -1
  162. data/lib/datadog/tracing/component.rb +15 -10
  163. data/lib/datadog/tracing/configuration/dynamic/option.rb +2 -2
  164. data/lib/datadog/tracing/configuration/ext.rb +2 -0
  165. data/lib/datadog/tracing/configuration/settings.rb +14 -3
  166. data/lib/datadog/tracing/context.rb +1 -1
  167. data/lib/datadog/tracing/context_provider.rb +8 -0
  168. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +2 -2
  169. data/lib/datadog/tracing/contrib/active_job/data_streams.rb +27 -2
  170. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  171. data/lib/datadog/tracing/contrib/active_record/configuration/settings.rb +1 -1
  172. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  173. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +1 -1
  174. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +1 -1
  175. data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +2 -2
  176. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  177. data/lib/datadog/tracing/contrib/aws/configuration/settings.rb +1 -1
  178. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
  179. data/lib/datadog/tracing/contrib/dalli/configuration/settings.rb +1 -1
  180. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +1 -1
  181. data/lib/datadog/tracing/contrib/delayed_job/plugin.rb +2 -2
  182. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +1 -1
  183. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -3
  184. data/lib/datadog/tracing/contrib/ethon/configuration/settings.rb +1 -1
  185. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +17 -12
  186. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +1 -1
  187. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +1 -1
  188. data/lib/datadog/tracing/contrib/excon/middleware.rb +16 -9
  189. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +1 -1
  190. data/lib/datadog/tracing/contrib/faraday/middleware.rb +14 -8
  191. data/lib/datadog/tracing/contrib/grape/endpoint.rb +4 -4
  192. data/lib/datadog/tracing/contrib/graphql/patcher.rb +1 -1
  193. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +3 -3
  194. data/lib/datadog/tracing/contrib/grpc/configuration/settings.rb +1 -1
  195. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
  196. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
  197. data/lib/datadog/tracing/contrib/grpc.rb +1 -1
  198. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +1 -1
  199. data/lib/datadog/tracing/contrib/hanami/plugin.rb +1 -1
  200. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +1 -1
  201. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +1 -1
  202. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +1 -1
  203. data/lib/datadog/tracing/contrib/http/instrumentation.rb +21 -6
  204. data/lib/datadog/tracing/contrib/http.rb +1 -1
  205. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +1 -1
  206. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +14 -8
  207. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +1 -1
  208. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +14 -8
  209. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
  210. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
  211. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  212. data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
  213. data/lib/datadog/tracing/contrib/karafka.rb +1 -1
  214. data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -1
  215. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +1 -1
  216. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  217. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +1 -1
  218. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +1 -1
  219. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +3 -3
  220. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +2 -2
  221. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +3 -3
  222. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +1 -1
  223. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -4
  224. data/lib/datadog/tracing/contrib/presto/configuration/settings.rb +1 -1
  225. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +4 -4
  226. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +1 -1
  227. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  228. data/lib/datadog/tracing/contrib/racecar/configuration/settings.rb +1 -1
  229. data/lib/datadog/tracing/contrib/racecar/events/batch.rb +1 -1
  230. data/lib/datadog/tracing/contrib/racecar/events/message.rb +1 -1
  231. data/lib/datadog/tracing/contrib/rack/middlewares.rb +3 -3
  232. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  233. data/lib/datadog/tracing/contrib/rails/framework.rb +7 -7
  234. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  235. data/lib/datadog/tracing/contrib/rails/runner.rb +4 -4
  236. data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -1
  237. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  238. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
  239. data/lib/datadog/tracing/contrib/rest_client/configuration/settings.rb +1 -1
  240. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +17 -10
  241. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -1
  242. data/lib/datadog/tracing/contrib/sequel/dataset.rb +1 -1
  243. data/lib/datadog/tracing/contrib/shoryuken/tracer.rb +1 -1
  244. data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +2 -2
  245. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +2 -2
  246. data/lib/datadog/tracing/contrib/sidekiq.rb +1 -1
  247. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +1 -1
  248. data/lib/datadog/tracing/contrib/status_range_env_parser.rb +1 -1
  249. data/lib/datadog/tracing/contrib/sucker_punch/instrumentation.rb +1 -1
  250. data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +1 -1
  251. data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +3 -3
  252. data/lib/datadog/tracing/contrib/utils/quantization/http.rb +102 -0
  253. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +2 -2
  254. data/lib/datadog/tracing/contrib/waterdrop.rb +1 -1
  255. data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
  256. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  257. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  258. data/lib/datadog/tracing/distributed/baggage.rb +3 -3
  259. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  260. data/lib/datadog/tracing/distributed/propagation.rb +7 -7
  261. data/lib/datadog/tracing/distributed/trace_context.rb +1 -1
  262. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +1 -1
  263. data/lib/datadog/tracing/otel_thread_context.rb +3 -3
  264. data/lib/datadog/tracing/pipeline.rb +1 -1
  265. data/lib/datadog/tracing/remote.rb +50 -19
  266. data/lib/datadog/tracing/sampling/priority_sampler.rb +1 -1
  267. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  268. data/lib/datadog/tracing/sampling/rule_sampler.rb +1 -1
  269. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  270. data/lib/datadog/tracing/span_operation.rb +1 -1
  271. data/lib/datadog/tracing/trace_digest.rb +1 -1
  272. data/lib/datadog/tracing/trace_operation.rb +6 -6
  273. data/lib/datadog/tracing/tracer.rb +6 -6
  274. data/lib/datadog/tracing/transport/http/telemetry.rb +1 -1
  275. data/lib/datadog/tracing/transport/http.rb +2 -2
  276. data/lib/datadog/tracing/transport/io.rb +1 -1
  277. data/lib/datadog/tracing/transport/native.rb +3 -3
  278. data/lib/datadog/tracing/transport/statistics.rb +2 -2
  279. data/lib/datadog/tracing/transport/telemetry.rb +3 -1
  280. data/lib/datadog/tracing/transport/trace_formatter.rb +12 -12
  281. data/lib/datadog/tracing/transport/traces.rb +1 -1
  282. data/lib/datadog/tracing/utils.rb +1 -1
  283. data/lib/datadog/tracing/workers.rb +1 -1
  284. data/lib/datadog/version.rb +1 -1
  285. metadata +9 -8
  286. data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.15.1"
4
+ "rules_version": "1.17.0"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -3063,4 +3063,4 @@
3063
3063
  }
3064
3064
  }
3065
3065
  ]
3066
- }
3066
+ }
@@ -7,7 +7,7 @@ if %w[1 true].include?((Datadog::DATADOG_ENV["DD_APPSEC_ENABLED"] || "").downcas
7
7
  rescue => e
8
8
  Kernel.warn(
9
9
  "[datadog] AppSec failed to instrument. No security check will be performed. error: " \
10
- " #{e.class}: #{e.message}"
10
+ " #{e.class}: #{e.message}",
11
11
  )
12
12
  end
13
13
  end
@@ -26,7 +26,7 @@ module Datadog
26
26
  Datadog.logger.warn(
27
27
  "AppSec is not supported in Ruby versions above 3.3.0 when using `ffi` versions older than 1.16.0, " \
28
28
  "and will be forcibly disabled due to a memory leak in `ffi`. " \
29
- "Please upgrade your `ffi` version to 1.16.0 or higher."
29
+ "Please upgrade your `ffi` version to 1.16.0 or higher.",
30
30
  )
31
31
  telemetry.error("AppSec: Component not loaded, ffi version is leaky with ruby > 3.3.0")
32
32
 
@@ -28,7 +28,7 @@ module Datadog
28
28
 
29
29
  private_class_method def self.compress_and_encode(payload)
30
30
  Core::Utils::Base64Codec.strict_encode64(
31
- Zlib.gzip(payload, level: Zlib::BEST_SPEED, strategy: Zlib::DEFAULT_STRATEGY)
31
+ Zlib.gzip(payload, level: Zlib::BEST_SPEED, strategy: Zlib::DEFAULT_STRATEGY),
32
32
  )
33
33
  rescue Zlib::Error, TypeError => e
34
34
  AppSec.telemetry.report(e, description: "AppSec: Failed to compress and encode value")
@@ -34,7 +34,7 @@ module Datadog
34
34
  SAFE_TRACK_USER_EVENTS_MODE, EXTENDED_TRACK_USER_EVENTS_MODE,
35
35
  ].freeze
36
36
  APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES = ["1", "true"].concat(
37
- APPSEC_VALID_TRACK_USER_EVENTS_MODE
37
+ APPSEC_VALID_TRACK_USER_EVENTS_MODE,
38
38
  ).freeze
39
39
 
40
40
  def self.extended(base)
@@ -297,7 +297,7 @@ module Datadog
297
297
  Datadog.logger.warn(
298
298
  "The appsec.auto_user_instrumentation.mode value provided is not supported. " \
299
299
  "Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(" | ")}. " \
300
- "Using value: #{DISABLED_AUTO_USER_INSTRUMENTATION_MODE}."
300
+ "Using value: #{DISABLED_AUTO_USER_INSTRUMENTATION_MODE}.",
301
301
  )
302
302
 
303
303
  DISABLED_AUTO_USER_INSTRUMENTATION_MODE
@@ -342,7 +342,7 @@ module Datadog
342
342
  Datadog.logger.warn(
343
343
  "The appsec.track_user_events.mode value provided is not supported." \
344
344
  "Supported values are: #{APPSEC_VALID_TRACK_USER_EVENTS_MODE.join(" | ")}." \
345
- "Using default value: #{SAFE_TRACK_USER_EVENTS_MODE}."
345
+ "Using default value: #{SAFE_TRACK_USER_EVENTS_MODE}.",
346
346
  )
347
347
 
348
348
  SAFE_TRACK_USER_EVENTS_MODE
@@ -57,7 +57,7 @@ module Datadog
57
57
  @waf_runner = waf_runner
58
58
  @metrics = Metrics::Collector.new
59
59
  @downstream_body_sampler = CounterSampler.new(
60
- Datadog.configuration.appsec.api_security.downstream_body_analysis.sample_rate
60
+ Datadog.configuration.appsec.api_security.downstream_body_analysis.sample_rate,
61
61
  )
62
62
  @state = {
63
63
  events: [],
@@ -36,13 +36,23 @@ module Datadog
36
36
  TraceKeeper.keep!(context.trace) if result.keep?
37
37
 
38
38
  context.events.push(
39
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
39
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
40
40
  )
41
41
 
42
42
  AppSec::ActionsHandler.handle(result.actions)
43
43
  end
44
44
  end
45
45
 
46
+ module PreprocessQueryAdapterPatch
47
+ private
48
+
49
+ def preprocess_query(sql)
50
+ Instrumentation.detect_sql_injection(sql, adapter_name)
51
+
52
+ super
53
+ end
54
+ end
55
+
46
56
  # patch for mysql2, sqlite3, and postgres+jdbc adapters in ActiveRecord >= 7.1
47
57
  module InternalExecQueryAdapterPatch
48
58
  def internal_exec_query(sql, *args, **rest)
@@ -52,7 +52,9 @@ module Datadog
52
52
  end
53
53
 
54
54
  def patch_sqlite3_adapter
55
- instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
55
+ instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("8.0")
56
+ Instrumentation::PreprocessQueryAdapterPatch
57
+ elsif ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
56
58
  Instrumentation::InternalExecQueryAdapterPatch
57
59
  elsif ::ActiveRecord.gem_version.segments.first == 4
58
60
  Instrumentation::Rails4ExecQueryAdapterPatch
@@ -65,7 +67,9 @@ module Datadog
65
67
  end
66
68
 
67
69
  def patch_mysql2_adapter
68
- instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
70
+ instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("8.0")
71
+ Instrumentation::PreprocessQueryAdapterPatch
72
+ elsif ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
69
73
  Instrumentation::InternalExecQueryAdapterPatch
70
74
  elsif ::ActiveRecord.gem_version.segments.first == 4
71
75
  Instrumentation::Rails4ExecQueryAdapterPatch
@@ -78,14 +82,18 @@ module Datadog
78
82
  end
79
83
 
80
84
  def patch_postgresql_adapter
81
- instrumentation_module = if ::ActiveRecord.gem_version.segments.first == 4
85
+ instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("8.0")
86
+ Instrumentation::PreprocessQueryAdapterPatch
87
+ elsif ::ActiveRecord.gem_version.segments.first == 4
82
88
  Instrumentation::Rails4ExecuteAndClearAdapterPatch
83
89
  else
84
90
  Instrumentation::ExecuteAndClearAdapterPatch
85
91
  end
86
92
 
87
93
  if defined?(::ActiveRecord::ConnectionAdapters::JdbcAdapter)
88
- instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
94
+ instrumentation_module = if ::ActiveRecord.gem_version >= Gem::Version.new("8.0")
95
+ Instrumentation::PreprocessQueryAdapterPatch
96
+ elsif ::ActiveRecord.gem_version >= Gem::Version.new("7.1")
89
97
  Instrumentation::InternalExecQueryAdapterPatch
90
98
  elsif ::ActiveRecord.gem_version.segments.first == 4
91
99
  Instrumentation::Rails4ExecQueryAdapterPatch
@@ -30,7 +30,7 @@ module Datadog
30
30
 
31
31
  if result.match? || !result.attributes.empty?
32
32
  context.events.push(
33
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
33
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
34
34
  )
35
35
  end
36
36
 
@@ -57,7 +57,7 @@ module Datadog
57
57
  TraceKeeper.keep!(context.trace) if result.keep?
58
58
 
59
59
  context.events.push(
60
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
60
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
61
61
  )
62
62
 
63
63
  AppSec::ActionsHandler.handle(result.actions)
@@ -113,7 +113,7 @@ module Datadog
113
113
 
114
114
  body = Core::Utils::Base64Codec.strict_decode64(body) if payload["base64_encoded"]
115
115
  AppSec::Utils::HTTP::Body.parse(
116
- body, media_type: media_type, limit: Datadog.configuration.appsec.body_parsing_size_limit
116
+ body, media_type: media_type, limit: Datadog.configuration.appsec.body_parsing_size_limit,
117
117
  )
118
118
  rescue ArgumentError => e
119
119
  AppSec.telemetry.report(e, description: "AppSec: Failed to decode base64 body")
@@ -39,7 +39,7 @@ module Datadog
39
39
  if !appsec.track_user_events.options[:mode].default_precedence? &&
40
40
  appsec.auto_user_instrumentation.options[:mode].default_precedence?
41
41
  return TRACK_USER_EVENTS_CONVERSION_RULES.fetch(
42
- appsec.track_user_events.mode, appsec.auto_user_instrumentation.mode
42
+ appsec.track_user_events.mode, appsec.auto_user_instrumentation.mode,
43
43
  )
44
44
  end
45
45
 
@@ -64,7 +64,7 @@ module Datadog
64
64
  # and because of that we will trigger an additional event even
65
65
  # if it was already done via the SDK
66
66
  AppSec::Instrumentation.gateway.push(
67
- "identity.set_user", AppSec::Instrumentation::Gateway::User.new(id, login)
67
+ "identity.set_user", AppSec::Instrumentation::Gateway::User.new(id, login),
68
68
  )
69
69
  end
70
70
 
@@ -59,7 +59,7 @@ module Datadog
59
59
  # and because of that we will trigger an additional event even
60
60
  # if it was already done via the SDK
61
61
  AppSec::Instrumentation.gateway.push(
62
- "identity.set_user", AppSec::Instrumentation::Gateway::User.new(id, login)
62
+ "identity.set_user", AppSec::Instrumentation::Gateway::User.new(id, login),
63
63
  )
64
64
  end
65
65
  end
@@ -49,7 +49,7 @@ module Datadog
49
49
  # passing them at first place.
50
50
  # This is a temporary situation until we refactor events model.
51
51
  AppSec::Instrumentation.gateway.push(
52
- "identity.set_user", AppSec::Instrumentation::Gateway::User.new(user_id, nil, user_session_id)
52
+ "identity.set_user", AppSec::Instrumentation::Gateway::User.new(user_id, nil, user_session_id),
53
53
  )
54
54
  end
55
55
 
@@ -169,7 +169,7 @@ module Datadog
169
169
  TraceKeeper.keep!(context.trace) if result.keep?
170
170
 
171
171
  context.events.push(
172
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
172
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
173
173
  )
174
174
 
175
175
  AppSec::ActionsHandler.handle(result.actions)
@@ -154,7 +154,7 @@ module Datadog
154
154
  TraceKeeper.keep!(context.trace) if result.keep?
155
155
 
156
156
  context.events.push(
157
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
157
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
158
158
  )
159
159
 
160
160
  AppSec::ActionsHandler.handle(result.actions)
@@ -60,7 +60,7 @@ module Datadog
60
60
  when ::GraphQL::Language::Nodes::FragmentSpread
61
61
  fragment_name = selection.name
62
62
  append_arguments(
63
- args_hash, fragment_name, nil, arguments_from_directives(selection.directives, query_variables)
63
+ args_hash, fragment_name, nil, arguments_from_directives(selection.directives, query_variables),
64
64
  )
65
65
 
66
66
  next if visited_fragments[fragment_name]
@@ -69,13 +69,13 @@ module Datadog
69
69
  next unless fragment
70
70
 
71
71
  append_arguments(
72
- args_hash, fragment_name, nil, arguments_from_directives(fragment.directives, query_variables)
72
+ args_hash, fragment_name, nil, arguments_from_directives(fragment.directives, query_variables),
73
73
  )
74
74
 
75
75
  # re-used fragments are not expanded
76
76
  visited_fragments[fragment_name] = true
77
77
  arguments_from_selections(
78
- fragment.selections, query_variables, args_hash, fragments, visited_fragments
78
+ fragment.selections, query_variables, args_hash, fragments, visited_fragments,
79
79
  )
80
80
  when ::GraphQL::Language::Nodes::Field
81
81
  selection_name = selection.alias || selection.name
@@ -84,19 +84,19 @@ module Datadog
84
84
  args_hash,
85
85
  selection_name,
86
86
  field_arguments,
87
- arguments_from_directives(selection.directives, query_variables)
87
+ arguments_from_directives(selection.directives, query_variables),
88
88
  )
89
89
 
90
90
  arguments_from_selections(
91
- selection.selections, query_variables, args_hash, fragments, visited_fragments
91
+ selection.selections, query_variables, args_hash, fragments, visited_fragments,
92
92
  )
93
93
  when ::GraphQL::Language::Nodes::InlineFragment
94
94
  append_arguments(
95
- args_hash, selection.type.name, nil, arguments_from_directives(selection.directives, query_variables)
95
+ args_hash, selection.type.name, nil, arguments_from_directives(selection.directives, query_variables),
96
96
  )
97
97
 
98
98
  arguments_from_selections(
99
- selection.selections, query_variables, args_hash, fragments, visited_fragments
99
+ selection.selections, query_variables, args_hash, fragments, visited_fragments,
100
100
  )
101
101
  end
102
102
  end
@@ -37,7 +37,7 @@ module Datadog
37
37
  TraceKeeper.keep!(context.trace) if result.keep?
38
38
 
39
39
  context.events.push(
40
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
40
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
41
41
  )
42
42
 
43
43
  AppSec::ActionsHandler.handle(result.actions)
@@ -41,7 +41,7 @@ module Datadog
41
41
 
42
42
  if result.match? || !result.attributes.empty?
43
43
  context.events.push(
44
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
44
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
45
45
  )
46
46
  end
47
47
 
@@ -73,7 +73,7 @@ module Datadog
73
73
  TraceKeeper.keep!(context.trace) if result.keep?
74
74
 
75
75
  context.events.push(
76
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
76
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
77
77
  )
78
78
 
79
79
  AppSec::ActionsHandler.handle(result.actions)
@@ -119,7 +119,7 @@ module Datadog
119
119
  TraceKeeper.keep!(context.trace) if result.keep?
120
120
 
121
121
  context.events.push(
122
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
122
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
123
123
  )
124
124
 
125
125
  AppSec::ActionsHandler.handle(result.actions)
@@ -49,7 +49,7 @@ module Datadog
49
49
  return @app.call(env) unless security_engine
50
50
 
51
51
  ctx = Datadog::AppSec::Context.activate(
52
- Datadog::AppSec::Context.new(active_trace, active_span, security_engine.new_runner)
52
+ Datadog::AppSec::Context.new(active_trace, active_span, security_engine.new_runner),
53
53
  )
54
54
  env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx
55
55
 
@@ -68,7 +68,7 @@ module Datadog
68
68
  end
69
69
 
70
70
  gateway_response = Gateway::Response.new(
71
- http_response[2], http_response[0], http_response[1], context: ctx
71
+ http_response[2], http_response[0], http_response[1], context: ctx,
72
72
  )
73
73
 
74
74
  Instrumentation.gateway.push("rack.request.finish", gateway_request)
@@ -165,7 +165,7 @@ module Datadog
165
165
  trace.keep!
166
166
  trace.set_tag(
167
167
  Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
168
- Datadog::Tracing::Sampling::Ext::Decision::ASM
168
+ Datadog::Tracing::Sampling::Ext::Decision::ASM,
169
169
  )
170
170
  end
171
171
  end
@@ -182,7 +182,7 @@ module Datadog
182
182
  if span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
183
183
  # always collect client ip, as this is part of AppSec provided functionality
184
184
  Datadog::Tracing::ClientIp.set_client_ip_tag!(
185
- span, headers: headers, remote_ip: env["REMOTE_ADDR"]
185
+ span, headers: headers, remote_ip: env["REMOTE_ADDR"],
186
186
  )
187
187
  end
188
188
  end
@@ -192,7 +192,7 @@ module Datadog
192
192
  return unless span
193
193
 
194
194
  AppSec::DefaultHeaderTags.tag_response(
195
- span, Datadog::Core::HeaderCollection.from_hash(response.headers)
195
+ span, Datadog::Core::HeaderCollection.from_hash(response.headers),
196
196
  )
197
197
 
198
198
  unless response.headers.key?("content-length")
@@ -49,7 +49,7 @@ module Datadog
49
49
 
50
50
  if result.match?
51
51
  context.events.push(
52
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
52
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
53
53
  )
54
54
 
55
55
  AppSec::Event.tag(context, result)
@@ -66,14 +66,27 @@ module Datadog
66
66
  gateway.watch("rails.response.body.json") do |stack, container|
67
67
  context = container.context
68
68
 
69
+ body_bytesize = container.data.bytesize
70
+ limit = Datadog.configuration.appsec.body_parsing_size_limit
71
+
69
72
  persistent_data = {
70
- "server.response.body" => container.data,
73
+ "server.response.body.byte_length" => body_bytesize,
71
74
  }
72
- result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
75
+
76
+ if limit > 0 && body_bytesize <= limit
77
+ json = extract_json(container.data)
78
+ persistent_data["server.response.body"] = WAF::JSONString.new(json) if json
79
+ end
80
+
81
+ result = begin
82
+ context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
83
+ rescue WAF::ConversionError
84
+ next stack.call(container)
85
+ end
73
86
 
74
87
  if result.match?
75
88
  context.events.push(
76
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
89
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
77
90
  )
78
91
 
79
92
  AppSec::Event.tag(context, result)
@@ -85,6 +98,20 @@ module Datadog
85
98
  stack.call(container)
86
99
  end
87
100
  end
101
+
102
+ private
103
+
104
+ def extract_json(body)
105
+ return body unless body.start_with?("/**/")
106
+ return unless body.end_with?(")")
107
+
108
+ # NOTE: Best-effort support for standard Rails JSONP callbacks.
109
+ # Callback expressions with parentheses may prevent extraction
110
+ opening_parenthesis_index = body.b.index("(")
111
+ return unless opening_parenthesis_index
112
+
113
+ body.byteslice(opening_parenthesis_index + 1, body.bytesize - opening_parenthesis_index - 2) #: String
114
+ end
88
115
  end
89
116
  end
90
117
  end
@@ -66,7 +66,7 @@ module Datadog
66
66
  if include_middleware?(Datadog::Tracing::Contrib::Rack::TraceMiddleware, app)
67
67
  app.middleware.insert_after(
68
68
  Datadog::Tracing::Contrib::Rack::TraceMiddleware,
69
- Datadog::AppSec::Contrib::Rack::RequestMiddleware
69
+ Datadog::AppSec::Contrib::Rack::RequestMiddleware,
70
70
  )
71
71
  else
72
72
  app.middleware.insert_before(0, Datadog::AppSec::Contrib::Rack::RequestMiddleware)
@@ -162,7 +162,7 @@ module Datadog
162
162
 
163
163
  GUARD_ROUTES_REPORTING_ONCE_PER_APP[::Rails.application].run do
164
164
  AppSec.telemetry.app_endpoints_loaded(
165
- APISecurity::EndpointCollection::RailsCollector.new(routes).to_enum
165
+ APISecurity::EndpointCollection::RailsCollector.new(routes).to_enum,
166
166
  )
167
167
  end
168
168
  rescue => e
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../../utils/hash_coercion"
4
3
  require_relative "../../../instrumentation/gateway/argument"
5
4
 
6
5
  module Datadog
@@ -8,8 +7,8 @@ module Datadog
8
7
  module Contrib
9
8
  module Rails
10
9
  module Patches
11
- # A patch targeting `AbstractController::Rendering#render_to_body`
12
- # method to capture JSON response body right before it is serialized.
10
+ # A patch for `AbstractController::Rendering#render_to_body` that captures
11
+ # the serialized JSON response body for AppSec inspection
13
12
  module RenderToBodyPatch
14
13
  def render_to_body(options = {})
15
14
  return super unless options.key?(:json)
@@ -17,13 +16,15 @@ module Datadog
17
16
  context = request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
18
17
  return super unless context
19
18
 
20
- data = Utils::HashCoercion.coerce(options[:json])
21
- return super unless data
19
+ # NOTE: Custom renderers can return streaming bodies, which we
20
+ # currently do not inspect
21
+ body = super
22
+ return body unless body.is_a?(String)
22
23
 
23
- container = Instrumentation::Gateway::DataContainer.new(data, context: context)
24
+ container = Instrumentation::Gateway::DataContainer.new(body, context: context)
24
25
  Instrumentation.gateway.push("rails.response.body.json", container)
25
26
 
26
- super
27
+ body
27
28
  end
28
29
  end
29
30
  end
@@ -181,7 +181,7 @@ module Datadog
181
181
  TraceKeeper.keep!(context.trace) if result.keep?
182
182
 
183
183
  context.events.push(
184
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
184
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
185
185
  )
186
186
 
187
187
  AppSec::ActionsHandler.handle(result.actions)
@@ -56,7 +56,7 @@ module Datadog
56
56
 
57
57
  if result.match? || !result.attributes.empty?
58
58
  context.events.push(
59
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
59
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
60
60
  )
61
61
  end
62
62
 
@@ -87,7 +87,7 @@ module Datadog
87
87
  TraceKeeper.keep!(context.trace) if result.keep?
88
88
 
89
89
  context.events.push(
90
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
90
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
91
91
  )
92
92
 
93
93
  AppSec::ActionsHandler.handle(result.actions)
@@ -101,14 +101,26 @@ module Datadog
101
101
  gateway.watch("sinatra.response.body.json") do |stack, container|
102
102
  context = container.context # : Context
103
103
 
104
+ body_bytesize = container.data.bytesize
105
+ limit = Datadog.configuration.appsec.body_parsing_size_limit
106
+
104
107
  persistent_data = {
105
- "server.response.body" => container.data,
108
+ "server.response.body.byte_length" => body_bytesize,
106
109
  }
107
- result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
110
+
111
+ if limit > 0 && body_bytesize <= limit
112
+ persistent_data["server.response.body"] = WAF::JSONString.new(container.data)
113
+ end
114
+
115
+ result = begin
116
+ context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
117
+ rescue WAF::ConversionError
118
+ next stack.call(container)
119
+ end
108
120
 
109
121
  if result.match?
110
122
  context.events.push(
111
- AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
123
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span),
112
124
  )
113
125
 
114
126
  AppSec::Event.tag(context, result)
@@ -37,7 +37,7 @@ module Datadog
37
37
  tracing_sinatra_framework.add_middleware_after(
38
38
  tracing_middleware,
39
39
  Datadog::AppSec::Contrib::Rack::RequestMiddleware,
40
- builder
40
+ builder,
41
41
  )
42
42
  else
43
43
  tracing_sinatra_framework.add_middleware(Datadog::AppSec::Contrib::Rack::RequestMiddleware, builder)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../../utils/hash_coercion"
4
3
  require_relative "../../../instrumentation/gateway/argument"
5
4
 
6
5
  module Datadog
@@ -8,20 +7,22 @@ module Datadog
8
7
  module Contrib
9
8
  module Sinatra
10
9
  module Patches
11
- # A patch targeting `Sinatra::JSON#json` method to capture JSON response
12
- # body right before it is serialized.
10
+ # A patch for `Sinatra::JSON#json` that captures the serialized
11
+ # response body for AppSec inspection
13
12
  module JsonPatch
14
13
  def json(object, options = {})
15
14
  context = @request.env[Datadog::AppSec::Ext::CONTEXT_KEY] # : Context?
16
15
  return super unless context
17
16
 
18
- data = Utils::HashCoercion.coerce(object)
19
- return super unless data
17
+ # NOTE: Custom renderers can return streaming bodies, which we
18
+ # currently do not inspect
19
+ body = super
20
+ return body unless body.is_a?(String)
20
21
 
21
- container = Instrumentation::Gateway::DataContainer.new(data, context: context)
22
+ container = Instrumentation::Gateway::DataContainer.new(body, context: context)
22
23
  Instrumentation.gateway.push("sinatra.response.body.json", container)
23
24
 
24
- super
25
+ body
25
26
  end
26
27
  end
27
28
  end
@@ -14,7 +14,7 @@ module Datadog
14
14
  :duration_ext_ns,
15
15
  :inputs_truncated,
16
16
  :downstream_requests,
17
- keyword_init: true
17
+ keyword_init: true,
18
18
  )
19
19
 
20
20
  DownstreamResponseStore = Struct.new(
@@ -22,7 +22,7 @@ module Datadog
22
22
  :content_length_missing,
23
23
  :content_length_too_big,
24
24
  :content_exceed_content_length,
25
- keyword_init: true
25
+ keyword_init: true,
26
26
  )
27
27
 
28
28
  attr_reader :waf, :rasp, :downstream_responses
@@ -32,17 +32,17 @@ module Datadog
32
32
 
33
33
  @waf = Store.new(
34
34
  evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
35
- duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0
35
+ duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0,
36
36
  )
37
37
 
38
38
  @rasp = Store.new(
39
39
  evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0,
40
- duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0
40
+ duration_ext_ns: 0, inputs_truncated: 0, downstream_requests: 0,
41
41
  )
42
42
 
43
43
  @downstream_responses = DownstreamResponseStore.new(
44
44
  content_type_invalid: 0, content_length_missing: 0,
45
- content_length_too_big: 0, content_exceed_content_length: 0
45
+ content_length_too_big: 0, content_exceed_content_length: 0,
46
46
  )
47
47
  end
48
48