datadog 2.30.0 → 2.32.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +11 -4
  5. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
  6. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
  7. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +7 -4
  9. data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
  10. data/ext/libdatadog_api/crashtracker.c +5 -8
  11. data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
  12. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  13. data/ext/libdatadog_api/di.c +127 -0
  14. data/ext/libdatadog_api/extconf.rb +9 -4
  15. data/ext/libdatadog_api/init.c +5 -2
  16. data/ext/libdatadog_extconf_helpers.rb +46 -1
  17. data/lib/datadog/ai_guard/component.rb +2 -0
  18. data/lib/datadog/ai_guard/configuration.rb +105 -2
  19. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
  20. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  21. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  22. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
  23. data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
  24. data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
  25. data/lib/datadog/ai_guard/evaluation.rb +37 -7
  26. data/lib/datadog/ai_guard/ext.rb +1 -0
  27. data/lib/datadog/ai_guard.rb +26 -8
  28. data/lib/datadog/appsec/autoload.rb +1 -1
  29. data/lib/datadog/appsec/component.rb +11 -7
  30. data/lib/datadog/appsec/configuration.rb +414 -1
  31. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
  32. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -7
  33. data/lib/datadog/appsec/instrumentation/gateway.rb +0 -13
  34. data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
  35. data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -0
  36. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  37. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  38. data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
  39. data/lib/datadog/appsec/utils/http/url_encoded.rb +3 -3
  40. data/lib/datadog/appsec.rb +5 -9
  41. data/lib/datadog/core/configuration/base.rb +17 -5
  42. data/lib/datadog/core/configuration/components.rb +22 -9
  43. data/lib/datadog/core/configuration/config_helper.rb +9 -0
  44. data/lib/datadog/core/configuration/option.rb +30 -5
  45. data/lib/datadog/core/configuration/option_definition.rb +38 -12
  46. data/lib/datadog/core/configuration/options.rb +40 -6
  47. data/lib/datadog/core/configuration/settings.rb +18 -0
  48. data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
  49. data/lib/datadog/core/configuration.rb +1 -1
  50. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  51. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  52. data/lib/datadog/core/crashtracking/component.rb +3 -3
  53. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  54. data/lib/datadog/core/environment/container.rb +2 -2
  55. data/lib/datadog/core/environment/ext.rb +1 -0
  56. data/lib/datadog/core/environment/identity.rb +25 -3
  57. data/lib/datadog/core/environment/process.rb +12 -0
  58. data/lib/datadog/core/feature_flags.rb +1 -1
  59. data/lib/datadog/core/metrics/client.rb +5 -5
  60. data/lib/datadog/core/remote/client.rb +1 -1
  61. data/lib/datadog/core/remote/component.rb +38 -21
  62. data/lib/datadog/core/runtime/metrics.rb +1 -1
  63. data/lib/datadog/core/telemetry/component.rb +3 -0
  64. data/lib/datadog/core/telemetry/emitter.rb +1 -1
  65. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
  66. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  67. data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
  68. data/lib/datadog/core/telemetry/event.rb +1 -7
  69. data/lib/datadog/core/telemetry/ext.rb +1 -0
  70. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
  71. data/lib/datadog/core/telemetry/worker.rb +20 -0
  72. data/lib/datadog/core/transport/http.rb +2 -0
  73. data/lib/datadog/core/utils/only_once.rb +1 -1
  74. data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
  75. data/lib/datadog/core/utils.rb +1 -1
  76. data/lib/datadog/core/workers/async.rb +1 -1
  77. data/lib/datadog/core.rb +1 -2
  78. data/lib/datadog/data_streams/configuration.rb +40 -1
  79. data/lib/datadog/data_streams/pathway_context.rb +1 -1
  80. data/lib/datadog/data_streams/processor.rb +1 -1
  81. data/lib/datadog/data_streams.rb +1 -1
  82. data/lib/datadog/di/base.rb +8 -5
  83. data/lib/datadog/di/boot.rb +2 -4
  84. data/lib/datadog/di/code_tracker.rb +179 -1
  85. data/lib/datadog/di/component.rb +5 -1
  86. data/lib/datadog/di/configuration.rb +235 -2
  87. data/lib/datadog/di/instrumenter.rb +55 -29
  88. data/lib/datadog/di/probe_builder.rb +1 -1
  89. data/lib/datadog/di/probe_file_loader.rb +2 -2
  90. data/lib/datadog/di/probe_manager.rb +6 -6
  91. data/lib/datadog/di/probe_notification_builder.rb +110 -2
  92. data/lib/datadog/di/probe_notifier_worker.rb +2 -2
  93. data/lib/datadog/di/remote.rb +6 -6
  94. data/lib/datadog/di/transport/input.rb +3 -3
  95. data/lib/datadog/di.rb +81 -0
  96. data/lib/datadog/error_tracking/configuration.rb +55 -2
  97. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  98. data/lib/datadog/open_feature/component.rb +18 -1
  99. data/lib/datadog/open_feature/evaluation_engine.rb +2 -2
  100. data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
  101. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  102. data/lib/datadog/open_feature/provider.rb +19 -1
  103. data/lib/datadog/open_feature/remote.rb +1 -1
  104. data/lib/datadog/open_feature/transport.rb +1 -1
  105. data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
  106. data/lib/datadog/opentelemetry/metrics.rb +3 -3
  107. data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
  108. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
  109. data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
  110. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
  111. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
  112. data/lib/datadog/profiling/collectors/info.rb +16 -3
  113. data/lib/datadog/profiling/component.rb +12 -4
  114. data/lib/datadog/profiling/exporter.rb +37 -12
  115. data/lib/datadog/profiling/ext.rb +0 -2
  116. data/lib/datadog/profiling/flush.rb +21 -12
  117. data/lib/datadog/profiling/http_transport.rb +12 -1
  118. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  119. data/lib/datadog/profiling/profiler.rb +13 -5
  120. data/lib/datadog/profiling/scheduler.rb +2 -2
  121. data/lib/datadog/profiling/tasks/exec.rb +8 -3
  122. data/lib/datadog/profiling/tasks/help.rb +1 -0
  123. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  124. data/lib/datadog/profiling.rb +1 -2
  125. data/lib/datadog/single_step_instrument.rb +1 -1
  126. data/lib/datadog/symbol_database/configuration.rb +65 -0
  127. data/lib/datadog/symbol_database/extractor.rb +915 -0
  128. data/lib/datadog/symbol_database/file_hash.rb +46 -0
  129. data/lib/datadog/symbol_database/logger.rb +43 -0
  130. data/lib/datadog/symbol_database/scope.rb +98 -0
  131. data/lib/datadog/symbol_database/service_version.rb +57 -0
  132. data/lib/datadog/symbol_database/symbol.rb +66 -0
  133. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  134. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  135. data/lib/datadog/symbol_database/transport.rb +54 -0
  136. data/lib/datadog/symbol_database/uploader.rb +166 -0
  137. data/lib/datadog/symbol_database.rb +49 -0
  138. data/lib/datadog/tracing/buffer.rb +3 -3
  139. data/lib/datadog/tracing/component.rb +11 -0
  140. data/lib/datadog/tracing/configuration/settings.rb +2 -1
  141. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
  142. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
  143. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
  144. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  145. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  146. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  147. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  148. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  149. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  150. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  151. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  152. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  153. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  154. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  155. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
  156. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  157. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
  158. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  159. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
  160. data/lib/datadog/tracing/contrib/component.rb +1 -1
  161. data/lib/datadog/tracing/contrib/configurable.rb +18 -3
  162. data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
  163. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  164. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
  165. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
  166. data/lib/datadog/tracing/contrib/extensions.rb +9 -0
  167. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
  168. data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
  169. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
  170. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
  171. data/lib/datadog/tracing/contrib/http/instrumentation.rb +3 -3
  172. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
  173. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +3 -3
  174. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
  175. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
  176. data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
  177. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
  178. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
  179. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
  180. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  181. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  182. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  183. data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
  184. data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
  185. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
  186. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  187. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
  188. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  189. data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
  190. data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
  191. data/lib/datadog/tracing/contrib.rb +8 -0
  192. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
  193. data/lib/datadog/tracing/distributed/baggage.rb +59 -5
  194. data/lib/datadog/tracing/distributed/datadog.rb +13 -11
  195. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
  196. data/lib/datadog/tracing/distributed/propagation.rb +2 -2
  197. data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
  198. data/lib/datadog/tracing/event.rb +1 -1
  199. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  200. data/lib/datadog/tracing/pipeline.rb +1 -1
  201. data/lib/datadog/tracing/remote.rb +1 -1
  202. data/lib/datadog/tracing/sampling/ext.rb +2 -0
  203. data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
  204. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  205. data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
  206. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  207. data/lib/datadog/tracing/span_operation.rb +4 -4
  208. data/lib/datadog/tracing/trace_operation.rb +53 -9
  209. data/lib/datadog/tracing/tracer.rb +29 -4
  210. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  211. data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
  212. data/lib/datadog/tracing/workers.rb +2 -1
  213. data/lib/datadog/version.rb +1 -1
  214. metadata +27 -12
  215. data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
  216. data/lib/datadog/appsec/configuration/settings.rb +0 -423
  217. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  218. data/lib/datadog/di/configuration/settings.rb +0 -243
  219. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
@@ -1,11 +1,424 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'configuration/settings'
3
+ require_relative '../core/utils/duration'
4
+ require_relative 'sample_rate'
4
5
 
5
6
  module Datadog
6
7
  module AppSec
7
8
  # Configuration for AppSec
8
9
  module Configuration
10
+ # Settings
11
+ module Settings
12
+ # rubocop:disable Layout/LineLength
13
+ DEFAULT_OBFUSCATOR_KEY_REGEX = '(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt'
14
+ DEFAULT_OBFUSCATOR_VALUE_REGEX = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=[^;]|"\s*:\s*"[^"]+")|bearer\s+[a-z0-9\._\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\w=-]+\.ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}[^\-]+[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*[a-z0-9\/\.+]{100,}'
15
+ # rubocop:enable Layout/LineLength
16
+
17
+ DISABLED_AUTO_USER_INSTRUMENTATION_MODE = 'disabled'
18
+ ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE = 'anonymization'
19
+ IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE = 'identification'
20
+ AUTO_USER_INSTRUMENTATION_MODES = [
21
+ DISABLED_AUTO_USER_INSTRUMENTATION_MODE,
22
+ ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
23
+ IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
24
+ ].freeze
25
+ AUTO_USER_INSTRUMENTATION_MODES_ALIASES = {
26
+ 'ident' => IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE,
27
+ 'anon' => ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE,
28
+ }.freeze
29
+
30
+ # NOTE: These two constants are deprecated
31
+ SAFE_TRACK_USER_EVENTS_MODE = 'safe'
32
+ EXTENDED_TRACK_USER_EVENTS_MODE = 'extended'
33
+ APPSEC_VALID_TRACK_USER_EVENTS_MODE = [
34
+ SAFE_TRACK_USER_EVENTS_MODE, EXTENDED_TRACK_USER_EVENTS_MODE
35
+ ].freeze
36
+ APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES = ['1', 'true'].concat(
37
+ APPSEC_VALID_TRACK_USER_EVENTS_MODE
38
+ ).freeze
39
+
40
+ def self.extended(base)
41
+ base = base.singleton_class unless base.is_a?(Class)
42
+ add_settings!(base)
43
+ end
44
+
45
+ # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/BlockLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
46
+ def self.add_settings!(base)
47
+ base.class_eval do
48
+ settings :appsec do
49
+ option :enabled do |o|
50
+ o.type :bool
51
+ o.env 'DD_APPSEC_ENABLED'
52
+ o.default false
53
+ end
54
+
55
+ define_method(:instrument) do |integration_name|
56
+ if enabled
57
+ registered_integration = Datadog::AppSec::Contrib::Integration.registry[integration_name]
58
+ if registered_integration
59
+ klass = registered_integration.klass
60
+ if klass.loaded? && klass.compatible?
61
+ instance = klass.new
62
+ instance.patcher.patch unless instance.patcher.patched?
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ # RASP or Runtime Application Self-Protection
69
+ # is a collection of techniques and heuristics aimed at detecting malicious inputs and preventing
70
+ # any potential side-effects on the application resulting from the use of said malicious inputs.
71
+ option :rasp_enabled do |o|
72
+ o.type :bool, nilable: true
73
+ o.env 'DD_APPSEC_RASP_ENABLED'
74
+ o.default true
75
+ end
76
+
77
+ option :ruleset do |o|
78
+ o.env 'DD_APPSEC_RULES'
79
+ o.default :recommended
80
+ end
81
+
82
+ option :ip_passlist do |o|
83
+ o.default []
84
+
85
+ o.setter do |value|
86
+ next value if value.nil? || value.empty?
87
+
88
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
89
+ 'The ip_passlist setting is deprecated and will be removed in the next release. ' \
90
+ 'Please migrate this configuration to your service settings via the Datadog UI'
91
+ end
92
+
93
+ value
94
+ end
95
+ end
96
+
97
+ option :ip_denylist do |o|
98
+ o.type :array
99
+ o.default []
100
+
101
+ o.setter do |value|
102
+ next value if value.nil? || value.empty?
103
+
104
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
105
+ 'The ip_denylist setting is deprecated and will be removed in the next release. ' \
106
+ 'Please migrate this configuration to your service settings via the Datadog UI'
107
+ end
108
+
109
+ value
110
+ end
111
+ end
112
+
113
+ option :user_id_denylist do |o|
114
+ o.type :array
115
+ o.default []
116
+
117
+ o.setter do |value|
118
+ next value if value.nil? || value.empty?
119
+
120
+ Datadog::Core.log_deprecation(disallowed_next_major: false) do
121
+ 'The user_id_denylist setting is deprecated and will be removed in the next release. ' \
122
+ 'Please migrate this configuration to your service settings via the Datadog UI'
123
+ end
124
+
125
+ value
126
+ end
127
+ end
128
+
129
+ option :waf_timeout do |o|
130
+ o.env 'DD_APPSEC_WAF_TIMEOUT' # us
131
+ o.default 5_000
132
+ o.setter do |v|
133
+ Datadog::Core::Utils::Duration.call(v.to_s, base: :us)
134
+ end
135
+ end
136
+
137
+ option :waf_debug do |o|
138
+ o.env 'DD_APPSEC_WAF_DEBUG'
139
+ o.default false
140
+ o.type :bool
141
+ end
142
+
143
+ option :trace_rate_limit do |o|
144
+ o.type :int
145
+ o.env 'DD_APPSEC_TRACE_RATE_LIMIT' # trace/s
146
+ o.default 100
147
+ end
148
+
149
+ option :obfuscator_key_regex do |o|
150
+ o.type :string
151
+ o.env 'DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP'
152
+ o.default DEFAULT_OBFUSCATOR_KEY_REGEX
153
+ end
154
+
155
+ option :obfuscator_value_regex do |o|
156
+ o.type :string
157
+ o.env 'DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP'
158
+ o.default DEFAULT_OBFUSCATOR_VALUE_REGEX
159
+ end
160
+
161
+ settings :block do
162
+ settings :templates do
163
+ option :html do |o|
164
+ o.env 'DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML'
165
+ o.type :string, nilable: true
166
+ o.setter do |value|
167
+ if value
168
+ unless File.exist?(value)
169
+ raise(ArgumentError,
170
+ "appsec.templates.html: file not found: #{value}")
171
+ end
172
+
173
+ File.binread(value) || ''
174
+ end
175
+ end
176
+ end
177
+
178
+ option :json do |o|
179
+ o.env 'DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON'
180
+ o.type :string, nilable: true
181
+ o.setter do |value|
182
+ if value
183
+ unless File.exist?(value)
184
+ raise(ArgumentError,
185
+ "appsec.templates.json: file not found: #{value}")
186
+ end
187
+
188
+ File.binread(value) || ''
189
+ end
190
+ end
191
+ end
192
+
193
+ option :text do |o|
194
+ o.env 'DD_APPSEC_HTTP_BLOCKED_TEMPLATE_TEXT'
195
+ o.type :string, nilable: true
196
+ o.setter do |value|
197
+ if value
198
+ unless File.exist?(value)
199
+ raise(ArgumentError,
200
+ "appsec.templates.text: file not found: #{value}")
201
+ end
202
+
203
+ File.binread(value) || ''
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ settings :stack_trace do
211
+ option :enabled do |o|
212
+ o.type :bool
213
+ o.env 'DD_APPSEC_STACK_TRACE_ENABLED'
214
+ o.default true
215
+ end
216
+
217
+ # The maximum number of stack trace frames to collect for each stack trace.
218
+ #
219
+ # If the stack trace exceeds this limit, the frames are dropped from the middle of the stack trace:
220
+ # 75% of the frames are kept from the top of the stack trace and 25% from the bottom
221
+ # (this percentage is also configurable).
222
+ #
223
+ # Minimum value is 10.
224
+ # Set to zero if you don't want any frames to be dropped.
225
+ #
226
+ # Default value is 32
227
+ option :max_depth do |o|
228
+ o.type :int
229
+ o.env 'DD_APPSEC_MAX_STACK_TRACE_DEPTH'
230
+ o.default 32
231
+
232
+ o.setter do |value|
233
+ value = 0 if value < 0
234
+ value
235
+ end
236
+ end
237
+
238
+ # The percentage of frames to keep from the top of the stack trace.
239
+ #
240
+ # Default value is 75
241
+ option :top_percentage do |o|
242
+ o.type :int
243
+ o.env 'DD_APPSEC_MAX_STACK_TRACE_DEPTH_TOP_PERCENT'
244
+ o.default 75
245
+
246
+ o.setter do |value|
247
+ value = 100 if value > 100
248
+ value = 0 if value.negative?
249
+ value
250
+ end
251
+ end
252
+
253
+ # Maximum number of stack traces to collect per span.
254
+ #
255
+ # Set to zero if you want to collect all stack traces.
256
+ #
257
+ # Default value is 2
258
+ option :max_stack_traces do |o|
259
+ o.type :int
260
+ o.env 'DD_APPSEC_MAX_STACK_TRACES'
261
+ o.default 2
262
+
263
+ o.setter do |value|
264
+ value = 0 if value < 0
265
+ value
266
+ end
267
+ end
268
+ end
269
+
270
+ settings :auto_user_instrumentation do
271
+ define_method(:enabled?) { get_option(:mode) != DISABLED_AUTO_USER_INSTRUMENTATION_MODE }
272
+
273
+ option :mode do |o|
274
+ o.type :string
275
+ o.env 'DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE'
276
+ o.default IDENTIFICATION_AUTO_USER_INSTRUMENTATION_MODE
277
+ o.setter do |value|
278
+ mode = AUTO_USER_INSTRUMENTATION_MODES_ALIASES.fetch(value, value)
279
+ next mode if AUTO_USER_INSTRUMENTATION_MODES.include?(mode)
280
+
281
+ Datadog.logger.warn(
282
+ 'The appsec.auto_user_instrumentation.mode value provided is not supported. ' \
283
+ "Supported values are: #{AUTO_USER_INSTRUMENTATION_MODES.join(" | ")}. " \
284
+ "Using value: #{DISABLED_AUTO_USER_INSTRUMENTATION_MODE}."
285
+ )
286
+
287
+ DISABLED_AUTO_USER_INSTRUMENTATION_MODE
288
+ end
289
+ end
290
+ end
291
+
292
+ # DEV-3.0: Remove `track_user_events.enabled` and `track_user_events.mode` options
293
+ settings :track_user_events do
294
+ option :enabled do |o|
295
+ o.default true
296
+ o.type :bool
297
+ o.env 'DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING'
298
+ o.env_parser do |env_value|
299
+ if env_value == 'disabled'
300
+ false
301
+ else
302
+ APPSEC_VALID_TRACK_USER_EVENTS_ENABLED_VALUES.include?(env_value.strip.downcase)
303
+ end
304
+ end
305
+ o.after_set do |_, _, precedence|
306
+ unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
307
+ Core.log_deprecation(key: :appsec_track_user_events_enabled) do
308
+ 'The appsec.track_user_events.enabled setting is deprecated. ' \
309
+ 'Please remove it from your Datadog.configure block and use ' \
310
+ 'appsec.auto_user_instrumentation.mode instead.'
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ option :mode do |o|
317
+ o.type :string
318
+ o.env 'DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING'
319
+ o.default SAFE_TRACK_USER_EVENTS_MODE
320
+ o.setter do |v|
321
+ if APPSEC_VALID_TRACK_USER_EVENTS_MODE.include?(v)
322
+ v
323
+ elsif v == 'disabled'
324
+ SAFE_TRACK_USER_EVENTS_MODE
325
+ else
326
+ Datadog.logger.warn(
327
+ 'The appsec.track_user_events.mode value provided is not supported.' \
328
+ "Supported values are: #{APPSEC_VALID_TRACK_USER_EVENTS_MODE.join(" | ")}." \
329
+ "Using default value: #{SAFE_TRACK_USER_EVENTS_MODE}."
330
+ )
331
+
332
+ SAFE_TRACK_USER_EVENTS_MODE
333
+ end
334
+ end
335
+ o.after_set do |_, _, precedence|
336
+ unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
337
+ Core.log_deprecation(key: :appsec_track_user_events_mode) do
338
+ 'The appsec.track_user_events.mode setting is deprecated. ' \
339
+ 'Please remove it from your Datadog.configure block and use ' \
340
+ 'appsec.auto_user_instrumentation.mode instead.'
341
+ end
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ settings :api_security do
348
+ define_method(:enabled?) { get_option(:enabled) }
349
+
350
+ option :enabled do |o|
351
+ o.type :bool
352
+ o.env 'DD_API_SECURITY_ENABLED'
353
+ o.default true
354
+ end
355
+
356
+ settings :endpoint_collection do
357
+ # Enables reporting of application routes at application start via telemetry
358
+ option :enabled do |o|
359
+ o.type :bool, nilable: true
360
+ o.env 'DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED'
361
+ o.default true
362
+ end
363
+ end
364
+
365
+ # NOTE: Unfortunately, we have to go with Float due to other libs
366
+ # setup, even tho we don't plan to support sub-second delays.
367
+ #
368
+ # WARNING: The value will be converted to Integer.
369
+ option :sample_delay do |o|
370
+ o.type :float
371
+ o.env 'DD_API_SECURITY_SAMPLE_DELAY'
372
+ o.default 30
373
+ o.setter do |value|
374
+ value.to_i
375
+ end
376
+ end
377
+
378
+ # DEV-3.0: Remove `api_security.sample_rate` option
379
+ option :sample_rate do |o|
380
+ o.type :float
381
+ o.env 'DD_API_SECURITY_REQUEST_SAMPLE_RATE'
382
+ o.default 0.1
383
+ o.setter do |value|
384
+ value = 1 if value > 1
385
+ SampleRate.new(value)
386
+ end
387
+ o.after_set do |_, _, precedence|
388
+ next if precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
389
+
390
+ Core.log_deprecation(key: :appsec_api_security_sample_rate) do
391
+ 'The appsec.api_security.sample_rate setting is deprecated. ' \
392
+ 'Please remove it from your Datadog.configure block and use ' \
393
+ 'appsec.api_security.sample_delay instead.'
394
+ end
395
+ end
396
+ end
397
+
398
+ settings :downstream_body_analysis do
399
+ option :sample_rate do |o|
400
+ o.type :float
401
+ o.env 'DD_API_SECURITY_DOWNSTREAM_BODY_ANALYSIS_SAMPLE_RATE'
402
+ o.default 0.5
403
+ end
404
+
405
+ option :max_requests do |o|
406
+ o.type :int
407
+ o.env 'DD_API_SECURITY_MAX_DOWNSTREAM_REQUEST_BODY_ANALYSIS'
408
+ o.default 1
409
+ end
410
+ end
411
+ end
412
+
413
+ option :sca_enabled do |o|
414
+ o.type :bool, nilable: true
415
+ o.env 'DD_APPSEC_SCA_ENABLED'
416
+ end
417
+ end
418
+ end
419
+ end
420
+ # rubocop:enable Metrics/AbcSize,Metrics/MethodLength,Metrics/BlockLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
421
+ end
9
422
  end
10
423
  end
11
424
  end
@@ -18,9 +18,10 @@ module Datadog
18
18
  return result unless AppSec.enabled?
19
19
  return result if @_datadog_appsec_skip_track_login_event
20
20
  return result unless Configuration.auto_user_instrumentation_enabled?
21
- return result unless AppSec.active_context
22
21
 
23
22
  context = AppSec.active_context
23
+ return result unless context
24
+
24
25
  if context.trace.nil? || context.span.nil?
25
26
  Datadog.logger.debug { 'AppSec: unable to track signin events, due to missing trace or span' }
26
27
  return result
@@ -116,17 +116,16 @@ module Datadog
116
116
  gateway.watch('rack.request.finish') do |stack, gateway_request|
117
117
  context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
118
118
 
119
- if context.span.nil? || !gateway.pushed?('appsec.events.user_lifecycle')
120
- next stack.call(gateway_request.request)
121
- end
119
+ next stack.call(gateway_request.request) if context.span.nil?
122
120
 
123
121
  gateway_request.headers.each do |name, value|
124
- if !Ext::COLLECTABLE_REQUEST_HEADERS.include?(name) &&
125
- !Ext::IDENTITY_COLLECTABLE_REQUEST_HEADERS.include?(name)
126
- next
122
+ if Ext::COLLECTABLE_REQUEST_HEADERS.include?(name)
123
+ context.span["http.request.headers.#{name}"] ||= value
127
124
  end
128
125
 
129
- context.span["http.request.headers.#{name}"] ||= value
126
+ if context.state[:has_identity_event] && Ext::IDENTITY_COLLECTABLE_REQUEST_HEADERS.include?(name)
127
+ context.span["http.request.headers.#{name}"] ||= value
128
+ end
130
129
  end
131
130
 
132
131
  stack.call(gateway_request.request)
@@ -10,18 +10,9 @@ module Datadog
10
10
  class Gateway
11
11
  def initialize
12
12
  @middlewares = Hash.new { |h, k| h[k] = [] }
13
- @pushed_events = {}
14
13
  end
15
14
 
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.
22
15
  def push(name, env, &block)
23
- @pushed_events[name] = true
24
-
25
16
  block ||= -> {}
26
17
  middlewares_for_name = @middlewares[name]
27
18
 
@@ -44,10 +35,6 @@ module Datadog
44
35
  def watch(name, &block)
45
36
  @middlewares[name] << Middleware.new(&block)
46
37
  end
47
-
48
- def pushed?(name)
49
- @pushed_events.key?(name)
50
- end
51
38
  end
52
39
 
53
40
  # NOTE: This left as-is and will be depricated soon.
@@ -5,6 +5,11 @@ module Datadog
5
5
  module Metrics
6
6
  # A class responsible for reporting WAF and RASP telemetry metrics.
7
7
  module Telemetry
8
+ ACTION_BLOCK = 'block_request'
9
+ ACTION_REDIRECT = 'redirect_request'
10
+ BLOCK_SUCCESS = 'success'
11
+ BLOCK_IRRELEVANT = 'irrelevant'
12
+
8
13
  module_function
9
14
 
10
15
  def report_rasp(type, result, phase: nil)
@@ -19,8 +24,15 @@ module Datadog
19
24
  namespace = Ext::TELEMETRY_METRICS_NAMESPACE
20
25
 
21
26
  AppSec.telemetry.inc(namespace, 'rasp.rule.eval', 1, tags: tags)
22
- AppSec.telemetry.inc(namespace, 'rasp.rule.match', 1, tags: tags) if result.match?
23
27
  AppSec.telemetry.inc(namespace, 'rasp.timeout', 1, tags: tags) if result.timeout?
28
+
29
+ if result.match?
30
+ blocked = result.actions.key?(ACTION_BLOCK) || result.actions.key?(ACTION_REDIRECT)
31
+ # NOTE: Mutates tags to avoid an extra hash allocation. Keep this the last .inc call.
32
+ tags[:block] = blocked ? BLOCK_SUCCESS : BLOCK_IRRELEVANT
33
+
34
+ AppSec.telemetry.inc(namespace, 'rasp.rule.match', 1, tags: tags)
35
+ end
24
36
  end
25
37
  end
26
38
  end
@@ -26,6 +26,7 @@ module Datadog
26
26
  def watch_user_id(gateway = Instrumentation.gateway)
27
27
  gateway.watch('identity.set_user') do |stack, user|
28
28
  context = AppSec.active_context
29
+ context.state[:has_identity_event] = true
29
30
 
30
31
  if user.id.nil? && user.login.nil? && user.session_id.nil?
31
32
  Datadog.logger.debug { 'AppSec: skipping WAF check because no user information was provided' }
@@ -57,6 +58,7 @@ module Datadog
57
58
  def watch_user_login(gateway = Instrumentation.gateway)
58
59
  gateway.watch('appsec.events.user_lifecycle') do |stack, kind|
59
60
  context = AppSec.active_context
61
+ context.state[:has_identity_event] = true
60
62
 
61
63
  next stack.call(kind) unless WATCHED_LOGIN_EVENTS.include?(kind)
62
64
 
@@ -79,7 +79,7 @@ module Datadog
79
79
  def try_run(persistent_data, ephemeral_data, timeout)
80
80
  waf_context.run(persistent_data, ephemeral_data, timeout)
81
81
  rescue WAF::LibDDWAFError => e
82
- Datadog.logger.debug { "#{@debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
82
+ Datadog.logger.debug { "#{@debug_tag} execution error: #{e.class}: #{e.message} backtrace: #{e.backtrace&.first(3)}" }
83
83
  AppSec.telemetry.report(e, description: 'libddwaf-rb internal low-level error')
84
84
 
85
85
  WAF::Result.new(
@@ -7,16 +7,28 @@ module Datadog
7
7
  def self.keep!(trace)
8
8
  return unless trace
9
9
 
10
+ previous_dm = trace.get_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER)
11
+
10
12
  # NOTE: This action will not set correct decision maker value, so the
11
13
  # trace keeping must be done with additional steps below
12
14
  trace.keep!
13
15
 
14
- # Propagate to downstream services the information that
15
- # the current distributed trace is containing at least one ASM event.
16
- trace.set_tag(
17
- Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
18
- Tracing::Sampling::Ext::Decision::ASM
19
- )
16
+ # NOTE: Preserve decision maker if already set by another product.
17
+ # As `trace.keep!` resets `_dd.p.dm` to `MANUAL`, we restore the
18
+ # previous value when another product has already claimed the
19
+ # decision maker.
20
+ if previous_dm.nil? || previous_dm == Tracing::Sampling::Ext::Decision::MANUAL
21
+ trace.set_tag(
22
+ Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
23
+ Tracing::Sampling::Ext::Decision::ASM
24
+ )
25
+ else
26
+ trace.set_tag(
27
+ Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
28
+ previous_dm,
29
+ )
30
+ end
31
+
20
32
  trace.set_distributed_source(Ext::PRODUCT_BIT)
21
33
  end
22
34
  end
@@ -68,8 +68,7 @@ module Datadog
68
68
  name.downcase! # steep:ignore NoMethod
69
69
  value.downcase!
70
70
 
71
- # See https://github.com/soutaro/steep/issues/2051
72
- parameters[name] = value # steep:ignore ArgumentTypeMismatch
71
+ parameters[name] = value
73
72
  end
74
73
  end
75
74
 
@@ -30,9 +30,9 @@ module Datadog
30
30
  #
31
31
  # @type var key: ::String
32
32
  # @type var value: ::String
33
- key, value = pair.split('=', 2).map! do |value| #: ::String
34
- CGI.unescape(value)
35
- end
33
+ key, value = pair.split('=', 2).map! do |val|
34
+ CGI.unescape(val)
35
+ end #: [::String, ::String]
36
36
 
37
37
  if (stored = memo[key])
38
38
  if stored.is_a?(Array)
@@ -11,25 +11,21 @@ module Datadog
11
11
  module AppSec
12
12
  class << self
13
13
  def enabled?
14
- Datadog.configuration.appsec.enabled
14
+ !!components.appsec
15
15
  end
16
16
 
17
17
  def rasp_enabled?
18
- Datadog.configuration.appsec.rasp_enabled
18
+ # TODO this should take rasp_enabled flag from the settings in
19
+ # the appsec component rather than reading global configuration.
20
+ enabled? && Datadog.configuration.appsec.rasp_enabled
19
21
  end
20
22
 
21
23
  def active_context
22
24
  Datadog::AppSec::Context.active
23
25
  end
24
26
 
25
- # NOTE: This is a temporary workaround for type checking.
26
- #
27
- # We want to move from possible nil-component to the disabled-component
28
- # on an initialization error. Technically, telemetry will be never
29
- # used if AppSec was not able to initialize, so it's safe to assume
30
- # that telemetry will never be used and will be nil at the same time.
31
27
  def telemetry
32
- components.appsec&.telemetry || components.telemetry
28
+ components.telemetry
33
29
  end
34
30
 
35
31
  def security_engine
@@ -24,9 +24,21 @@ module Datadog
24
24
  # e.g. `settings :foo { option :bar }` --> `config.foo.bar`
25
25
  # @param [Symbol] name option name. Methods will be created based on this name.
26
26
  def settings(name, &block)
27
- settings_class = new_settings_class(name, &block)
28
-
29
- option(name) do |o|
27
+ nested_settings_path = settings_path ? "#{settings_path}.#{name}" : name.to_s
28
+ settings_class = new_settings_class(name, nested_settings_path, &block)
29
+ # Record the child settings class on the owning class so
30
+ # Options::ClassMethods#settings_path= can later propagate any path
31
+ # changes down to nested settings classes.
32
+ #
33
+ # Example:
34
+ # settings :cache_key { option :enabled }
35
+ # creates a child class whose initial settings_path is "cache_key".
36
+ # If a contrib integration later assigns the parent path to
37
+ # "tracing.active_support", settings_children lets us update the
38
+ # nested class to "tracing.active_support.cache_key" as well.
39
+ settings_children[name] = settings_class
40
+
41
+ option(name, is_settings: true) do |o|
30
42
  o.default { settings_class.new }
31
43
 
32
44
  o.resetter do |value|
@@ -40,9 +52,9 @@ module Datadog
40
52
 
41
53
  private
42
54
 
43
- def new_settings_class(name, &block)
55
+ def new_settings_class(name, settings_path, &block)
44
56
  Class.new { include Configuration::Base }.tap do |klass|
45
- klass.instance_variable_set(:@settings_name, name)
57
+ klass.instance_variable_set(:@settings_path, settings_path)
46
58
  klass.instance_eval(&block) if block
47
59
  end
48
60
  end