datadog 2.31.0 → 2.33.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
  3. data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +73 -0
  4. data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
  5. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +16 -5
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +8 -4
  9. data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
  10. data/ext/datadog_profiling_native_extension/stack_recorder.c +3 -9
  11. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -0
  12. data/ext/libdatadog_api/crashtracker.c +2 -0
  13. data/ext/libdatadog_api/di.c +48 -0
  14. data/ext/libdatadog_api/extconf.rb +7 -4
  15. data/ext/libdatadog_extconf_helpers.rb +38 -1
  16. data/lib/datadog/ai_guard/autoload.rb +10 -0
  17. data/lib/datadog/ai_guard/component.rb +1 -1
  18. data/lib/datadog/ai_guard/configuration.rb +105 -2
  19. data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
  20. data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
  21. data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
  22. data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +83 -0
  23. data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
  24. data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
  25. data/lib/datadog/ai_guard/evaluation.rb +2 -0
  26. data/lib/datadog/ai_guard/ext.rb +2 -0
  27. data/lib/datadog/ai_guard.rb +8 -0
  28. data/lib/datadog/appsec/autoload.rb +1 -1
  29. data/lib/datadog/appsec/component.rb +1 -1
  30. data/lib/datadog/appsec/configuration.rb +414 -1
  31. data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
  32. data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
  33. data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
  34. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +111 -0
  35. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
  36. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
  38. data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
  39. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  40. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  41. data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
  42. data/lib/datadog/appsec.rb +1 -0
  43. data/lib/datadog/core/configuration/components.rb +1 -1
  44. data/lib/datadog/core/configuration/settings.rb +13 -0
  45. data/lib/datadog/core/configuration/supported_configurations.rb +4 -0
  46. data/lib/datadog/core/configuration.rb +1 -1
  47. data/lib/datadog/core/contrib/rails/utils.rb +1 -1
  48. data/lib/datadog/core/crashtracking/component.rb +3 -3
  49. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  50. data/lib/datadog/core/environment/container.rb +2 -2
  51. data/lib/datadog/core/environment/ext.rb +1 -0
  52. data/lib/datadog/core/environment/socket.rb +13 -0
  53. data/lib/datadog/core/feature_flags.rb +1 -1
  54. data/lib/datadog/core/metrics/client.rb +5 -5
  55. data/lib/datadog/core/remote/client.rb +1 -1
  56. data/lib/datadog/core/remote/component.rb +2 -2
  57. data/lib/datadog/core/runtime/metrics.rb +1 -1
  58. data/lib/datadog/core/telemetry/emitter.rb +1 -1
  59. data/lib/datadog/core/telemetry/event/app_started.rb +2 -2
  60. data/lib/datadog/core/transport/http.rb +2 -0
  61. data/lib/datadog/core/utils.rb +1 -1
  62. data/lib/datadog/core/workers/async.rb +1 -1
  63. data/lib/datadog/core.rb +1 -1
  64. data/lib/datadog/data_streams/configuration.rb +40 -1
  65. data/lib/datadog/data_streams/pathway_context.rb +1 -1
  66. data/lib/datadog/data_streams/processor.rb +1 -1
  67. data/lib/datadog/data_streams.rb +1 -1
  68. data/lib/datadog/di/base.rb +8 -5
  69. data/lib/datadog/di/code_tracker.rb +179 -1
  70. data/lib/datadog/di/component.rb +1 -1
  71. data/lib/datadog/di/configuration.rb +235 -2
  72. data/lib/datadog/di/instrumenter.rb +46 -26
  73. data/lib/datadog/di/probe_builder.rb +1 -1
  74. data/lib/datadog/di/probe_file_loader.rb +2 -2
  75. data/lib/datadog/di/probe_manager.rb +6 -6
  76. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  77. data/lib/datadog/di/probe_notifier_worker.rb +2 -2
  78. data/lib/datadog/di/remote.rb +6 -6
  79. data/lib/datadog/di/serializer.rb +1 -1
  80. data/lib/datadog/di/transport/input.rb +3 -3
  81. data/lib/datadog/error_tracking/configuration.rb +55 -2
  82. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  83. data/lib/datadog/open_feature/component.rb +18 -1
  84. data/lib/datadog/open_feature/evaluation_engine.rb +3 -3
  85. data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
  86. data/lib/datadog/open_feature/exposures/worker.rb +1 -1
  87. data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
  88. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  89. data/lib/datadog/open_feature/provider.rb +19 -1
  90. data/lib/datadog/open_feature/remote.rb +1 -1
  91. data/lib/datadog/open_feature/transport.rb +1 -1
  92. data/lib/datadog/opentelemetry/metrics.rb +13 -4
  93. data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
  94. data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
  95. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
  96. data/lib/datadog/profiling/collectors/code_provenance.rb +35 -9
  97. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
  98. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
  99. data/lib/datadog/profiling/collectors/info.rb +16 -3
  100. data/lib/datadog/profiling/component.rb +3 -6
  101. data/lib/datadog/profiling/exporter.rb +37 -12
  102. data/lib/datadog/profiling/ext.rb +0 -2
  103. data/lib/datadog/profiling/flush.rb +21 -12
  104. data/lib/datadog/profiling/http_transport.rb +12 -1
  105. data/lib/datadog/profiling/load_native_extension.rb +1 -1
  106. data/lib/datadog/profiling/profiler.rb +13 -1
  107. data/lib/datadog/profiling/scheduler.rb +2 -2
  108. data/lib/datadog/profiling/stack_recorder.rb +0 -4
  109. data/lib/datadog/profiling/tasks/exec.rb +8 -3
  110. data/lib/datadog/profiling/tasks/help.rb +1 -0
  111. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  112. data/lib/datadog/single_step_instrument.rb +1 -1
  113. data/lib/datadog/symbol_database/configuration.rb +65 -0
  114. data/lib/datadog/symbol_database/extractor.rb +906 -0
  115. data/lib/datadog/symbol_database/file_hash.rb +46 -0
  116. data/lib/datadog/symbol_database/logger.rb +43 -0
  117. data/lib/datadog/symbol_database/scope.rb +102 -0
  118. data/lib/datadog/symbol_database/scope_batcher.rb +280 -0
  119. data/lib/datadog/symbol_database/service_version.rb +57 -0
  120. data/lib/datadog/symbol_database/symbol.rb +66 -0
  121. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  122. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  123. data/lib/datadog/symbol_database/transport.rb +54 -0
  124. data/lib/datadog/symbol_database/uploader.rb +169 -0
  125. data/lib/datadog/symbol_database.rb +49 -0
  126. data/lib/datadog/tracing/buffer.rb +3 -3
  127. data/lib/datadog/tracing/configuration/settings.rb +1 -1
  128. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
  129. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  130. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  131. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  132. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  133. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  134. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  135. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  136. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  137. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  138. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  139. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  140. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
  141. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  142. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
  143. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  144. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
  145. data/lib/datadog/tracing/contrib/component.rb +1 -1
  146. data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
  147. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  148. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
  149. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
  150. data/lib/datadog/tracing/contrib/extensions.rb +9 -0
  151. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
  152. data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
  153. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
  154. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
  155. data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -2
  156. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
  157. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -2
  158. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
  159. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
  160. data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
  161. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
  162. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
  163. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
  164. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +6 -0
  165. data/lib/datadog/tracing/contrib/rack/ext.rb +27 -0
  166. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  167. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  168. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +117 -1
  169. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  170. data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
  171. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
  172. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  173. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
  174. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  175. data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
  176. data/lib/datadog/tracing/contrib.rb +8 -0
  177. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
  178. data/lib/datadog/tracing/distributed/baggage.rb +59 -5
  179. data/lib/datadog/tracing/distributed/datadog.rb +11 -11
  180. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
  181. data/lib/datadog/tracing/distributed/propagation.rb +2 -2
  182. data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
  183. data/lib/datadog/tracing/event.rb +1 -1
  184. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  185. data/lib/datadog/tracing/pipeline.rb +1 -1
  186. data/lib/datadog/tracing/remote.rb +1 -1
  187. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  188. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -2
  189. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  190. data/lib/datadog/tracing/span_operation.rb +3 -3
  191. data/lib/datadog/tracing/trace_operation.rb +4 -4
  192. data/lib/datadog/tracing/tracer.rb +6 -8
  193. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  194. data/lib/datadog/tracing/workers.rb +2 -1
  195. data/lib/datadog/version.rb +1 -1
  196. metadata +33 -12
  197. data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
  198. data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
  199. data/lib/datadog/appsec/configuration/settings.rb +0 -423
  200. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  201. data/lib/datadog/di/configuration/settings.rb +0 -243
  202. 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
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../waf_addresses'
4
+ require_relative '../../../event'
5
+ require_relative '../../../trace_keeper'
6
+ require_relative '../../../security_event'
7
+ require_relative '../../../instrumentation/gateway'
8
+
9
+ module Datadog
10
+ module AppSec
11
+ module Contrib
12
+ module AwsLambda
13
+ module Gateway
14
+ module Watcher
15
+ class << self
16
+ def watch
17
+ gateway = Instrumentation.gateway
18
+
19
+ watch_request(gateway)
20
+ watch_response(gateway)
21
+ end
22
+
23
+ def watch_request(gateway = Instrumentation.gateway)
24
+ gateway.watch('aws_lambda.request.start') do |stack, payload|
25
+ context = payload.context
26
+ next stack.call(payload) unless context
27
+
28
+ persistent_data = WAFAddresses.from_request(payload.data)
29
+ result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
30
+
31
+ if result.match? || !result.attributes.empty?
32
+ context.events.push(
33
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
34
+ )
35
+ end
36
+
37
+ if result.match?
38
+ AppSec::Event.tag(context, result)
39
+ TraceKeeper.keep!(context.trace) if result.keep?
40
+ AppSec::ActionsHandler.handle(result.actions)
41
+ end
42
+
43
+ stack.call(payload)
44
+ end
45
+ end
46
+
47
+ def watch_response(gateway = Instrumentation.gateway)
48
+ gateway.watch('aws_lambda.response.start') do |stack, payload|
49
+ context = payload.context
50
+ next stack.call(payload) unless context
51
+
52
+ persistent_data = WAFAddresses.from_response(payload.data)
53
+ result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
54
+
55
+ if result.match?
56
+ AppSec::Event.tag(context, result)
57
+ TraceKeeper.keep!(context.trace) if result.keep?
58
+
59
+ context.events.push(
60
+ AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
61
+ )
62
+
63
+ AppSec::ActionsHandler.handle(result.actions)
64
+ end
65
+
66
+ stack.call(payload)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'patcher'
4
+ require_relative '../integration'
5
+
6
+ module Datadog
7
+ module AppSec
8
+ module Contrib
9
+ module AwsLambda
10
+ class Integration
11
+ include Datadog::AppSec::Contrib::Integration
12
+
13
+ register_as :aws_lambda, auto_patch: false
14
+
15
+ # NOTE: AWS Lambda is a runtime environment, not an installable gem
16
+ def self.version
17
+ nil
18
+ end
19
+
20
+ def self.loaded?
21
+ true
22
+ end
23
+
24
+ def self.compatible?
25
+ super
26
+ end
27
+
28
+ def self.auto_instrument?
29
+ false
30
+ end
31
+
32
+ def patcher
33
+ Patcher
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../monitor'
4
+ require_relative 'gateway/watcher'
5
+
6
+ module Datadog
7
+ module AppSec
8
+ module Contrib
9
+ module AwsLambda
10
+ module Patcher
11
+ module_function
12
+
13
+ def patched?
14
+ Patcher.instance_variable_get(:@patched)
15
+ end
16
+
17
+ def target_version
18
+ Integration.version
19
+ end
20
+
21
+ def patch
22
+ Monitor::Gateway::Watcher.watch
23
+ Gateway::Watcher.watch
24
+ Patcher.instance_variable_set(:@patched, true)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ require_relative '../../utils/http/media_type'
6
+ require_relative '../../utils/http/body'
7
+ require_relative '../../../core/utils/base64'
8
+ require_relative '../../../core/header_collection'
9
+ require_relative '../../../tracing/client_ip'
10
+
11
+ module Datadog
12
+ module AppSec
13
+ module Contrib
14
+ module AwsLambda
15
+ # Extracts WAF input addresses from normalized AWS Lambda API Gateway event payloads.
16
+ # @api private
17
+ module WAFAddresses
18
+ module_function
19
+
20
+ def from_request(payload)
21
+ return {} if payload.nil? || payload.empty?
22
+
23
+ headers = parse_headers(payload)
24
+ data = {
25
+ 'server.request.cookies' => parse_cookies(payload, headers),
26
+ 'server.request.query' => payload['query'],
27
+ 'server.request.uri.raw' => build_fullpath(payload),
28
+ 'server.request.headers' => headers,
29
+ 'server.request.headers.no_cookies' => headers.dup.tap { |h| h.delete('cookie') },
30
+ 'http.client_ip' => extract_client_ip(payload['source_ip'], headers),
31
+ 'server.request.method' => payload['method'],
32
+ 'server.request.body' => parse_body(payload, headers),
33
+ 'server.request.path_params' => payload['path_params']
34
+ }
35
+
36
+ data.compact!
37
+ data
38
+ end
39
+
40
+ def from_response(payload)
41
+ return {} if payload.nil? || payload.empty?
42
+
43
+ headers = parse_headers(payload)
44
+ data = {
45
+ 'server.response.status' => payload['statusCode']&.to_s,
46
+ 'server.response.headers' => headers,
47
+ 'server.response.headers.no_cookies' => headers.dup.tap { |h| h.delete('set-cookie') }
48
+ }
49
+
50
+ data.compact!
51
+ data
52
+ end
53
+
54
+ def parse_headers(payload)
55
+ (payload['headers'] || {}).each_with_object({}) do |(key, value), hash|
56
+ hash[key.downcase] = value
57
+ end
58
+ end
59
+
60
+ def parse_cookies(payload, headers)
61
+ raw_pairs = payload['cookies'] || headers['cookie']&.split(';')
62
+ return unless raw_pairs
63
+
64
+ raw_pairs.each_with_object({}) do |pair, hash|
65
+ name, value = pair.strip.split('=', 2)
66
+ hash[name] = value if name
67
+ end
68
+ end
69
+
70
+ def build_fullpath(payload)
71
+ path = payload['path']
72
+ return unless path
73
+
74
+ query_string = build_query_string(payload)
75
+ query_string ? "#{path}?#{query_string}" : path
76
+ end
77
+
78
+ def build_query_string(payload)
79
+ query_string = payload['query_string']
80
+ return query_string if query_string && !query_string.empty?
81
+
82
+ query = payload['query']
83
+ return if query.nil? || query.empty?
84
+
85
+ URI.encode_www_form(query)
86
+ end
87
+
88
+ def extract_client_ip(remote_ip, headers)
89
+ header_collection = Datadog::Core::HeaderCollection.from_hash(headers)
90
+ Datadog::Tracing::ClientIp.extract_client_ip(header_collection, remote_ip)
91
+ end
92
+
93
+ def parse_body(payload, headers)
94
+ body = payload['body']
95
+ return unless body
96
+
97
+ body = Core::Utils::Base64.strict_decode64(body) if payload['base64_encoded']
98
+
99
+ content_type = headers['content-type']
100
+ return unless content_type
101
+
102
+ media_type = AppSec::Utils::HTTP::MediaType.parse(content_type)
103
+ return unless media_type
104
+
105
+ AppSec::Utils::HTTP::Body.parse(body, media_type: media_type)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ 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