datadog 2.12.2 → 2.13.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +14 -13
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
- data/lib/datadog/appsec/actions_handler.rb +22 -1
- data/lib/datadog/appsec/anonymizer.rb +16 -0
- data/lib/datadog/appsec/configuration/settings.rb +62 -10
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/configuration.rb +7 -31
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +79 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +0 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +36 -23
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
- data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +2 -2
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +93 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +14 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +10 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -2
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/ext.rb +4 -2
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +4 -2
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -3
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/core/configuration/components.rb +2 -1
- data/lib/datadog/core/configuration/ext.rb +4 -0
- data/lib/datadog/core/configuration/options.rb +2 -2
- data/lib/datadog/core/configuration/settings.rb +53 -30
- data/lib/datadog/core/environment/agent_info.rb +4 -3
- data/lib/datadog/core/remote/component.rb +3 -6
- data/lib/datadog/core/remote/configuration/repository.rb +2 -1
- data/lib/datadog/core/remote/negotiation.rb +9 -9
- data/lib/datadog/core/remote/transport/config.rb +4 -3
- data/lib/datadog/core/remote/transport/http/client.rb +4 -3
- data/lib/datadog/core/remote/transport/http/config.rb +6 -32
- data/lib/datadog/core/remote/transport/http/negotiation.rb +6 -32
- data/lib/datadog/core/remote/transport/http.rb +22 -57
- data/lib/datadog/core/remote/transport/negotiation.rb +4 -3
- data/lib/datadog/core/runtime/metrics.rb +8 -1
- data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
- data/lib/datadog/core/transport/http/api/instance.rb +17 -0
- data/lib/datadog/core/transport/http/api/spec.rb +17 -0
- data/lib/datadog/core/transport/http/builder.rb +5 -3
- data/lib/datadog/core/transport/http.rb +39 -2
- data/lib/datadog/di/component.rb +0 -2
- data/lib/datadog/di/probe_notifier_worker.rb +16 -16
- data/lib/datadog/di/transport/diagnostics.rb +4 -3
- data/lib/datadog/di/transport/http/api.rb +2 -12
- data/lib/datadog/di/transport/http/client.rb +4 -3
- data/lib/datadog/di/transport/http/diagnostics.rb +7 -33
- data/lib/datadog/di/transport/http/input.rb +7 -33
- data/lib/datadog/di/transport/http.rb +14 -56
- data/lib/datadog/di/transport/input.rb +4 -3
- data/lib/datadog/di/utils.rb +5 -0
- data/lib/datadog/kit/appsec/events.rb +9 -0
- data/lib/datadog/kit/identity.rb +5 -1
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
- data/lib/datadog/opentelemetry/api/context.rb +16 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/opentelemetry.rb +2 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
- data/lib/datadog/profiling.rb +5 -2
- data/lib/datadog/tracing/component.rb +15 -12
- data/lib/datadog/tracing/configuration/ext.rb +7 -1
- data/lib/datadog/tracing/configuration/settings.rb +18 -2
- data/lib/datadog/tracing/context_provider.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -11
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/correlation.rb +9 -2
- data/lib/datadog/tracing/distributed/baggage.rb +131 -0
- data/lib/datadog/tracing/distributed/datadog.rb +2 -0
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/metadata/ext.rb +5 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span_operation.rb +2 -1
- data/lib/datadog/tracing/sync_writer.rb +1 -2
- data/lib/datadog/tracing/trace_digest.rb +9 -2
- data/lib/datadog/tracing/trace_operation.rb +29 -17
- data/lib/datadog/tracing/trace_segment.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +38 -2
- data/lib/datadog/tracing/transport/http/api.rb +2 -10
- data/lib/datadog/tracing/transport/http/client.rb +5 -4
- data/lib/datadog/tracing/transport/http/traces.rb +13 -41
- data/lib/datadog/tracing/transport/http.rb +11 -44
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +21 -9
- data/lib/datadog/tracing/workers/trace_writer.rb +2 -6
- data/lib/datadog/tracing/writer.rb +2 -6
- data/lib/datadog/tracing.rb +16 -3
- data/lib/datadog/version.rb +2 -2
- metadata +17 -13
- data/lib/datadog/appsec/contrib/devise/event.rb +0 -54
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -72
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -47
- data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
- data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
- data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../ext'
|
4
|
+
require_relative '../configuration'
|
5
|
+
require_relative '../data_extractor'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module AppSec
|
9
|
+
module Contrib
|
10
|
+
module Devise
|
11
|
+
module Patches
|
12
|
+
# A patch for Devise::Authenticatable strategy with tracking functionality
|
13
|
+
module SigninTrackingPatch
|
14
|
+
def validate(resource, &block)
|
15
|
+
result = super
|
16
|
+
|
17
|
+
return result unless AppSec.enabled?
|
18
|
+
return result if @_datadog_appsec_skip_track_login_event
|
19
|
+
return result unless Configuration.auto_user_instrumentation_enabled?
|
20
|
+
return result unless AppSec.active_context
|
21
|
+
|
22
|
+
context = AppSec.active_context
|
23
|
+
if context.trace.nil? || context.span.nil?
|
24
|
+
Datadog.logger.debug { 'AppSec: unable to track signin events, due to missing trace or span' }
|
25
|
+
return result
|
26
|
+
end
|
27
|
+
|
28
|
+
context.trace.keep!
|
29
|
+
|
30
|
+
if result
|
31
|
+
record_successful_signin(context, resource)
|
32
|
+
Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_LOGIN_SUCCESS)
|
33
|
+
|
34
|
+
return result
|
35
|
+
end
|
36
|
+
|
37
|
+
record_failed_signin(context, resource)
|
38
|
+
Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_LOGIN_FAILURE)
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def record_successful_signin(context, resource)
|
46
|
+
extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
|
47
|
+
|
48
|
+
id = extractor.extract_id(resource)
|
49
|
+
login = extractor.extract_login(authentication_hash) || extractor.extract_login(resource)
|
50
|
+
|
51
|
+
if id
|
52
|
+
context.span[Ext::TAG_USR_ID] ||= id
|
53
|
+
context.span[Ext::TAG_DD_USR_ID] = id
|
54
|
+
end
|
55
|
+
|
56
|
+
context.span[Ext::TAG_LOGIN_SUCCESS_USR_LOGIN] ||= login
|
57
|
+
context.span[Ext::TAG_LOGIN_SUCCESS_TRACK] = 'true'
|
58
|
+
context.span[Ext::TAG_DD_USR_LOGIN] = login
|
59
|
+
context.span[Ext::TAG_DD_LOGIN_SUCCESS_MODE] = Configuration.auto_user_instrumentation_mode
|
60
|
+
|
61
|
+
# NOTE: We don't have a way to make one-shot receivers for events,
|
62
|
+
# and because of that we will trigger an additional event even
|
63
|
+
# if it was already done via the SDK
|
64
|
+
AppSec::Instrumentation.gateway.push(
|
65
|
+
'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, login)
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def record_failed_signin(context, resource)
|
70
|
+
extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
|
71
|
+
|
72
|
+
context.span[Ext::TAG_LOGIN_FAILURE_TRACK] = 'true'
|
73
|
+
context.span[Ext::TAG_DD_LOGIN_FAILURE_MODE] = Configuration.auto_user_instrumentation_mode
|
74
|
+
|
75
|
+
unless resource
|
76
|
+
login = extractor.extract_login(authentication_hash)
|
77
|
+
|
78
|
+
context.span[Ext::TAG_DD_USR_LOGIN] = login
|
79
|
+
context.span[Ext::TAG_LOGIN_FAILURE_USR_LOGIN] ||= login
|
80
|
+
context.span[Ext::TAG_LOGIN_FAILURE_USR_EXISTS] ||= 'false'
|
81
|
+
|
82
|
+
return
|
83
|
+
end
|
84
|
+
|
85
|
+
id = extractor.extract_id(resource)
|
86
|
+
login = extractor.extract_login(authentication_hash) || extractor.extract_login(resource)
|
87
|
+
|
88
|
+
if id
|
89
|
+
context.span[Ext::TAG_DD_USR_ID] = id
|
90
|
+
context.span[Ext::TAG_LOGIN_FAILURE_USR_ID] ||= id
|
91
|
+
end
|
92
|
+
|
93
|
+
context.span[Ext::TAG_DD_USR_LOGIN] = login
|
94
|
+
context.span[Ext::TAG_LOGIN_FAILURE_USR_LOGIN] ||= login
|
95
|
+
context.span[Ext::TAG_LOGIN_FAILURE_USR_EXISTS] ||= 'true'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../ext'
|
4
|
+
require_relative '../configuration'
|
5
|
+
require_relative '../data_extractor'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module AppSec
|
9
|
+
module Contrib
|
10
|
+
module Devise
|
11
|
+
module Patches
|
12
|
+
# A patch for Devise::RegistrationsController with tracking functionality
|
13
|
+
module SignupTrackingPatch
|
14
|
+
def create
|
15
|
+
return super unless AppSec.enabled?
|
16
|
+
return super unless Configuration.auto_user_instrumentation_enabled?
|
17
|
+
return super unless AppSec.active_context
|
18
|
+
|
19
|
+
super do |resource|
|
20
|
+
context = AppSec.active_context
|
21
|
+
|
22
|
+
if context.trace.nil? || context.span.nil?
|
23
|
+
Datadog.logger.debug { 'AppSec: unable to track signup events, due to missing trace or span' }
|
24
|
+
next yield(resource) if block_given?
|
25
|
+
end
|
26
|
+
|
27
|
+
next yield(resource) if resource.new_record? && block_given?
|
28
|
+
|
29
|
+
context.trace.keep!
|
30
|
+
record_successful_signup(context, resource)
|
31
|
+
Instrumentation.gateway.push('appsec.events.user_lifecycle', Ext::EVENT_SIGNUP)
|
32
|
+
|
33
|
+
yield(resource) if block_given?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def record_successful_signup(context, resource)
|
40
|
+
extractor = DataExtractor.new(mode: Configuration.auto_user_instrumentation_mode)
|
41
|
+
|
42
|
+
id = extractor.extract_id(resource)
|
43
|
+
login = extractor.extract_login(resource_params) || extractor.extract_login(resource)
|
44
|
+
|
45
|
+
context.span[Ext::TAG_SIGNUP_TRACK] = 'true'
|
46
|
+
context.span[Ext::TAG_DD_USR_LOGIN] = login
|
47
|
+
context.span[Ext::TAG_SIGNUP_USR_LOGIN] ||= login
|
48
|
+
context.span[Ext::TAG_DD_SIGNUP_MODE] = Configuration.auto_user_instrumentation_mode
|
49
|
+
|
50
|
+
if id
|
51
|
+
context.span[Ext::TAG_DD_USR_ID] = id
|
52
|
+
|
53
|
+
id_tag = resource.active_for_authentication? ? Ext::TAG_USR_ID : Ext::TAG_SIGNUP_USR_ID
|
54
|
+
context.span[id_tag] ||= id
|
55
|
+
end
|
56
|
+
|
57
|
+
# NOTE: We don't have a way to make one-shot receivers for events,
|
58
|
+
# and because of that we will trigger an additional event even
|
59
|
+
# if it was already done via the SDK
|
60
|
+
AppSec::Instrumentation.gateway.push(
|
61
|
+
'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, login)
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -4,10 +4,10 @@ module Datadog
|
|
4
4
|
module AppSec
|
5
5
|
module Contrib
|
6
6
|
module Devise
|
7
|
-
module
|
7
|
+
module Patches
|
8
8
|
# To avoid tracking new sessions that are created by
|
9
9
|
# Rememberable strategy as Login Success events.
|
10
|
-
module
|
10
|
+
module SkipSigninTrackingPatch
|
11
11
|
def validate(*args)
|
12
12
|
@_datadog_appsec_skip_track_login_event = true
|
13
13
|
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'ext'
|
4
|
+
require_relative '../../anonymizer'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module AppSec
|
8
|
+
module Contrib
|
9
|
+
module Devise
|
10
|
+
# A Rack middleware capable of tracking currently signed user
|
11
|
+
class TrackingMiddleware
|
12
|
+
WARDEN_KEY = 'warden'
|
13
|
+
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
@devise_session_scope_keys = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
return @app.call(env) unless AppSec.enabled?
|
21
|
+
return @app.call(env) unless Configuration.auto_user_instrumentation_enabled?
|
22
|
+
return @app.call(env) unless AppSec.active_context
|
23
|
+
|
24
|
+
unless env.key?(WARDEN_KEY)
|
25
|
+
Datadog.logger.debug { 'AppSec: unable to track requests, due to missing warden manager' }
|
26
|
+
return @app.call(env)
|
27
|
+
end
|
28
|
+
|
29
|
+
context = AppSec.active_context
|
30
|
+
if context.trace.nil? || context.span.nil?
|
31
|
+
Datadog.logger.debug { 'AppSec: unable to track requests, due to missing trace or span' }
|
32
|
+
return @app.call(env)
|
33
|
+
end
|
34
|
+
|
35
|
+
id = transform(extract_id(env[WARDEN_KEY]))
|
36
|
+
if id
|
37
|
+
unless context.span.has_tag?(Ext::TAG_USR_ID)
|
38
|
+
context.span[Ext::TAG_USR_ID] = id
|
39
|
+
AppSec::Instrumentation.gateway.push(
|
40
|
+
'identity.set_user', AppSec::Instrumentation::Gateway::User.new(id, nil)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
context.span[Ext::TAG_DD_USR_ID] = id.to_s
|
45
|
+
context.span[Ext::TAG_DD_COLLECTION_MODE] ||= Configuration.auto_user_instrumentation_mode
|
46
|
+
end
|
47
|
+
|
48
|
+
@app.call(env)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def extract_id(warden)
|
54
|
+
session_serializer = warden.session_serializer
|
55
|
+
|
56
|
+
key = session_key_for(session_serializer, ::Devise.default_scope)
|
57
|
+
id = session_serializer.session[key]&.dig(0, 0)
|
58
|
+
|
59
|
+
return id if ::Devise.mappings.size == 1
|
60
|
+
return "#{::Devise.default_scope}:#{id}" if id
|
61
|
+
|
62
|
+
::Devise.mappings.each_key do |scope|
|
63
|
+
next if scope == ::Devise.default_scope
|
64
|
+
|
65
|
+
key = session_key_for(session_serializer, scope)
|
66
|
+
id = session_serializer.session[key]&.dig(0, 0)
|
67
|
+
|
68
|
+
return "#{scope}:#{id}" if id
|
69
|
+
end
|
70
|
+
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def session_key_for(session_serializer, scope)
|
75
|
+
@devise_session_scope_keys[scope] ||= session_serializer.key_for(scope)
|
76
|
+
end
|
77
|
+
|
78
|
+
def transform(value)
|
79
|
+
return if value.nil?
|
80
|
+
return value.to_s unless anonymize?
|
81
|
+
|
82
|
+
Anonymizer.anonimyze(value.to_s)
|
83
|
+
end
|
84
|
+
|
85
|
+
def anonymize?
|
86
|
+
Configuration.auto_user_instrumentation_mode ==
|
87
|
+
AppSec::Configuration::Settings::ANONYMIZATION_AUTO_USER_INSTRUMENTATION_MODE
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -6,6 +6,20 @@ module Datadog
|
|
6
6
|
module Rack
|
7
7
|
# Rack integration constants
|
8
8
|
module Ext
|
9
|
+
COLLECTABLE_REQUEST_HEADERS = [
|
10
|
+
'accept',
|
11
|
+
'akamai-user-risk',
|
12
|
+
'cf-ray',
|
13
|
+
'cloudfront-viewer-ja3-fingerprint',
|
14
|
+
'content-type',
|
15
|
+
'user-agent',
|
16
|
+
'x-amzn-trace-Id',
|
17
|
+
'x-appgw-trace-id',
|
18
|
+
'x-cloud-trace-context',
|
19
|
+
'x-sigsci-requestid',
|
20
|
+
'x-sigsci-tags'
|
21
|
+
].freeze
|
22
|
+
|
9
23
|
IDENTITY_COLLECTABLE_REQUEST_HEADERS = [
|
10
24
|
'accept-encoding',
|
11
25
|
'accept-language',
|
@@ -18,6 +18,7 @@ module Datadog
|
|
18
18
|
watch_request(gateway)
|
19
19
|
watch_response(gateway)
|
20
20
|
watch_request_body(gateway)
|
21
|
+
watch_request_finish(gateway)
|
21
22
|
end
|
22
23
|
|
23
24
|
def watch_request(gateway = Instrumentation.gateway)
|
@@ -119,12 +120,18 @@ module Datadog
|
|
119
120
|
def watch_request_finish(gateway = Instrumentation.gateway)
|
120
121
|
gateway.watch('rack.request.finish', :appsec) do |stack, gateway_request|
|
121
122
|
context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
|
122
|
-
|
123
|
+
|
124
|
+
if context.span.nil? || !gateway.pushed?('appsec.events.user_lifecycle')
|
125
|
+
next stack.call(gateway_request.request)
|
126
|
+
end
|
123
127
|
|
124
128
|
gateway_request.headers.each do |name, value|
|
125
|
-
|
129
|
+
if !Ext::COLLECTABLE_REQUEST_HEADERS.include?(name) &&
|
130
|
+
!Ext::IDENTITY_COLLECTABLE_REQUEST_HEADERS.include?(name)
|
131
|
+
next
|
132
|
+
end
|
126
133
|
|
127
|
-
context.span["http.request.headers.#{name}"]
|
134
|
+
context.span["http.request.headers.#{name}"] ||= value
|
128
135
|
end
|
129
136
|
|
130
137
|
stack.call(gateway_request.request)
|
@@ -150,8 +150,6 @@ module Datadog
|
|
150
150
|
return unless trace && span
|
151
151
|
|
152
152
|
span.set_metric(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1)
|
153
|
-
# We add this tag when ASM standalone is enabled to make sure we don't bill APM
|
154
|
-
span.set_metric(Datadog::AppSec::Ext::TAG_APM_ENABLED, 0) if Datadog.configuration.appsec.standalone.enabled
|
155
153
|
span.set_tag('_dd.runtime_family', 'ruby')
|
156
154
|
span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
157
155
|
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -187,7 +187,7 @@ module Datadog
|
|
187
187
|
Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
|
188
188
|
Datadog::Tracing::Sampling::Ext::Decision::ASM
|
189
189
|
)
|
190
|
-
trace.
|
190
|
+
trace.set_distributed_source(Datadog::AppSec::Ext::PRODUCT_BIT)
|
191
191
|
end
|
192
192
|
end
|
193
193
|
end
|
data/lib/datadog/appsec/ext.rb
CHANGED
@@ -7,13 +7,15 @@ module Datadog
|
|
7
7
|
RASP_LFI = 'lfi'
|
8
8
|
RASP_SSRF = 'ssrf'
|
9
9
|
|
10
|
+
PRODUCT_BIT = 0b00000010
|
11
|
+
|
10
12
|
INTERRUPT = :datadog_appsec_interrupt
|
11
13
|
CONTEXT_KEY = 'datadog.appsec.context'
|
12
14
|
ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
|
15
|
+
EXPLOIT_PREVENTION_EVENT_CATEGORY = 'exploit'
|
13
16
|
|
14
17
|
TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
|
15
|
-
|
16
|
-
TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec'
|
18
|
+
TAG_METASTRUCT_STACK_TRACE = '_dd.stack'
|
17
19
|
|
18
20
|
TELEMETRY_METRICS_NAMESPACE = 'appsec'
|
19
21
|
end
|
@@ -19,9 +19,14 @@ module Datadog
|
|
19
19
|
gateway.watch('identity.set_user', :appsec) do |stack, user|
|
20
20
|
context = Datadog::AppSec.active_context
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
if user.id.nil? && user.login.nil?
|
23
|
+
Datadog.logger.debug { 'AppSec: skipping WAF check because no user information was provided' }
|
24
|
+
next stack.call(user)
|
25
|
+
end
|
26
|
+
|
27
|
+
persistent_data = {}
|
28
|
+
persistent_data['usr.id'] = user.id if user.id
|
29
|
+
persistent_data['usr.login'] = user.login if user.login
|
25
30
|
|
26
31
|
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
27
32
|
|
@@ -24,13 +24,13 @@ module Datadog
|
|
24
24
|
persistent_data.reject! do |_, v|
|
25
25
|
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
26
26
|
|
27
|
-
v.nil?
|
27
|
+
v.nil? || v.empty?
|
28
28
|
end
|
29
29
|
|
30
30
|
ephemeral_data.reject! do |_, v|
|
31
31
|
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
32
32
|
|
33
|
-
v.nil?
|
33
|
+
v.nil? || v.empty?
|
34
34
|
end
|
35
35
|
|
36
36
|
_code, result = try_run(persistent_data, ephemeral_data, timeout)
|
data/lib/datadog/appsec/utils.rb
CHANGED
@@ -45,6 +45,7 @@ module Datadog
|
|
45
45
|
options = { enabled: settings.runtime_metrics.enabled }
|
46
46
|
options[:statsd] = settings.runtime_metrics.statsd unless settings.runtime_metrics.statsd.nil?
|
47
47
|
options[:services] = [settings.service] unless settings.service.nil?
|
48
|
+
options[:experimental_runtime_id_enabled] = settings.runtime_metrics.experimental_runtime_id_enabled
|
48
49
|
|
49
50
|
Core::Runtime::Metrics.new(logger: logger, **options)
|
50
51
|
end
|
@@ -101,7 +102,7 @@ module Datadog
|
|
101
102
|
agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
|
102
103
|
|
103
104
|
# Exposes agent capability information for detection by any components
|
104
|
-
@agent_info = Core::Environment::AgentInfo.new(agent_settings)
|
105
|
+
@agent_info = Core::Environment::AgentInfo.new(agent_settings, logger: @logger)
|
105
106
|
|
106
107
|
@telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
|
107
108
|
|
@@ -18,6 +18,10 @@ module Datadog
|
|
18
18
|
ENV_DEFAULT_PORT = 'DD_METRIC_AGENT_PORT'
|
19
19
|
end
|
20
20
|
|
21
|
+
module APM
|
22
|
+
ENV_TRACING_ENABLED = 'DD_APM_TRACING_ENABLED'
|
23
|
+
end
|
24
|
+
|
21
25
|
module Agent
|
22
26
|
ENV_DEFAULT_HOST = 'DD_AGENT_HOST'
|
23
27
|
# Some env vars have "trace" in them, but they apply to all products
|
@@ -45,7 +45,7 @@ module Datadog
|
|
45
45
|
option_name.to_sym => proc do
|
46
46
|
get_option(option_name)
|
47
47
|
end,
|
48
|
-
"#{option_name}="
|
48
|
+
:"#{option_name}=" => proc do |value|
|
49
49
|
set_option(option_name, value)
|
50
50
|
end
|
51
51
|
}
|
@@ -117,7 +117,7 @@ module Datadog
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def resolved_env(name)
|
120
|
-
|
120
|
+
options[name].resolved_env if options.key?(name)
|
121
121
|
end
|
122
122
|
|
123
123
|
def assert_valid_option!(name)
|
@@ -570,6 +570,12 @@ module Datadog
|
|
570
570
|
o.type :bool
|
571
571
|
end
|
572
572
|
|
573
|
+
option :experimental_runtime_id_enabled do |o|
|
574
|
+
o.type :bool
|
575
|
+
o.env 'DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED'
|
576
|
+
o.default false
|
577
|
+
end
|
578
|
+
|
573
579
|
option :opts, default: {}, type: :hash
|
574
580
|
option :statsd
|
575
581
|
end
|
@@ -619,38 +625,31 @@ module Datadog
|
|
619
625
|
o.type :hash, nilable: true
|
620
626
|
o.env [Core::Environment::Ext::ENV_TAGS, Core::Environment::Ext::ENV_OTEL_RESOURCE_ATTRIBUTES]
|
621
627
|
o.env_parser do |env_value|
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
when 'deployment.environment'
|
645
|
-
tags['env'] = value
|
646
|
-
when 'service.version'
|
647
|
-
tags['version'] = value
|
648
|
-
when 'service.name'
|
649
|
-
tags['service'] = value
|
650
|
-
else
|
651
|
-
tags[key] = value
|
628
|
+
# Parses a string containing key-value pairs and returns a hash.
|
629
|
+
# Key-value pairs are delimited by ':' OR `=`, and pairs are separated by whitespace, comma, OR BOTH.
|
630
|
+
result = {}
|
631
|
+
unless env_value.nil? || env_value.empty?
|
632
|
+
# falling back to comma as separator
|
633
|
+
sep = env_value.include?(',') ? ',' : ' '
|
634
|
+
# split by separator
|
635
|
+
env_value.split(sep).each do |tag|
|
636
|
+
tag.strip!
|
637
|
+
next if tag.empty?
|
638
|
+
|
639
|
+
# tag by : or = (for OpenTelemetry)
|
640
|
+
key, val = tag.split(/[:=]/, 2).map(&:strip)
|
641
|
+
val ||= ''
|
642
|
+
# maps OpenTelemetry semantic attributes to Datadog tags
|
643
|
+
key = case key.downcase
|
644
|
+
when 'deployment.environment' then 'env'
|
645
|
+
when 'service.version' then 'version'
|
646
|
+
when 'service.name' then 'service'
|
647
|
+
else key
|
648
|
+
end
|
649
|
+
result[key] = val unless key.empty?
|
652
650
|
end
|
653
651
|
end
|
652
|
+
result
|
654
653
|
end
|
655
654
|
o.setter do |new_value, old_value|
|
656
655
|
raw_tags = new_value || {}
|
@@ -958,6 +957,30 @@ module Datadog
|
|
958
957
|
end
|
959
958
|
end
|
960
959
|
|
960
|
+
# Tracer specific configuration starting with APM (e.g. DD_APM_TRACING_ENABLED).
|
961
|
+
# @public_api
|
962
|
+
settings :apm do
|
963
|
+
# Tracing as a transport
|
964
|
+
# @public_api
|
965
|
+
settings :tracing do
|
966
|
+
# Enables tracing as transport.
|
967
|
+
# Disabling it will set sampling priority to -1 (FORCE_DROP) on most traces,
|
968
|
+
# (which tells to the agent to drop these traces)
|
969
|
+
# except heartbeat ones (1 per minute) and manually kept ones (sampling priority to 2) (e.g. appsec events)
|
970
|
+
#
|
971
|
+
# This is different than `DD_TRACE_ENABLED`, which completely disables tracing (sends no trace at all),
|
972
|
+
# while this will send heartbeat traces (1 per minute) so that the service is considered alive in the backend.
|
973
|
+
#
|
974
|
+
# @default `DD_APM_TRACING_ENABLED` environment variable, otherwise `true`
|
975
|
+
# @return [Boolean]
|
976
|
+
option :enabled do |o|
|
977
|
+
o.env Configuration::Ext::APM::ENV_TRACING_ENABLED
|
978
|
+
o.default true
|
979
|
+
o.type :bool
|
980
|
+
end
|
981
|
+
end
|
982
|
+
end
|
983
|
+
|
961
984
|
# TODO: Tracing should manage its own settings.
|
962
985
|
# Keep this extension here for now to keep things working.
|
963
986
|
extend Datadog::Tracing::Configuration::Settings
|
@@ -51,11 +51,12 @@ module Datadog
|
|
51
51
|
#
|
52
52
|
# @see https://github.com/DataDog/datadog-agent/blob/f07df0a3c1fca0c83b5a15f553bd994091b0c8ac/pkg/trace/api/info.go#L20
|
53
53
|
class AgentInfo
|
54
|
-
attr_reader :agent_settings
|
54
|
+
attr_reader :agent_settings, :logger
|
55
55
|
|
56
|
-
def initialize(agent_settings)
|
56
|
+
def initialize(agent_settings, logger:)
|
57
57
|
@agent_settings = agent_settings
|
58
|
-
@
|
58
|
+
@logger = logger
|
59
|
+
@client = Remote::Transport::HTTP.root(agent_settings: agent_settings, logger: logger)
|
59
60
|
end
|
60
61
|
|
61
62
|
# Fetches the information from the agent.
|
@@ -18,11 +18,8 @@ module Datadog
|
|
18
18
|
def initialize(settings, capabilities, agent_settings, logger:)
|
19
19
|
@logger = logger
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
negotiation = Negotiation.new(settings, agent_settings)
|
25
|
-
transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(**transport_options) # steep:ignore
|
21
|
+
negotiation = Negotiation.new(settings, agent_settings, logger: logger)
|
22
|
+
transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(agent_settings: agent_settings, logger: logger)
|
26
23
|
|
27
24
|
@barrier = Barrier.new(settings.remote.boot_timeout_seconds)
|
28
25
|
|
@@ -49,7 +46,7 @@ module Datadog
|
|
49
46
|
# In case of unexpected errors, reset the negotiation object
|
50
47
|
# given external conditions have changed and the negotiation
|
51
48
|
# negotiation object stores error logging state that should be reset.
|
52
|
-
negotiation = Negotiation.new(settings, agent_settings)
|
49
|
+
negotiation = Negotiation.new(settings, agent_settings, logger: logger)
|
53
50
|
|
54
51
|
# Transient errors due to network or agent. Logged the error but not via telemetry
|
55
52
|
logger.error do
|
@@ -272,7 +272,8 @@ module Datadog
|
|
272
272
|
|
273
273
|
return deleted(path, previous) if previous && content.nil?
|
274
274
|
return inserted(path, content) if content && previous.nil?
|
275
|
-
|
275
|
+
|
276
|
+
updated(path, content, previous) if content && previous
|
276
277
|
end
|
277
278
|
|
278
279
|
def deleted(path, previous)
|