datadog 2.20.0 → 2.26.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 (310) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +212 -1
  3. data/README.md +0 -1
  4. data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +93 -23
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_stack.c +21 -5
  8. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
  9. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
  10. data/ext/datadog_profiling_native_extension/extconf.rb +9 -4
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  12. data/ext/datadog_profiling_native_extension/http_transport.c +1 -0
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
  15. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  16. data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
  17. data/ext/libdatadog_api/ddsketch.c +106 -0
  18. data/ext/libdatadog_api/feature_flags.c +554 -0
  19. data/ext/libdatadog_api/feature_flags.h +5 -0
  20. data/ext/libdatadog_api/init.c +5 -0
  21. data/ext/libdatadog_api/library_config.c +34 -25
  22. data/ext/libdatadog_api/process_discovery.c +24 -18
  23. data/ext/libdatadog_extconf_helpers.rb +1 -1
  24. data/lib/datadog/ai_guard/api_client.rb +82 -0
  25. data/lib/datadog/ai_guard/component.rb +42 -0
  26. data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
  27. data/lib/datadog/ai_guard/configuration/settings.rb +98 -0
  28. data/lib/datadog/ai_guard/configuration.rb +11 -0
  29. data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
  30. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +34 -0
  31. data/lib/datadog/ai_guard/evaluation/request.rb +81 -0
  32. data/lib/datadog/ai_guard/evaluation/result.rb +43 -0
  33. data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
  34. data/lib/datadog/ai_guard/evaluation.rb +72 -0
  35. data/lib/datadog/ai_guard/ext.rb +16 -0
  36. data/lib/datadog/ai_guard.rb +153 -0
  37. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  38. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
  39. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
  40. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  41. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  42. data/lib/datadog/appsec/api_security/route_extractor.rb +26 -5
  43. data/lib/datadog/appsec/api_security/sampler.rb +7 -4
  44. data/lib/datadog/appsec/assets/blocked.html +8 -0
  45. data/lib/datadog/appsec/assets/blocked.json +1 -1
  46. data/lib/datadog/appsec/assets/blocked.text +3 -1
  47. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  48. data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
  49. data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
  50. data/lib/datadog/appsec/assets.rb +1 -1
  51. data/lib/datadog/appsec/autoload.rb +1 -1
  52. data/lib/datadog/appsec/compressed_json.rb +1 -1
  53. data/lib/datadog/appsec/configuration/settings.rb +9 -0
  54. data/lib/datadog/appsec/context.rb +2 -1
  55. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  56. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
  57. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
  58. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
  59. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
  60. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
  61. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
  62. data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
  63. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
  64. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
  65. data/lib/datadog/appsec/event.rb +12 -14
  66. data/lib/datadog/appsec/metrics/collector.rb +19 -3
  67. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
  68. data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
  69. data/lib/datadog/appsec/remote.rb +34 -25
  70. data/lib/datadog/appsec/response.rb +18 -4
  71. data/lib/datadog/appsec/security_engine/engine.rb +3 -3
  72. data/lib/datadog/appsec/security_engine/result.rb +29 -9
  73. data/lib/datadog/appsec/security_engine/runner.rb +19 -9
  74. data/lib/datadog/appsec/security_event.rb +5 -7
  75. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -4
  76. data/lib/datadog/core/configuration/components.rb +59 -11
  77. data/lib/datadog/core/configuration/config_helper.rb +100 -0
  78. data/lib/datadog/core/configuration/deprecations.rb +36 -0
  79. data/lib/datadog/core/configuration/ext.rb +0 -1
  80. data/lib/datadog/core/configuration/option.rb +38 -43
  81. data/lib/datadog/core/configuration/option_definition.rb +4 -11
  82. data/lib/datadog/core/configuration/options.rb +9 -10
  83. data/lib/datadog/core/configuration/settings.rb +38 -9
  84. data/lib/datadog/core/configuration/stable_config.rb +10 -0
  85. data/lib/datadog/core/configuration/supported_configurations.rb +373 -0
  86. data/lib/datadog/core/configuration.rb +2 -2
  87. data/lib/datadog/core/ddsketch.rb +19 -0
  88. data/lib/datadog/core/deprecations.rb +2 -2
  89. data/lib/datadog/core/environment/cgroup.rb +52 -25
  90. data/lib/datadog/core/environment/container.rb +140 -46
  91. data/lib/datadog/core/environment/ext.rb +7 -2
  92. data/lib/datadog/core/environment/git.rb +2 -2
  93. data/lib/datadog/core/environment/process.rb +87 -0
  94. data/lib/datadog/core/environment/variable_helpers.rb +3 -3
  95. data/lib/datadog/core/environment/yjit.rb +2 -1
  96. data/lib/datadog/core/error.rb +6 -6
  97. data/lib/datadog/core/feature_flags.rb +61 -0
  98. data/lib/datadog/core/metrics/client.rb +2 -2
  99. data/lib/datadog/core/pin.rb +8 -8
  100. data/lib/datadog/core/process_discovery/tracer_memfd.rb +2 -4
  101. data/lib/datadog/core/process_discovery.rb +48 -23
  102. data/lib/datadog/core/rate_limiter.rb +9 -1
  103. data/lib/datadog/core/remote/client/capabilities.rb +7 -0
  104. data/lib/datadog/core/remote/client.rb +14 -6
  105. data/lib/datadog/core/remote/component.rb +10 -10
  106. data/lib/datadog/core/remote/configuration/content.rb +15 -2
  107. data/lib/datadog/core/remote/configuration/digest.rb +14 -7
  108. data/lib/datadog/core/remote/configuration/repository.rb +1 -1
  109. data/lib/datadog/core/remote/configuration/target.rb +13 -6
  110. data/lib/datadog/core/remote/transport/config.rb +4 -25
  111. data/lib/datadog/core/remote/transport/http/config.rb +10 -50
  112. data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
  113. data/lib/datadog/core/remote/transport/http.rb +15 -24
  114. data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
  115. data/lib/datadog/core/remote/worker.rb +25 -37
  116. data/lib/datadog/core/runtime/ext.rb +0 -1
  117. data/lib/datadog/core/runtime/metrics.rb +11 -1
  118. data/lib/datadog/core/semaphore.rb +1 -4
  119. data/lib/datadog/core/tag_builder.rb +0 -4
  120. data/lib/datadog/core/tag_normalizer.rb +84 -0
  121. data/lib/datadog/core/telemetry/component.rb +69 -15
  122. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  123. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  124. data/lib/datadog/core/telemetry/event/app_started.rb +89 -51
  125. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
  126. data/lib/datadog/core/telemetry/event.rb +1 -0
  127. data/lib/datadog/core/telemetry/logger.rb +2 -2
  128. data/lib/datadog/core/telemetry/logging.rb +2 -8
  129. data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
  130. data/lib/datadog/core/telemetry/request.rb +17 -3
  131. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +3 -34
  132. data/lib/datadog/core/telemetry/transport/http.rb +21 -16
  133. data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -11
  134. data/lib/datadog/core/telemetry/worker.rb +88 -32
  135. data/lib/datadog/core/transport/ext.rb +2 -0
  136. data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
  137. data/lib/datadog/core/transport/http/api/instance.rb +4 -21
  138. data/lib/datadog/core/transport/http/builder.rb +9 -5
  139. data/lib/datadog/core/transport/http/client.rb +80 -0
  140. data/lib/datadog/core/transport/http.rb +22 -19
  141. data/lib/datadog/core/transport/response.rb +15 -1
  142. data/lib/datadog/core/transport/transport.rb +90 -0
  143. data/lib/datadog/core/utils/array.rb +29 -0
  144. data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
  145. data/lib/datadog/core/utils/network.rb +22 -1
  146. data/lib/datadog/core/utils/only_once_successful.rb +8 -2
  147. data/lib/datadog/core/utils/safe_dup.rb +2 -2
  148. data/lib/datadog/core/utils/sequence.rb +2 -0
  149. data/lib/datadog/core/utils/time.rb +1 -1
  150. data/lib/datadog/core/utils.rb +2 -0
  151. data/lib/datadog/core/workers/async.rb +10 -1
  152. data/lib/datadog/core/workers/interval_loop.rb +44 -3
  153. data/lib/datadog/core/workers/polling.rb +2 -0
  154. data/lib/datadog/core/workers/queue.rb +100 -1
  155. data/lib/datadog/core.rb +2 -0
  156. data/lib/datadog/data_streams/configuration/settings.rb +49 -0
  157. data/lib/datadog/data_streams/configuration.rb +11 -0
  158. data/lib/datadog/data_streams/ext.rb +11 -0
  159. data/lib/datadog/data_streams/extensions.rb +16 -0
  160. data/lib/datadog/data_streams/pathway_context.rb +169 -0
  161. data/lib/datadog/data_streams/processor.rb +509 -0
  162. data/lib/datadog/data_streams/transport/http/stats.rb +52 -0
  163. data/lib/datadog/data_streams/transport/http.rb +40 -0
  164. data/lib/datadog/data_streams/transport/stats.rb +46 -0
  165. data/lib/datadog/data_streams.rb +100 -0
  166. data/lib/datadog/di/boot.rb +7 -3
  167. data/lib/datadog/di/component.rb +14 -16
  168. data/lib/datadog/di/context.rb +70 -0
  169. data/lib/datadog/di/contrib/active_record.rb +30 -5
  170. data/lib/datadog/di/el/compiler.rb +168 -0
  171. data/lib/datadog/di/el/evaluator.rb +159 -0
  172. data/lib/datadog/di/el/expression.rb +42 -0
  173. data/lib/datadog/di/el.rb +5 -0
  174. data/lib/datadog/di/error.rb +34 -0
  175. data/lib/datadog/di/instrumenter.rb +189 -55
  176. data/lib/datadog/di/logger.rb +2 -2
  177. data/lib/datadog/di/probe.rb +55 -15
  178. data/lib/datadog/di/probe_builder.rb +41 -2
  179. data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
  180. data/lib/datadog/di/probe_file_loader.rb +1 -1
  181. data/lib/datadog/di/probe_manager.rb +50 -35
  182. data/lib/datadog/di/probe_notification_builder.rb +121 -70
  183. data/lib/datadog/di/probe_notifier_worker.rb +5 -5
  184. data/lib/datadog/di/proc_responder.rb +32 -0
  185. data/lib/datadog/di/remote.rb +89 -84
  186. data/lib/datadog/di/serializer.rb +151 -7
  187. data/lib/datadog/di/transport/diagnostics.rb +8 -36
  188. data/lib/datadog/di/transport/http/diagnostics.rb +1 -33
  189. data/lib/datadog/di/transport/http/input.rb +1 -33
  190. data/lib/datadog/di/transport/http.rb +32 -17
  191. data/lib/datadog/di/transport/input.rb +67 -34
  192. data/lib/datadog/di.rb +61 -5
  193. data/lib/datadog/error_tracking/filters.rb +2 -2
  194. data/lib/datadog/kit/appsec/events/v2.rb +2 -3
  195. data/lib/datadog/open_feature/component.rb +60 -0
  196. data/lib/datadog/open_feature/configuration.rb +27 -0
  197. data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
  198. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  199. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  200. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  201. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  202. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  203. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  204. data/lib/datadog/open_feature/ext.rb +14 -0
  205. data/lib/datadog/open_feature/native_evaluator.rb +38 -0
  206. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  207. data/lib/datadog/open_feature/provider.rb +141 -0
  208. data/lib/datadog/open_feature/remote.rb +67 -0
  209. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  210. data/lib/datadog/open_feature/transport.rb +70 -0
  211. data/lib/datadog/open_feature.rb +19 -0
  212. data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
  213. data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
  214. data/lib/datadog/opentelemetry/metrics.rb +117 -0
  215. data/lib/datadog/opentelemetry/sdk/configurator.rb +26 -2
  216. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +35 -0
  217. data/lib/datadog/opentelemetry.rb +3 -0
  218. data/lib/datadog/profiling/collectors/code_provenance.rb +41 -7
  219. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -2
  220. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
  221. data/lib/datadog/profiling/collectors/info.rb +6 -5
  222. data/lib/datadog/profiling/component.rb +12 -11
  223. data/lib/datadog/profiling/ext/dir_monkey_patches.rb +18 -0
  224. data/lib/datadog/profiling/ext.rb +2 -1
  225. data/lib/datadog/profiling/http_transport.rb +5 -2
  226. data/lib/datadog/profiling/profiler.rb +4 -0
  227. data/lib/datadog/profiling/tag_builder.rb +36 -3
  228. data/lib/datadog/profiling/tasks/exec.rb +2 -2
  229. data/lib/datadog/profiling.rb +1 -2
  230. data/lib/datadog/single_step_instrument.rb +1 -1
  231. data/lib/datadog/tracing/component.rb +6 -17
  232. data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
  233. data/lib/datadog/tracing/configuration/ext.rb +9 -3
  234. data/lib/datadog/tracing/configuration/settings.rb +89 -10
  235. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
  236. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
  237. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  238. data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
  239. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
  240. data/lib/datadog/tracing/contrib/component.rb +2 -2
  241. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
  242. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
  243. data/lib/datadog/tracing/contrib/extensions.rb +10 -2
  244. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
  245. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
  246. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  247. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  248. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +84 -43
  249. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
  250. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
  251. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
  252. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  253. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  254. data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
  255. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  256. data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
  257. data/lib/datadog/tracing/contrib/karafka/patcher.rb +35 -4
  258. data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
  259. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -0
  260. data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
  261. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +7 -1
  262. data/lib/datadog/tracing/contrib/rails/ext.rb +2 -1
  263. data/lib/datadog/tracing/contrib/rails/integration.rb +1 -1
  264. data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
  265. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
  266. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
  267. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
  268. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +1 -1
  269. data/lib/datadog/tracing/contrib/status_range_matcher.rb +9 -1
  270. data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
  271. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
  272. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
  273. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
  274. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  275. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  276. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
  277. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  278. data/lib/datadog/tracing/contrib/waterdrop.rb +41 -0
  279. data/lib/datadog/tracing/contrib.rb +1 -0
  280. data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
  281. data/lib/datadog/tracing/distributed/baggage.rb +3 -2
  282. data/lib/datadog/tracing/metadata/ext.rb +9 -1
  283. data/lib/datadog/tracing/remote.rb +1 -9
  284. data/lib/datadog/tracing/sampling/priority_sampler.rb +3 -1
  285. data/lib/datadog/tracing/span.rb +1 -1
  286. data/lib/datadog/tracing/span_event.rb +2 -2
  287. data/lib/datadog/tracing/span_operation.rb +20 -9
  288. data/lib/datadog/tracing/trace_operation.rb +44 -6
  289. data/lib/datadog/tracing/tracer.rb +42 -16
  290. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  291. data/lib/datadog/tracing/transport/http/traces.rb +2 -50
  292. data/lib/datadog/tracing/transport/http.rb +15 -9
  293. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  294. data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
  295. data/lib/datadog/tracing/transport/traces.rb +9 -71
  296. data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
  297. data/lib/datadog/tracing/writer.rb +1 -0
  298. data/lib/datadog/version.rb +2 -2
  299. data/lib/datadog.rb +3 -0
  300. metadata +110 -24
  301. data/ext/libdatadog_api/macos_development.md +0 -26
  302. data/lib/datadog/core/remote/transport/http/api.rb +0 -53
  303. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  304. data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
  305. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  306. data/lib/datadog/core/transport/http/api/spec.rb +0 -36
  307. data/lib/datadog/di/transport/http/api.rb +0 -42
  308. data/lib/datadog/di/transport/http/client.rb +0 -47
  309. data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
  310. data/lib/datadog/tracing/transport/http/api.rb +0 -44
@@ -161,7 +161,7 @@ module Datadog
161
161
  if context.waf_runner_ruleset_version
162
162
  span.set_tag('_dd.appsec.event_rules.version', context.waf_runner_ruleset_version)
163
163
 
164
- unless @oneshot_tags_sent
164
+ unless oneshot_tags_sent?
165
165
  # Small race condition, but it's inoccuous: worst case the tags
166
166
  # are sent a couple of times more than expected
167
167
  @oneshot_tags_sent = true
@@ -204,6 +204,10 @@ module Datadog
204
204
  end
205
205
  # standard:enable Metrics/MethodLength
206
206
 
207
+ def oneshot_tags_sent?
208
+ @oneshot_tags_sent
209
+ end
210
+
207
211
  def to_rack_header(header)
208
212
  @rack_headers[header] ||= Datadog::Tracing::Contrib::Rack::Header.to_rack_header(header)
209
213
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../../event'
4
+ require_relative '../../../trace_keeper'
4
5
  require_relative '../../../security_event'
5
6
  require_relative '../../../instrumentation/gateway'
6
7
 
@@ -35,7 +36,9 @@ module Datadog
35
36
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
36
37
  )
37
38
 
38
- AppSec::Event.tag_and_keep!(context, result)
39
+ AppSec::Event.tag(context, result)
40
+ TraceKeeper.keep!(context.trace) if result.keep?
41
+
39
42
  AppSec::ActionsHandler.handle(result.actions)
40
43
  end
41
44
 
@@ -57,7 +60,9 @@ module Datadog
57
60
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
58
61
  )
59
62
 
60
- AppSec::Event.tag_and_keep!(context, result)
63
+ AppSec::Event.tag(context, result)
64
+ TraceKeeper.keep!(context.trace) if result.keep?
65
+
61
66
  AppSec::ActionsHandler.handle(result.actions)
62
67
  end
63
68
 
@@ -10,6 +10,7 @@ require_relative 'gateway/watcher'
10
10
  require_relative 'gateway/request'
11
11
  require_relative 'patches/render_to_body_patch'
12
12
  require_relative 'patches/process_action_patch'
13
+ require_relative '../../api_security/endpoint_collection/rails_collector'
13
14
 
14
15
  require_relative '../../../tracing/contrib/rack/middlewares'
15
16
 
@@ -20,6 +21,7 @@ module Datadog
20
21
  # Patcher for AppSec on Rails
21
22
  module Patcher
22
23
  GUARD_ACTION_CONTROLLER_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
24
+ GUARD_ROUTES_REPORTING_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
23
25
  BEFORE_INITIALIZE_ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
24
26
  AFTER_INITIALIZE_ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
25
27
 
@@ -38,6 +40,7 @@ module Datadog
38
40
  patch_before_initialize
39
41
  patch_after_initialize
40
42
  patch_action_controller
43
+ subscribe_to_routes_loaded
41
44
 
42
45
  Patcher.instance_variable_set(:@patched, true)
43
46
  end
@@ -128,7 +131,34 @@ module Datadog
128
131
  GUARD_ACTION_CONTROLLER_ONCE_PER_APP[self].run do
129
132
  ::ActionController::Base.prepend(Patches::RenderToBodyPatch)
130
133
  end
134
+
135
+ # Rails 7.1 adds `after_routes_loaded` hook
136
+ if Datadog::AppSec::Contrib::Rails::Patcher.target_version < Gem::Version.new('7.1')
137
+ Datadog::AppSec::Contrib::Rails::Patcher.report_routes_via_telemetry(::Rails.application.routes.routes)
138
+ end
139
+ end
140
+ end
141
+
142
+ def subscribe_to_routes_loaded
143
+ ::ActiveSupport.on_load(:after_routes_loaded) do |app|
144
+ Datadog::AppSec::Contrib::Rails::Patcher.report_routes_via_telemetry(app.routes.routes)
145
+ end
146
+ end
147
+
148
+ def report_routes_via_telemetry(routes)
149
+ # We do not support Rails 4.x for Endpoint Collection,
150
+ # mainly because the Route#verb was a Regexp before Rails 5.0
151
+ return if target_version < Gem::Version.new('5.0')
152
+ return unless Datadog.configuration.appsec.api_security.endpoint_collection.enabled
153
+ return unless AppSec.telemetry
154
+
155
+ GUARD_ROUTES_REPORTING_ONCE_PER_APP[::Rails.application].run do
156
+ AppSec.telemetry.app_endpoints_loaded(
157
+ APISecurity::EndpointCollection::RailsCollector.new(routes).to_enum
158
+ )
131
159
  end
160
+ rescue => e
161
+ AppSec.telemetry&.report(e, description: 'failed to report application endpoints')
132
162
  end
133
163
 
134
164
  def setup_security
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../event'
4
+ require_relative '../../trace_keeper'
4
5
  require_relative '../../security_event'
5
6
 
6
7
  module Datadog
@@ -18,7 +19,8 @@ module Datadog
18
19
  result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
19
20
 
20
21
  if result.match?
21
- AppSec::Event.tag_and_keep!(context, result)
22
+ AppSec::Event.tag(context, result)
23
+ TraceKeeper.keep!(context.trace) if result.keep?
22
24
 
23
25
  context.events.push(
24
26
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../../event'
4
+ require_relative '../../../trace_keeper'
4
5
  require_relative '../../../security_event'
5
6
  require_relative '../../../instrumentation/gateway'
6
7
 
@@ -30,14 +31,16 @@ module Datadog
30
31
 
31
32
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
32
33
 
33
- if result.match? || !result.derivatives.empty?
34
+ if result.match? || !result.attributes.empty?
34
35
  context.events.push(
35
36
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
36
37
  )
37
38
  end
38
39
 
39
40
  if result.match?
40
- AppSec::Event.tag_and_keep!(context, result)
41
+ AppSec::Event.tag(context, result)
42
+ TraceKeeper.keep!(context.trace) if result.keep?
43
+
41
44
  AppSec::ActionsHandler.handle(result.actions)
42
45
  end
43
46
 
@@ -56,7 +59,8 @@ module Datadog
56
59
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
57
60
 
58
61
  if result.match?
59
- AppSec::Event.tag_and_keep!(context, result)
62
+ AppSec::Event.tag(context, result)
63
+ TraceKeeper.keep!(context.trace) if result.keep?
60
64
 
61
65
  context.events.push(
62
66
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
@@ -83,7 +87,9 @@ module Datadog
83
87
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
84
88
  )
85
89
 
86
- AppSec::Event.tag_and_keep!(context, result)
90
+ AppSec::Event.tag(context, result)
91
+ TraceKeeper.keep!(context.trace) if result.keep?
92
+
87
93
  AppSec::ActionsHandler.handle(result.actions)
88
94
  end
89
95
 
@@ -9,8 +9,8 @@ module Datadog
9
9
  module AppSec
10
10
  # AppSec event
11
11
  module Event
12
- DERIVATIVE_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
13
- DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE = 25000
12
+ ATTRIBUTES_SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
13
+ ATTRIBUTES_SCHEMA_MAX_COMPRESSED_SIZE = 25000
14
14
  ALLOWED_REQUEST_HEADERS = %w[
15
15
  x-forwarded-for
16
16
  x-client-ip
@@ -40,16 +40,14 @@ module Datadog
40
40
  ].freeze
41
41
 
42
42
  class << self
43
- def tag_and_keep!(context, waf_result)
44
- TraceKeeper.keep!(context.trace)
43
+ def tag(context, waf_result)
44
+ return if context.span.nil?
45
45
 
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')
49
- end
50
-
51
- context.span.set_tag('appsec.event', 'true')
46
+ if waf_result.actions.key?('block_request') || waf_result.actions.key?('redirect_request')
47
+ context.span.set_tag('appsec.blocked', 'true')
52
48
  end
49
+
50
+ context.span.set_tag('appsec.event', 'true')
53
51
  end
54
52
 
55
53
  def record(context, request: nil, response: nil)
@@ -63,7 +61,7 @@ module Datadog
63
61
  end
64
62
  end
65
63
 
66
- if event_group.any? { |event| event.attack? || event.schema? }
64
+ if event_group.any? { |event| event.keep? || event.schema? }
67
65
  TraceKeeper.keep!(trace)
68
66
 
69
67
  context.span['_dd.origin'] = 'appsec'
@@ -106,13 +104,13 @@ module Datadog
106
104
  tags = security_events.each_with_object({}) do |security_event, memo|
107
105
  triggers.concat(security_event.waf_result.events)
108
106
 
109
- security_event.waf_result.derivatives.each do |key, value|
110
- next memo[key] = value unless key.start_with?(DERIVATIVE_SCHEMA_KEY_PREFIX)
107
+ security_event.waf_result.attributes.each do |key, value|
108
+ next memo[key] = value unless key.start_with?(ATTRIBUTES_SCHEMA_KEY_PREFIX)
111
109
 
112
110
  value = CompressedJson.dump(value)
113
111
  next if value.nil?
114
112
 
115
- if value.size >= DERIVATIVE_SCHEMA_MAX_COMPRESSED_SIZE
113
+ if value.size >= ATTRIBUTES_SCHEMA_MAX_COMPRESSED_SIZE
116
114
  Datadog.logger.debug { "AppSec: Schema key '#{key}' will not be included into span tags due to it's size" }
117
115
  next
118
116
  end
@@ -5,14 +5,28 @@ module Datadog
5
5
  module Metrics
6
6
  # A class responsible for collecting WAF and RASP call metrics.
7
7
  class Collector
8
- Store = Struct.new(:evals, :matches, :errors, :timeouts, :duration_ns, :duration_ext_ns, keyword_init: true)
8
+ Store = Struct.new(
9
+ :evals,
10
+ :matches,
11
+ :errors,
12
+ :timeouts,
13
+ :duration_ns,
14
+ :duration_ext_ns,
15
+ :inputs_truncated,
16
+ keyword_init: true
17
+ )
9
18
 
10
19
  attr_reader :waf, :rasp
11
20
 
12
21
  def initialize
13
22
  @mutex = Mutex.new
14
- @waf = Store.new(evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
15
- @rasp = Store.new(evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0)
23
+
24
+ @waf = Store.new(
25
+ evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0, inputs_truncated: 0
26
+ )
27
+ @rasp = Store.new(
28
+ evals: 0, matches: 0, errors: 0, timeouts: 0, duration_ns: 0, duration_ext_ns: 0, inputs_truncated: 0
29
+ )
16
30
  end
17
31
 
18
32
  def record_waf(result)
@@ -23,6 +37,7 @@ module Datadog
23
37
  @waf.timeouts += 1 if result.timeout?
24
38
  @waf.duration_ns += result.duration_ns
25
39
  @waf.duration_ext_ns += result.duration_ext_ns
40
+ @waf.inputs_truncated += 1 if result.input_truncated?
26
41
  end
27
42
  end
28
43
 
@@ -34,6 +49,7 @@ module Datadog
34
49
  @rasp.timeouts += 1 if result.timeout?
35
50
  @rasp.duration_ns += result.duration_ns
36
51
  @rasp.duration_ext_ns += result.duration_ext_ns
52
+ @rasp.inputs_truncated += 1 if result.input_truncated?
37
53
  end
38
54
  end
39
55
  end
@@ -18,7 +18,8 @@ module Datadog
18
18
  waf_timeout: metrics.timeouts.positive?.to_s,
19
19
  request_blocked: context.interrupted?.to_s,
20
20
  block_failure: 'false',
21
- rate_limited: (!context.trace.sampled?).to_s
21
+ rate_limited: (!context.trace.sampled?).to_s,
22
+ input_truncated: metrics.inputs_truncated.positive?.to_s,
22
23
  }
23
24
  )
24
25
  end
@@ -39,14 +39,14 @@ module Datadog
39
39
 
40
40
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
41
41
 
42
- if result.match? || result.derivatives.any?
42
+ if result.match? || result.attributes.any?
43
43
  context.events.push(
44
44
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
45
45
  )
46
46
  end
47
47
 
48
48
  if result.match?
49
- AppSec::Event.tag_and_keep!(context, result)
49
+ AppSec::Event.tag(context, result)
50
50
  AppSec::ActionsHandler.handle(result.actions)
51
51
  end
52
52
 
@@ -63,14 +63,14 @@ module Datadog
63
63
  persistent_data = {"server.business_logic.#{kind}" => ARBITRARY_VALUE}
64
64
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
65
65
 
66
- if result.match? || result.derivatives.any?
66
+ if result.match? || result.attributes.any?
67
67
  context.events.push(
68
68
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
69
69
  )
70
70
  end
71
71
 
72
72
  if result.match?
73
- AppSec::Event.tag_and_keep!(context, result)
73
+ AppSec::Event.tag(context, result)
74
74
  AppSec::ActionsHandler.handle(result.actions)
75
75
  end
76
76
 
@@ -7,24 +7,30 @@ module Datadog
7
7
  module AppSec
8
8
  # Remote
9
9
  module Remote
10
- class ReadError < StandardError; end
11
-
12
10
  class NoRulesError < StandardError; end
13
11
 
14
12
  class << self
15
- CAP_ASM_RESERVED_1 = 1 << 0 # RESERVED
16
- CAP_ASM_ACTIVATION = 1 << 1 # Remote activation via ASM_FEATURES product
17
- CAP_ASM_IP_BLOCKING = 1 << 2 # accept IP blocking data from ASM_DATA product
18
- CAP_ASM_DD_RULES = 1 << 3 # read ASM rules from ASM_DD product
19
- CAP_ASM_EXCLUSIONS = 1 << 4 # exclusion filters (passlist) via ASM product
20
- CAP_ASM_REQUEST_BLOCKING = 1 << 5 # can block on request info
21
- CAP_ASM_RESPONSE_BLOCKING = 1 << 6 # can block on response info
22
- CAP_ASM_USER_BLOCKING = 1 << 7 # accept user blocking data from ASM_DATA product
23
- CAP_ASM_CUSTOM_RULES = 1 << 8 # accept custom rules
24
- CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9 # supports custom http code or redirect sa blocking response
25
- CAP_ASM_TRUSTED_IPS = 1 << 10 # supports trusted ip
26
- CAP_ASM_RASP_SSRF = 1 << 23 # support for server-side request forgery exploit prevention rules
27
- CAP_ASM_RASP_SQLI = 1 << 21 # support for SQL injection exploit prevention rules
13
+ CAP_ASM_RESERVED_1 = 1 << 0
14
+ CAP_ASM_ACTIVATION = 1 << 1
15
+ CAP_ASM_IP_BLOCKING = 1 << 2
16
+ CAP_ASM_DD_RULES = 1 << 3
17
+ CAP_ASM_EXCLUSIONS = 1 << 4
18
+ CAP_ASM_REQUEST_BLOCKING = 1 << 5
19
+ CAP_ASM_RESPONSE_BLOCKING = 1 << 6
20
+ CAP_ASM_USER_BLOCKING = 1 << 7
21
+ CAP_ASM_CUSTOM_RULES = 1 << 8
22
+ CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9
23
+ CAP_ASM_TRUSTED_IPS = 1 << 10
24
+ CAP_ASM_PROCESSOR_OVERRIDES = 1 << 16
25
+ CAP_ASM_CUSTOM_DATA_SCANNERS = 1 << 17
26
+ CAP_ASM_RASP_SSRF = 1 << 23
27
+ CAP_ASM_RASP_SQLI = 1 << 21
28
+ CAP_ASM_AUTO_USER_INSTRUM_MODE = 1 << 31
29
+ CAP_ASM_ENDPOINT_FINGERPRINT = 1 << 32
30
+ CAP_ASM_SESSION_FINGERPRINT = 1 << 33
31
+ CAP_ASM_NETWORK_FINGERPRINT = 1 << 34
32
+ CAP_ASM_HEADER_FINGERPRINT = 1 << 35
33
+ CAP_ASM_TRACE_TAGGING_RULES = 1 << 43
28
34
 
29
35
  # TODO: we need to dynamically add CAP_ASM_ACTIVATION once we support it
30
36
  ASM_CAPABILITIES = [
@@ -37,8 +43,16 @@ module Datadog
37
43
  CAP_ASM_CUSTOM_RULES,
38
44
  CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
39
45
  CAP_ASM_TRUSTED_IPS,
46
+ CAP_ASM_PROCESSOR_OVERRIDES,
47
+ CAP_ASM_CUSTOM_DATA_SCANNERS,
40
48
  CAP_ASM_RASP_SSRF,
41
49
  CAP_ASM_RASP_SQLI,
50
+ CAP_ASM_AUTO_USER_INSTRUM_MODE,
51
+ CAP_ASM_ENDPOINT_FINGERPRINT,
52
+ CAP_ASM_SESSION_FINGERPRINT,
53
+ CAP_ASM_NETWORK_FINGERPRINT,
54
+ CAP_ASM_HEADER_FINGERPRINT,
55
+ CAP_ASM_TRACE_TAGGING_RULES,
42
56
  ].freeze
43
57
 
44
58
  ASM_PRODUCTS = [
@@ -69,11 +83,12 @@ module Datadog
69
83
 
70
84
  case change.type
71
85
  when :insert, :update
72
- AppSec.security_engine.add_or_update_config(parse_content(content), path: change.path.to_s) # steep:ignore
86
+ # @type var content: Core::Remote::Configuration::Content
87
+ AppSec.security_engine.add_or_update_config(parse_content(content), path: change.path.to_s)
73
88
 
74
- content.applied # steep:ignore
89
+ content.applied
75
90
  when :delete
76
- AppSec.security_engine.remove_config_at_path(change.path.to_s) # steep:ignore
91
+ AppSec.security_engine.remove_config_at_path(change.path.to_s)
77
92
  end
78
93
  end
79
94
 
@@ -93,13 +108,7 @@ module Datadog
93
108
  end
94
109
 
95
110
  def parse_content(content)
96
- data = content.data.read
97
-
98
- content.data.rewind
99
-
100
- raise ReadError, 'EOF reached' if data.nil?
101
-
102
- JSON.parse(data)
111
+ JSON.parse(content.data)
103
112
  end
104
113
  end
105
114
  end
@@ -7,6 +7,8 @@ module Datadog
7
7
  module AppSec
8
8
  # AppSec response
9
9
  class Response
10
+ SECURITY_RESPONSE_ID_PLACEHOLDER = '[security_response_id]'
11
+
10
12
  attr_reader :status, :headers, :body
11
13
 
12
14
  def initialize(status:, headers: {}, body: [])
@@ -37,16 +39,26 @@ module Datadog
37
39
  Response.new(
38
40
  status: interrupt_params['status_code']&.to_i || 403,
39
41
  headers: {'Content-Type' => content_type},
40
- body: [content(content_type)],
42
+ body: [
43
+ content(
44
+ security_response_id: interrupt_params['security_response_id'],
45
+ content_type: content_type
46
+ )
47
+ ],
41
48
  )
42
49
  end
43
50
 
44
51
  def redirect_response(interrupt_params)
45
52
  status_code = interrupt_params['status_code'].to_i
53
+ location = interrupt_params.fetch('location')
54
+
55
+ if (security_response_id = interrupt_params.fetch('security_response_id'))
56
+ location.gsub!(SECURITY_RESPONSE_ID_PLACEHOLDER, security_response_id)
57
+ end
46
58
 
47
59
  Response.new(
48
60
  status: ((status_code >= 300 && status_code < 400) ? status_code : 303),
49
- headers: {'Location' => interrupt_params.fetch('location')},
61
+ headers: {'Location' => location},
50
62
  body: [],
51
63
  )
52
64
  end
@@ -82,16 +94,18 @@ module Datadog
82
94
  DEFAULT_CONTENT_TYPE
83
95
  end
84
96
 
85
- def content(content_type)
97
+ def content(security_response_id:, content_type:)
86
98
  content_format = CONTENT_TYPE_TO_FORMAT[content_type]
87
99
 
88
100
  using_default = Datadog.configuration.appsec.block.templates.using_default?(content_format)
89
101
 
90
- if using_default
102
+ template = if using_default
91
103
  Datadog::AppSec::Assets.blocked(format: content_format)
92
104
  else
93
105
  Datadog.configuration.appsec.block.templates.send(content_format)
94
106
  end
107
+
108
+ template.gsub(SECURITY_RESPONSE_ID_PLACEHOLDER, security_response_id.to_s)
95
109
  end
96
110
  end
97
111
  end
@@ -54,17 +54,17 @@ module Datadog
54
54
  end
55
55
 
56
56
  def add_or_update_config(config, path:)
57
- @is_ruleset_update = path.include?('ASM_DD')
57
+ is_ruleset_update = path.include?('ASM_DD')
58
58
 
59
59
  # default config has to be removed when adding an ASM_DD config
60
- remove_config_at_path(DEFAULT_RULES_CONFIG_PATH) if @is_ruleset_update
60
+ remove_config_at_path(DEFAULT_RULES_CONFIG_PATH) if is_ruleset_update
61
61
 
62
62
  diagnostics = @waf_builder.add_or_update_config(config, path: path)
63
63
  @reconfigured_ruleset_version = diagnostics['ruleset_version'] if diagnostics.key?('ruleset_version')
64
64
  report_configuration_diagnostics(diagnostics, action: 'update', telemetry: AppSec.telemetry)
65
65
 
66
66
  # we need to load default config if diagnostics contains top-level error for rules or processors
67
- if @is_ruleset_update &&
67
+ if is_ruleset_update &&
68
68
  (diagnostics.key?('error') ||
69
69
  diagnostics.dig('rules', 'error') ||
70
70
  diagnostics.dig('processors', 'errors'))
@@ -7,20 +7,30 @@ module Datadog
7
7
  module Result
8
8
  # A generic result without indication of its type.
9
9
  class Base
10
- attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
10
+ attr_reader :events, :actions, :attributes, :duration_ns, :duration_ext_ns
11
11
 
12
- def initialize(events:, actions:, derivatives:, timeout:, duration_ns:, duration_ext_ns:)
12
+ def initialize(events:, actions:, attributes:, duration_ns:, duration_ext_ns:, timeout:, keep:, input_truncated:)
13
13
  @events = events
14
14
  @actions = actions
15
- @derivatives = derivatives
16
-
17
- @timeout = timeout
15
+ @attributes = attributes
18
16
  @duration_ns = duration_ns
19
17
  @duration_ext_ns = duration_ext_ns
18
+
19
+ @keep = !!keep
20
+ @timeout = !!timeout
21
+ @input_truncated = !!input_truncated
20
22
  end
21
23
 
22
24
  def timeout?
23
- !!@timeout
25
+ @timeout
26
+ end
27
+
28
+ def keep?
29
+ @keep
30
+ end
31
+
32
+ def input_truncated?
33
+ @input_truncated
24
34
  end
25
35
 
26
36
  def match?
@@ -56,19 +66,29 @@ module Datadog
56
66
 
57
67
  # A result that indicates an internal security library error
58
68
  class Error
59
- attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
69
+ attr_reader :events, :actions, :attributes, :duration_ns, :duration_ext_ns
60
70
 
61
- def initialize(duration_ext_ns:)
71
+ def initialize(duration_ext_ns:, input_truncated:)
62
72
  @events = []
63
- @actions = @derivatives = {}
73
+ @actions = {}.freeze
74
+ @attributes = {}.freeze
64
75
  @duration_ns = 0
65
76
  @duration_ext_ns = duration_ext_ns
77
+ @input_truncated = !!input_truncated
78
+ end
79
+
80
+ def keep?
81
+ false
66
82
  end
67
83
 
68
84
  def timeout?
69
85
  false
70
86
  end
71
87
 
88
+ def input_truncated?
89
+ @input_truncated
90
+ end
91
+
72
92
  def match?
73
93
  false
74
94
  end
@@ -27,13 +27,13 @@ module Datadog
27
27
  persistent_data.reject! do |_, v|
28
28
  next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
29
29
 
30
- v.nil? || v.empty?
30
+ v.nil? || (v.respond_to?(:empty?) && v.empty?)
31
31
  end
32
32
 
33
33
  ephemeral_data.reject! do |_, v|
34
34
  next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
35
35
 
36
- v.nil? || v.empty?
36
+ v.nil? || (v.respond_to?(:empty?) && v.empty?)
37
37
  end
38
38
 
39
39
  result = try_run(persistent_data, ephemeral_data, timeout)
@@ -42,17 +42,19 @@ module Datadog
42
42
  report_execution(result)
43
43
 
44
44
  unless SUCCESSFUL_EXECUTION_CODES.include?(result.status)
45
- return Result::Error.new(duration_ext_ns: stop_ns - start_ns)
45
+ return Result::Error.new(duration_ext_ns: stop_ns - start_ns, input_truncated: result.input_truncated?)
46
46
  end
47
47
 
48
48
  klass = (result.status == :match) ? Result::Match : Result::Ok
49
49
  klass.new(
50
50
  events: result.events,
51
51
  actions: result.actions,
52
- derivatives: result.derivatives,
53
- timeout: result.timeout,
54
- duration_ns: result.total_runtime,
55
- duration_ext_ns: (stop_ns - start_ns)
52
+ attributes: result.attributes,
53
+ keep: result.keep?,
54
+ timeout: result.timeout?,
55
+ duration_ns: result.duration,
56
+ duration_ext_ns: (stop_ns - start_ns),
57
+ input_truncated: result.input_truncated?
56
58
  )
57
59
  ensure
58
60
  @mutex.unlock
@@ -80,11 +82,19 @@ module Datadog
80
82
  Datadog.logger.debug { "#{@debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
81
83
  AppSec.telemetry.report(e, description: 'libddwaf-rb internal low-level error')
82
84
 
83
- WAF::Result.new(:err_internal, [], 0, false, [], [])
85
+ WAF::Result.new(
86
+ status: :err_internal,
87
+ events: [],
88
+ actions: {},
89
+ attributes: {},
90
+ duration: 0,
91
+ keep: false,
92
+ timeout: false
93
+ )
84
94
  end
85
95
 
86
96
  def report_execution(result)
87
- Datadog.logger.debug { "#{@debug_tag} execution timed out: #{result.inspect}" } if result.timeout
97
+ Datadog.logger.debug { "#{@debug_tag} execution timed out: #{result.inspect}" } if result.timeout?
88
98
 
89
99
  if SUCCESSFUL_EXECUTION_CODES.include?(result.status)
90
100
  Datadog.logger.debug { "#{@debug_tag} execution result: #{result.inspect}" }
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module AppSec
5
5
  # A class that represents a security event of any kind. It could be an event
6
- # representing an attack or fingerprinting results as derivatives or an API
6
+ # representing an attack or fingerprinting results as attributes or an API
7
7
  # security check with extracted schema.
8
8
  class SecurityEvent
9
9
  SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
@@ -17,22 +17,20 @@ module Datadog
17
17
  @span = span
18
18
  end
19
19
 
20
- def attack?
21
- return @is_attack if defined?(@is_attack)
22
-
23
- @is_attack = @waf_result.is_a?(SecurityEngine::Result::Match)
20
+ def keep?
21
+ @waf_result.keep?
24
22
  end
25
23
 
26
24
  def schema?
27
25
  return @has_schema if defined?(@has_schema)
28
26
 
29
- @has_schema = @waf_result.derivatives.any? { |name, _| name.start_with?(SCHEMA_KEY_PREFIX) }
27
+ @has_schema = @waf_result.attributes.any? { |name, _| name.start_with?(SCHEMA_KEY_PREFIX) }
30
28
  end
31
29
 
32
30
  def fingerprint?
33
31
  return @has_fingerprint if defined?(@has_fingerprint)
34
32
 
35
- @has_fingerprint = @waf_result.derivatives.any? { |name, _| name.start_with?(FINGERPRINT_KEY_PREFIX) }
33
+ @has_fingerprint = @waf_result.attributes.any? { |name, _| name.start_with?(FINGERPRINT_KEY_PREFIX) }
36
34
  end
37
35
  end
38
36
  end