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,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "uri"
4
+ require_relative "configuration/ext"
5
+
3
6
  module Datadog
4
7
  module AIGuard
5
8
  # Configuration module for AI Guard
6
9
  module Configuration
10
+ # AI Guard specific settings
11
+ module Settings
12
+ def self.extended(base)
13
+ base = base.singleton_class unless base.is_a?(Class)
14
+ add_settings!(base)
15
+ end
16
+
17
+ def self.add_settings!(base)
18
+ base.class_eval do
19
+ # AI Guard specific configurations.
20
+ # @public_api
21
+ #
22
+ # Steep does not update `self` for this `class_eval` block.
23
+ # @type self: Datadog::Core::Configuration::Base::_DslContext
24
+ settings :ai_guard do
25
+ # Enable AI Guard.
26
+ #
27
+ # You can use this option to skip calls to AI Guard API without having to remove library as a whole.
28
+ #
29
+ # @default `DD_AI_GUARD_ENABLED`, otherwise `false`
30
+ # @return [Boolean]
31
+ option :enabled do |o|
32
+ o.type :bool
33
+ o.env Ext::ENV_AI_GUARD_ENABLED
34
+ o.default false
35
+ end
36
+
37
+ define_method(:instrument) do |integration_name|
38
+ return unless enabled # steep:ignore
39
+
40
+ if (registered_integration = Datadog::AIGuard::Contrib::Integration.registry[integration_name])
41
+ klass = registered_integration.klass
42
+ if klass.loaded? && klass.compatible?
43
+ instance = klass.new
44
+ instance.patcher.patch unless instance.patcher.patched?
45
+ end
46
+ end
47
+ end
48
+
49
+ # AI Guard API endpoint path.
50
+ #
51
+ # @default `DD_AI_GUARD_ENDPOINT`, otherwise `nil`
52
+ # @return [String, nil]
53
+ option :endpoint do |o|
54
+ o.type :string, nilable: true
55
+ o.env Ext::ENV_AI_GUARD_ENDPOINT
56
+
57
+ o.setter do |value|
58
+ next unless value
59
+
60
+ uri = URI(value.to_s)
61
+ raise ArgumentError, "Please provide an absolute URI that includes a protocol" unless uri.absolute?
62
+
63
+ uri.to_s.delete_suffix("/")
64
+ end
65
+ end
66
+
67
+ # Datadog Application key.
68
+ #
69
+ # @default `DD_APP_KEY` environment variable, otherwise `nil`
70
+ # @return [String, nil]
71
+ option :app_key do |o|
72
+ o.type :string, nilable: true
73
+ o.env Ext::ENV_APP_KEY
74
+ end
75
+
76
+ # Request timeout in milliseconds.
77
+ #
78
+ # @default `DD_AI_GUARD_TIMEOUT`, otherwise 10 000 ms
79
+ # @return [Integer]
80
+ option :timeout_ms do |o|
81
+ o.type :int
82
+ o.env Ext::ENV_AI_GUARD_TIMEOUT
83
+ o.default 10_000
84
+ end
85
+
86
+ # Maximum content size in bytes.
87
+ # Content that exceeds the maximum allowed size is truncated before
88
+ # being stored in the current span context.
89
+ #
90
+ # @default `DD_AI_GUARD_MAX_CONTENT_SIZE`, otherwise 524 228 bytes
91
+ # @return [Integer]
92
+ option :max_content_size_bytes do |o|
93
+ o.type :int
94
+ o.env Ext::ENV_AI_GUARD_MAX_CONTENT_SIZE
95
+ o.default 512 * 1024
96
+ end
97
+
98
+ # Maximum number of messages.
99
+ # Older messages are omitted once the message limit is reached.
100
+ #
101
+ # @default `DD_AI_GUARD_MAX_MESSAGES_LENGTH`, otherwise 16 messages
102
+ # @return [Integer]
103
+ option :max_messages_length do |o|
104
+ o.type :int
105
+ o.env Ext::ENV_AI_GUARD_MAX_MESSAGES_LENGTH
106
+ o.default 16
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
7
112
  end
8
113
  end
9
114
  end
10
-
11
- require_relative "configuration/settings"
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AIGuard
5
+ module Contrib
6
+ # Auto-instrumentation for AI Guard integrations
7
+ module AutoInstrument
8
+ def self.patch_all
9
+ integrations = []
10
+
11
+ Datadog::AIGuard::Contrib::Integration.registry.each_value do |integration|
12
+ next unless integration.klass.auto_instrument?
13
+
14
+ integrations << integration.name
15
+ end
16
+
17
+ integrations.each do |integration_name|
18
+ Datadog.configuration.ai_guard.instrument(integration_name)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "patcher"
5
+ require_relative "request_middleware"
6
+
7
+ module Datadog
8
+ module AIGuard
9
+ module Contrib
10
+ module Rack
11
+ # Rack integration for AI Guard
12
+ class Integration
13
+ include Datadog::AIGuard::Contrib::Integration
14
+
15
+ MINIMUM_VERSION = Gem::Version.new("1.1.0")
16
+
17
+ register_as :rack, auto_patch: false
18
+
19
+ def self.version
20
+ Gem.loaded_specs["rack"]&.version
21
+ end
22
+
23
+ def self.loaded?
24
+ !defined?(::Rack).nil?
25
+ end
26
+
27
+ def self.compatible?
28
+ super && !!(version&.>= MINIMUM_VERSION)
29
+ end
30
+
31
+ def self.auto_instrument?
32
+ false
33
+ end
34
+
35
+ def patcher
36
+ Patcher
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AIGuard
5
+ module Contrib
6
+ module Rack
7
+ # Patcher for Rack integration
8
+ module Patcher
9
+ module_function
10
+
11
+ def patched?
12
+ !!Patcher.instance_variable_get(:@patched)
13
+ end
14
+
15
+ def target_version
16
+ Integration.version
17
+ end
18
+
19
+ def patch
20
+ Patcher.instance_variable_set(:@patched, true)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../tracing/client_ip"
4
+ require_relative "../../../tracing/contrib/rack/header_collection"
5
+ require_relative "../../../tracing/metadata/ext"
6
+ require_relative "../../ext"
7
+
8
+ module Datadog
9
+ module AIGuard
10
+ module Contrib
11
+ module Rack
12
+ # AI Guard Rack middleware.
13
+ #
14
+ # Inserted into the middleware stack right after
15
+ # Datadog::Tracing::Contrib::Rack::TraceMiddleware (i.e. nested inside
16
+ # it). This ordering matters: on the way out of the request, AI Guard's
17
+ # `ensure` block unwinds *before* Tracing's ensure, while Tracing's
18
+ # request span is still live. We need that, because Tracing's ensure
19
+ # calls `request_span.finish`, which builds a frozen `Span` snapshot of
20
+ # the meta hash — any `set_tag` call after that point mutates the
21
+ # `SpanOperation` but never reaches the exported `Span`.
22
+ #
23
+ # So while the span is still active, we tag `http.client_ip` and
24
+ # `network.client.ip` on it — but only when an AI Guard span was
25
+ # actually recorded during the request.
26
+ class RequestMiddleware
27
+ NETWORK_CLIENT_IP_TAG = "network.client.ip"
28
+
29
+ def initialize(app, opt = {})
30
+ @app = app
31
+ end
32
+
33
+ def call(env)
34
+ @app.call(env)
35
+ ensure
36
+ tag_client_ip(env) if consume_ai_guard_executed_flag
37
+ end
38
+
39
+ private
40
+
41
+ # AI Guard's evaluation flow sets `ai_guard.executed` on the trace
42
+ # whenever an AI Guard span is created during the request. We read
43
+ # it here to know whether to tag client IP, then clear it so the
44
+ # internal flag does not propagate to the exported trace.
45
+ #
46
+ # `Tracing.active_trace` is publicly typed as `TraceSegment?` but at
47
+ # runtime returns a `TraceOperation`, which exposes `get_tag` and
48
+ # `clear_tag`. Pre-existing sig mismatch — hence the steep:ignore.
49
+ # steep:ignore:start
50
+ def consume_ai_guard_executed_flag
51
+ trace = Datadog::Tracing.active_trace
52
+ return false unless trace
53
+ return false unless trace.get_tag(Datadog::AIGuard::Ext::SERVICE_ENTRY_EXECUTED_TAG) == "1"
54
+
55
+ trace.clear_tag(Datadog::AIGuard::Ext::SERVICE_ENTRY_EXECUTED_TAG)
56
+ true
57
+ end
58
+ # steep:ignore:end
59
+
60
+ def tag_client_ip(env)
61
+ span = Datadog::Tracing.active_span
62
+ return unless span
63
+
64
+ if span.get_tag(Datadog::Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP).nil?
65
+ headers = Datadog::Tracing::Contrib::Rack::Header::RequestHeaderCollection.new(env)
66
+ Datadog::Tracing::ClientIp.set_client_ip_tag!(
67
+ span,
68
+ headers: headers,
69
+ remote_ip: env["REMOTE_ADDR"]
70
+ )
71
+ end
72
+
73
+ if env["REMOTE_ADDR"] && span.get_tag(NETWORK_CLIENT_IP_TAG).nil?
74
+ span.set_tag(NETWORK_CLIENT_IP_TAG, env["REMOTE_ADDR"])
75
+ end
76
+ rescue => e
77
+ Datadog::AIGuard.telemetry&.report(e, description: "AI Guard: failed to tag client IP on root span")
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "patcher"
5
+
6
+ module Datadog
7
+ module AIGuard
8
+ module Contrib
9
+ module Rails
10
+ # Rails integration for AI Guard
11
+ class Integration
12
+ include Datadog::AIGuard::Contrib::Integration
13
+
14
+ MINIMUM_VERSION = Gem::Version.new("4")
15
+
16
+ register_as :rails, auto_patch: false
17
+
18
+ def self.version
19
+ Gem.loaded_specs["railties"]&.version
20
+ end
21
+
22
+ def self.loaded?
23
+ !defined?(::Rails).nil?
24
+ end
25
+
26
+ def self.compatible?
27
+ super && !!(version&.>= MINIMUM_VERSION)
28
+ end
29
+
30
+ def self.auto_instrument?
31
+ true
32
+ end
33
+
34
+ def patcher
35
+ Patcher
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../core/utils/only_once"
4
+ require_relative "../rack/request_middleware"
5
+ require_relative "../../../tracing/contrib"
6
+ require_relative "../../../tracing/contrib/rack/middlewares"
7
+
8
+ module Datadog
9
+ module AIGuard
10
+ module Contrib
11
+ module Rails
12
+ # Patcher for AI Guard on Rails. Inserts the AI Guard Rack middleware
13
+ # right after the Tracing Rack middleware so the request span is
14
+ # already active when AI Guard tags the client IP.
15
+ module Patcher
16
+ BEFORE_INITIALIZE_ONLY_ONCE_PER_APP = Hash.new { |h, key| h[key] = Datadog::Core::Utils::OnlyOnce.new }
17
+
18
+ module_function
19
+
20
+ def patched?
21
+ !!Patcher.instance_variable_get(:@patched)
22
+ end
23
+
24
+ def target_version
25
+ Integration.version
26
+ end
27
+
28
+ def patch
29
+ patch_before_initialize
30
+ Patcher.instance_variable_set(:@patched, true)
31
+ end
32
+
33
+ def patch_before_initialize
34
+ ::ActiveSupport.on_load(:before_initialize) do
35
+ Datadog::AIGuard::Contrib::Rails::Patcher.before_initialize(self)
36
+ end
37
+ end
38
+
39
+ def before_initialize(app)
40
+ BEFORE_INITIALIZE_ONLY_ONCE_PER_APP[app].run do
41
+ # Middleware must be added before the application is initialized.
42
+ # Otherwise the middleware stack will be frozen.
43
+ add_middleware(app) if Datadog.configuration.tracing[:rails][:middleware]
44
+ end
45
+ end
46
+
47
+ def add_middleware(app)
48
+ if include_middleware?(Datadog::Tracing::Contrib::Rack::TraceMiddleware, app)
49
+ app.middleware.insert_after(
50
+ Datadog::Tracing::Contrib::Rack::TraceMiddleware,
51
+ Datadog::AIGuard::Contrib::Rack::RequestMiddleware
52
+ )
53
+ else
54
+ app.middleware.insert_before(0, Datadog::AIGuard::Contrib::Rack::RequestMiddleware)
55
+ end
56
+ end
57
+
58
+ def include_middleware?(middleware, app)
59
+ found = false
60
+
61
+ # find tracer middleware reference in Rails::Configuration::MiddlewareStackProxy
62
+ app.middleware.instance_variable_get(:@operations).each do |operation|
63
+ args = case operation
64
+ when Array
65
+ # rails 5.2
66
+ _op, args = operation
67
+ args
68
+ when Proc
69
+ if operation.binding.local_variables.include?(:args)
70
+ # rails 6.0, 6.1
71
+ operation.binding.local_variable_get(:args)
72
+ else
73
+ # rails 7.0 uses ... to pass args
74
+ # steep:ignore:start
75
+ args_getter = Class.new do
76
+ def method_missing(_op, *args) # standard:disable Style/MissingRespondToMissing
77
+ args
78
+ end
79
+ end.new
80
+ # steep:ignore:end
81
+ operation.call(args_getter)
82
+ end
83
+ else
84
+ # unknown, pass through
85
+ []
86
+ end
87
+
88
+ found = true if args.include?(middleware)
89
+ end
90
+
91
+ found
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -15,6 +15,8 @@ module Datadog
15
15
  Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
16
16
  Tracing::Sampling::Ext::Decision::AI_GUARD
17
17
  )
18
+ trace.set_tag(Ext::EVENT_TAG, true)
19
+ trace.set_tag(Ext::SERVICE_ENTRY_EXECUTED_TAG, "1")
18
20
 
19
21
  if (last_message = messages.last)
20
22
  if last_message.tool_call
@@ -10,6 +10,8 @@ module Datadog
10
10
  ACTION_TAG = "ai_guard.action"
11
11
  REASON_TAG = "ai_guard.reason"
12
12
  BLOCKED_TAG = "ai_guard.blocked"
13
+ EVENT_TAG = "ai_guard.event"
14
+ SERVICE_ENTRY_EXECUTED_TAG = "_dd.ai_guard.executed"
13
15
  METASTRUCT_TAG = "ai_guard"
14
16
  end
15
17
  end
@@ -3,6 +3,8 @@
3
3
  require_relative "core/configuration"
4
4
  require_relative "ai_guard/configuration"
5
5
 
6
+ require_relative "ai_guard/contrib/rack/integration"
7
+ require_relative "ai_guard/contrib/rails/integration"
6
8
  require_relative "ai_guard/contrib/ruby_llm/integration"
7
9
 
8
10
  module Datadog
@@ -50,6 +52,10 @@ module Datadog
50
52
  Datadog.send(:components).ai_guard&.logger
51
53
  end
52
54
 
55
+ def telemetry
56
+ Datadog.send(:components).ai_guard&.telemetry
57
+ end
58
+
53
59
  # Evaluates one or more messages using AI Guard API.
54
60
  #
55
61
  # Example:
@@ -171,3 +177,5 @@ module Datadog
171
177
  end
172
178
  end
173
179
  end
180
+
181
+ require_relative "ai_guard/autoload"
@@ -7,7 +7,7 @@ if %w[1 true].include?((Datadog::DATADOG_ENV['DD_APPSEC_ENABLED'] || '').downcas
7
7
  rescue => e
8
8
  Kernel.warn(
9
9
  '[datadog] AppSec failed to instrument. No security check will be performed. error: ' \
10
- " #{e.class}: #{e}"
10
+ " #{e.class}: #{e.message}"
11
11
  )
12
12
  end
13
13
  end
@@ -47,7 +47,7 @@ module Datadog
47
47
  security_engine = SecurityEngine::Engine.new(appsec_settings: settings.appsec, telemetry: telemetry)
48
48
  new(security_engine: security_engine)
49
49
  rescue => e
50
- Datadog.logger.warn("AppSec is disabled: #{e.class}: #{e}; there may be additional logged errors above")
50
+ Datadog.logger.warn("AppSec is disabled: #{e.class}: #{e.message}; there may be additional logged errors above")
51
51
 
52
52
  # Not reporting to telemetry here because some of the rescued exceptions
53
53
  # have already been reported by the code that raised them