datadog 2.9.0 → 2.11.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 +72 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +2 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +46 -6
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +51 -93
- data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +56 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
- data/ext/datadog_profiling_native_extension/profiling.c +7 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +9 -22
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
- data/ext/libdatadog_api/crashtracker.c +4 -4
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/actions_handler.rb +27 -0
- data/lib/datadog/appsec/component.rb +14 -8
- data/lib/datadog/appsec/configuration/settings.rb +73 -11
- data/lib/datadog/appsec/context.rb +28 -8
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +6 -2
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
- data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
- data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
- data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
- data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +11 -14
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +65 -70
- data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +11 -22
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -24
- data/lib/datadog/appsec/contrib/rails/patcher.rb +3 -16
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -47
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +3 -29
- data/lib/datadog/appsec/ext.rb +6 -1
- data/lib/datadog/appsec/metrics/collector.rb +38 -0
- data/lib/datadog/appsec/metrics/exporter.rb +35 -0
- data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
- data/lib/datadog/appsec/metrics.rb +13 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -24
- data/lib/datadog/appsec/processor.rb +4 -3
- data/lib/datadog/appsec/remote.rb +4 -0
- data/lib/datadog/appsec/response.rb +18 -80
- data/lib/datadog/appsec/security_engine/result.rb +67 -0
- data/lib/datadog/appsec/security_engine/runner.rb +88 -0
- data/lib/datadog/appsec/security_engine.rb +9 -0
- data/lib/datadog/appsec.rb +16 -5
- data/lib/datadog/core/configuration/components.rb +7 -1
- data/lib/datadog/core/configuration/ext.rb +1 -1
- data/lib/datadog/core/configuration/option_definition.rb +2 -0
- data/lib/datadog/core/configuration/settings.rb +22 -6
- data/lib/datadog/core/encoding.rb +16 -0
- data/lib/datadog/core/environment/agent_info.rb +77 -0
- data/lib/datadog/core/remote/transport/http/api.rb +13 -18
- data/lib/datadog/core/remote/transport/http/config.rb +0 -18
- data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
- data/lib/datadog/core/remote/transport/http.rb +7 -12
- data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
- data/lib/datadog/core/telemetry/event.rb +5 -0
- data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
- data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
- data/lib/datadog/core/transport/response.rb +4 -0
- data/lib/datadog/di/code_tracker.rb +15 -8
- data/lib/datadog/di/component.rb +3 -0
- data/lib/datadog/di/configuration/settings.rb +14 -0
- data/lib/datadog/di/contrib.rb +2 -0
- data/lib/datadog/di/logger.rb +30 -0
- data/lib/datadog/di/probe.rb +3 -6
- data/lib/datadog/di/probe_manager.rb +5 -2
- data/lib/datadog/di/probe_notification_builder.rb +6 -0
- data/lib/datadog/di/probe_notifier_worker.rb +15 -4
- data/lib/datadog/di/redactor.rb +0 -1
- data/lib/datadog/di/remote.rb +29 -8
- data/lib/datadog/di/utils.rb +91 -0
- data/lib/datadog/di.rb +3 -0
- data/lib/datadog/profiling/component.rb +2 -8
- data/lib/datadog/profiling/load_native_extension.rb +1 -33
- data/lib/datadog/tracing/configuration/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/aws/integration.rb +1 -1
- data/lib/datadog/tracing/contrib/extensions.rb +29 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
- data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
- data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
- data/lib/datadog/tracing/transport/http/api.rb +11 -2
- data/lib/datadog/tracing/transport/http/traces.rb +0 -3
- data/lib/datadog/tracing/transport/http.rb +12 -7
- data/lib/datadog/tracing/transport/serializable_trace.rb +8 -4
- data/lib/datadog/tracing/transport/traces.rb +25 -8
- data/lib/datadog/version.rb +1 -1
- metadata +51 -42
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
- data/ext/datadog_profiling_loader/extconf.rb +0 -60
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
- data/lib/datadog/appsec/contrib/patcher.rb +0 -12
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
- data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
- data/lib/datadog/appsec/processor/context.rb +0 -107
- data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
- data/lib/datadog/appsec/reactive/engine.rb +0 -47
- data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
- data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
- data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
- data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
# This namespace contains classes related to metrics collection and exportation.
|
6
|
+
module Metrics
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative 'metrics/collector'
|
12
|
+
require_relative 'metrics/exporter'
|
13
|
+
require_relative 'metrics/telemetry'
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../../instrumentation/gateway'
|
4
|
-
require_relative '../../reactive/engine'
|
5
|
-
require_relative '../reactive/set_user'
|
6
4
|
|
7
5
|
module Datadog
|
8
6
|
module AppSec
|
@@ -19,30 +17,27 @@ module Datadog
|
|
19
17
|
|
20
18
|
def watch_user_id(gateway = Instrumentation.gateway)
|
21
19
|
gateway.watch('identity.set_user', :appsec) do |stack, user|
|
22
|
-
event = nil
|
23
20
|
context = Datadog::AppSec.active_context
|
24
|
-
engine = AppSec::Reactive::Engine.new
|
25
|
-
|
26
|
-
Monitor::Reactive::SetUser.subscribe(engine, context) do |result|
|
27
|
-
if result.status == :match
|
28
|
-
# TODO: should this hash be an Event instance instead?
|
29
|
-
event = {
|
30
|
-
waf_result: result,
|
31
|
-
trace: context.trace,
|
32
|
-
span: context.span,
|
33
|
-
user: user,
|
34
|
-
actions: result.actions
|
35
|
-
}
|
36
|
-
|
37
|
-
# We want to keep the trace in case of security event
|
38
|
-
context.trace.keep! if context.trace
|
39
|
-
Datadog::AppSec::Event.tag_and_keep!(context, result)
|
40
|
-
context.waf_runner.events << event
|
41
|
-
end
|
42
|
-
end
|
43
21
|
|
44
|
-
|
45
|
-
|
22
|
+
persistent_data = {
|
23
|
+
'usr.id' => user.id
|
24
|
+
}
|
25
|
+
|
26
|
+
result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
|
27
|
+
|
28
|
+
if result.match?
|
29
|
+
Datadog::AppSec::Event.tag_and_keep!(context, result)
|
30
|
+
|
31
|
+
context.events << {
|
32
|
+
waf_result: result,
|
33
|
+
trace: context.trace,
|
34
|
+
span: context.span,
|
35
|
+
user: user,
|
36
|
+
actions: result.actions
|
37
|
+
}
|
38
|
+
|
39
|
+
Datadog::AppSec::ActionsHandler.handle(result.actions)
|
40
|
+
end
|
46
41
|
|
47
42
|
stack.call(user)
|
48
43
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'security_engine/runner'
|
4
4
|
|
5
5
|
module Datadog
|
6
6
|
module AppSec
|
7
7
|
# Processor integrates libddwaf into datadog/appsec
|
8
|
+
# NOTE: This class will be moved under AppSec::SecurityEngine namespace
|
8
9
|
class Processor
|
9
10
|
attr_reader :diagnostics, :addresses
|
10
11
|
|
@@ -29,8 +30,8 @@ module Datadog
|
|
29
30
|
@handle.finalize
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
-
|
33
|
+
def new_runner
|
34
|
+
SecurityEngine::Runner.new(@handle, telemetry: @telemetry)
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
@@ -19,100 +19,38 @@ module Datadog
|
|
19
19
|
[status, headers, body]
|
20
20
|
end
|
21
21
|
|
22
|
-
def to_sinatra_response
|
23
|
-
::Sinatra::Response.new(body, status, headers)
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_action_dispatch_response
|
27
|
-
::ActionDispatch::Response.new(status, headers, body)
|
28
|
-
end
|
29
|
-
|
30
22
|
class << self
|
31
|
-
def
|
32
|
-
|
33
|
-
configured_response = nil
|
34
|
-
actions.each do |type, parameters|
|
35
|
-
# Need to use next to make steep happy :(
|
36
|
-
# I rather use break to stop the execution
|
37
|
-
next if configured_response
|
38
|
-
|
39
|
-
configured_response = case type
|
40
|
-
when 'block_request'
|
41
|
-
block_response(env, parameters)
|
42
|
-
when 'redirect_request'
|
43
|
-
redirect_response(env, parameters)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
configured_response || default_response(env)
|
48
|
-
end
|
49
|
-
|
50
|
-
def graphql_response(gateway_multiplex)
|
51
|
-
multiplex_return = []
|
52
|
-
gateway_multiplex.queries.each do |query|
|
53
|
-
# This method is only called in places where GraphQL-Ruby is already required
|
54
|
-
query_result = ::GraphQL::Query::Result.new(
|
55
|
-
query: query,
|
56
|
-
values: JSON.parse(content('application/json'))
|
57
|
-
)
|
58
|
-
multiplex_return << query_result
|
59
|
-
end
|
23
|
+
def from_interrupt_params(interrupt_params, http_accept_header)
|
24
|
+
return redirect_response(interrupt_params) if interrupt_params['location']
|
60
25
|
|
61
|
-
|
26
|
+
block_response(interrupt_params, http_accept_header)
|
62
27
|
end
|
63
28
|
|
64
29
|
private
|
65
30
|
|
66
|
-
def
|
67
|
-
content_type =
|
68
|
-
|
69
|
-
|
70
|
-
|
31
|
+
def block_response(interrupt_params, http_accept_header)
|
32
|
+
content_type = case interrupt_params['type']
|
33
|
+
when nil, 'auto' then content_type(http_accept_header)
|
34
|
+
else FORMAT_TO_CONTENT_TYPE.fetch(interrupt_params['type'], DEFAULT_CONTENT_TYPE)
|
35
|
+
end
|
71
36
|
|
72
37
|
Response.new(
|
73
|
-
status: 403,
|
38
|
+
status: interrupt_params['status_code']&.to_i || 403,
|
74
39
|
headers: { 'Content-Type' => content_type },
|
75
|
-
body:
|
40
|
+
body: [content(content_type)],
|
76
41
|
)
|
77
42
|
end
|
78
43
|
|
79
|
-
def
|
80
|
-
|
81
|
-
content_type(env)
|
82
|
-
else
|
83
|
-
FORMAT_TO_CONTENT_TYPE[options['type']]
|
84
|
-
end
|
85
|
-
|
86
|
-
body = []
|
87
|
-
body << content(content_type)
|
44
|
+
def redirect_response(interrupt_params)
|
45
|
+
status_code = interrupt_params['status_code'].to_i
|
88
46
|
|
89
47
|
Response.new(
|
90
|
-
status:
|
91
|
-
headers: { '
|
92
|
-
body:
|
48
|
+
status: (status_code >= 300 && status_code < 400 ? status_code : 303),
|
49
|
+
headers: { 'Location' => interrupt_params.fetch('location') },
|
50
|
+
body: [],
|
93
51
|
)
|
94
52
|
end
|
95
53
|
|
96
|
-
def redirect_response(env, options)
|
97
|
-
if options['location'] && !options['location'].empty?
|
98
|
-
content_type = content_type(env)
|
99
|
-
|
100
|
-
headers = {
|
101
|
-
'Content-Type' => content_type,
|
102
|
-
'Location' => options['location']
|
103
|
-
}
|
104
|
-
|
105
|
-
status_code = options['status_code'].to_i
|
106
|
-
Response.new(
|
107
|
-
status: (status_code >= 300 && status_code < 400 ? status_code : 303),
|
108
|
-
headers: headers,
|
109
|
-
body: [],
|
110
|
-
)
|
111
|
-
else
|
112
|
-
default_response(env)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
54
|
CONTENT_TYPE_TO_FORMAT = {
|
117
55
|
'application/json' => :json,
|
118
56
|
'text/html' => :html,
|
@@ -126,10 +64,10 @@ module Datadog
|
|
126
64
|
|
127
65
|
DEFAULT_CONTENT_TYPE = 'application/json'
|
128
66
|
|
129
|
-
def content_type(
|
130
|
-
return DEFAULT_CONTENT_TYPE
|
67
|
+
def content_type(http_accept_header)
|
68
|
+
return DEFAULT_CONTENT_TYPE if http_accept_header.nil?
|
131
69
|
|
132
|
-
accept_types =
|
70
|
+
accept_types = http_accept_header.split(',').map(&:strip)
|
133
71
|
|
134
72
|
accepted = accept_types.map { |m| Utils::HTTP::MediaRange.new(m) }.sort!.reverse!
|
135
73
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module SecurityEngine
|
6
|
+
# A namespace for value-objects representing the result of WAF check.
|
7
|
+
module Result
|
8
|
+
# A generic result without indication of its type.
|
9
|
+
class Base
|
10
|
+
attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
|
11
|
+
|
12
|
+
def initialize(events:, actions:, derivatives:, timeout:, duration_ns:, duration_ext_ns:)
|
13
|
+
@events = events
|
14
|
+
@actions = actions
|
15
|
+
@derivatives = derivatives
|
16
|
+
|
17
|
+
@timeout = timeout
|
18
|
+
@duration_ns = duration_ns
|
19
|
+
@duration_ext_ns = duration_ext_ns
|
20
|
+
end
|
21
|
+
|
22
|
+
def timeout?
|
23
|
+
!!@timeout
|
24
|
+
end
|
25
|
+
|
26
|
+
def match?
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# A result that indicates a security rule match
|
32
|
+
class Match < Base
|
33
|
+
def match?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A result that indicates a successful security rules check without a match
|
39
|
+
class Ok < Base
|
40
|
+
def match?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# A result that indicates an internal security library error
|
46
|
+
class Error
|
47
|
+
attr_reader :events, :actions, :derivatives, :duration_ns, :duration_ext_ns
|
48
|
+
|
49
|
+
def initialize(duration_ext_ns:)
|
50
|
+
@events = []
|
51
|
+
@actions = @derivatives = {}
|
52
|
+
@duration_ns = 0
|
53
|
+
@duration_ext_ns = duration_ext_ns
|
54
|
+
end
|
55
|
+
|
56
|
+
def timeout?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def match?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'result'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module AppSec
|
7
|
+
module SecurityEngine
|
8
|
+
# A class that check input via security engine (WAF) and respond with result.
|
9
|
+
class Runner
|
10
|
+
SUCCESSFUL_EXECUTION_CODES = [:ok, :match].freeze
|
11
|
+
|
12
|
+
def initialize(handle, telemetry:)
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@context = WAF::Context.new(handle)
|
15
|
+
@telemetry = telemetry
|
16
|
+
|
17
|
+
@debug_tag = "libddwaf:#{WAF::VERSION::STRING} method:ddwaf_run"
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
21
|
+
@mutex.lock
|
22
|
+
|
23
|
+
start_ns = Core::Utils::Time.get_time(:nanosecond)
|
24
|
+
persistent_data.reject! do |_, v|
|
25
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
26
|
+
|
27
|
+
v.nil? ? true : v.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
ephemeral_data.reject! do |_, v|
|
31
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
32
|
+
|
33
|
+
v.nil? ? true : v.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
_code, result = try_run(persistent_data, ephemeral_data, timeout)
|
37
|
+
stop_ns = Core::Utils::Time.get_time(:nanosecond)
|
38
|
+
|
39
|
+
report_execution(result)
|
40
|
+
|
41
|
+
unless SUCCESSFUL_EXECUTION_CODES.include?(result.status)
|
42
|
+
return Result::Error.new(duration_ext_ns: stop_ns - start_ns)
|
43
|
+
end
|
44
|
+
|
45
|
+
klass = result.status == :match ? Result::Match : Result::Ok
|
46
|
+
klass.new(
|
47
|
+
events: result.events,
|
48
|
+
actions: result.actions,
|
49
|
+
derivatives: result.derivatives,
|
50
|
+
timeout: result.timeout,
|
51
|
+
duration_ns: result.total_runtime,
|
52
|
+
duration_ext_ns: (stop_ns - start_ns)
|
53
|
+
)
|
54
|
+
ensure
|
55
|
+
@mutex.unlock
|
56
|
+
end
|
57
|
+
|
58
|
+
def finalize
|
59
|
+
@context.finalize
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def try_run(persistent_data, ephemeral_data, timeout)
|
65
|
+
@context.run(persistent_data, ephemeral_data, timeout)
|
66
|
+
rescue WAF::LibDDWAF::Error => e
|
67
|
+
Datadog.logger.debug { "#{@debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
|
68
|
+
@telemetry.report(e, description: 'libddwaf-rb internal low-level error')
|
69
|
+
|
70
|
+
[:err_internal, WAF::Result.new(:err_internal, [], 0, false, [], [])]
|
71
|
+
end
|
72
|
+
|
73
|
+
def report_execution(result)
|
74
|
+
Datadog.logger.debug { "#{@debug_tag} execution timed out: #{result.inspect}" } if result.timeout
|
75
|
+
|
76
|
+
if SUCCESSFUL_EXECUTION_CODES.include?(result.status)
|
77
|
+
Datadog.logger.debug { "#{@debug_tag} execution result: #{result.inspect}" }
|
78
|
+
else
|
79
|
+
message = "#{@debug_tag} execution error: #{result.status.inspect}"
|
80
|
+
|
81
|
+
Datadog.logger.debug { message }
|
82
|
+
@telemetry.error(message)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/datadog/appsec.rb
CHANGED
@@ -14,19 +14,24 @@ module Datadog
|
|
14
14
|
Datadog.configuration.appsec.enabled
|
15
15
|
end
|
16
16
|
|
17
|
+
def rasp_enabled?
|
18
|
+
Datadog.configuration.appsec.rasp_enabled
|
19
|
+
end
|
20
|
+
|
17
21
|
def active_context
|
18
22
|
Datadog::AppSec::Context.active
|
19
23
|
end
|
20
24
|
|
21
|
-
def
|
22
|
-
|
25
|
+
def telemetry
|
26
|
+
components.appsec&.telemetry
|
27
|
+
end
|
23
28
|
|
24
|
-
|
29
|
+
def processor
|
30
|
+
components.appsec&.processor
|
25
31
|
end
|
26
32
|
|
27
33
|
def reconfigure(ruleset:, telemetry:)
|
28
34
|
appsec_component = components.appsec
|
29
|
-
|
30
35
|
return unless appsec_component
|
31
36
|
|
32
37
|
appsec_component.reconfigure(ruleset: ruleset, telemetry: telemetry)
|
@@ -34,12 +39,16 @@ module Datadog
|
|
34
39
|
|
35
40
|
def reconfigure_lock(&block)
|
36
41
|
appsec_component = components.appsec
|
37
|
-
|
38
42
|
return unless appsec_component
|
39
43
|
|
40
44
|
appsec_component.reconfigure_lock(&block)
|
41
45
|
end
|
42
46
|
|
47
|
+
def api_security_enabled?
|
48
|
+
Datadog.configuration.appsec.api_security.enabled &&
|
49
|
+
Datadog.configuration.appsec.api_security.sample_rate.sample?
|
50
|
+
end
|
51
|
+
|
43
52
|
private
|
44
53
|
|
45
54
|
def components
|
@@ -59,5 +68,7 @@ require_relative 'appsec/contrib/rails/integration'
|
|
59
68
|
require_relative 'appsec/contrib/active_record/integration'
|
60
69
|
require_relative 'appsec/contrib/devise/integration'
|
61
70
|
require_relative 'appsec/contrib/graphql/integration'
|
71
|
+
require_relative 'appsec/contrib/faraday/integration'
|
72
|
+
require_relative 'appsec/contrib/excon/integration'
|
62
73
|
|
63
74
|
require_relative 'appsec/autoload'
|
@@ -16,6 +16,8 @@ require_relative '../../appsec/component'
|
|
16
16
|
require_relative '../../di/component'
|
17
17
|
require_relative '../crashtracking/component'
|
18
18
|
|
19
|
+
require_relative '../environment/agent_info'
|
20
|
+
|
19
21
|
module Datadog
|
20
22
|
module Core
|
21
23
|
module Configuration
|
@@ -85,7 +87,8 @@ module Datadog
|
|
85
87
|
:tracer,
|
86
88
|
:crashtracker,
|
87
89
|
:dynamic_instrumentation,
|
88
|
-
:appsec
|
90
|
+
:appsec,
|
91
|
+
:agent_info
|
89
92
|
|
90
93
|
def initialize(settings)
|
91
94
|
@logger = self.class.build_logger(settings)
|
@@ -96,6 +99,9 @@ module Datadog
|
|
96
99
|
# the Core resolver from within your product/component's namespace.
|
97
100
|
agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
|
98
101
|
|
102
|
+
# Exposes agent capability information for detection by any components
|
103
|
+
@agent_info = Core::Environment::AgentInfo.new(agent_settings)
|
104
|
+
|
99
105
|
@telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
|
100
106
|
|
101
107
|
@remote = Remote::Component.build(settings, agent_settings, telemetry: telemetry)
|
@@ -79,6 +79,8 @@ module Datadog
|
|
79
79
|
@deprecated_env = value
|
80
80
|
end
|
81
81
|
|
82
|
+
# Invoked when the option is first read, and {#env} is defined.
|
83
|
+
# The block provided is only invoked if the environment variable is present (not-nil).
|
82
84
|
def env_parser(&block)
|
83
85
|
@env_parser = block
|
84
86
|
end
|
@@ -461,15 +461,31 @@ module Datadog
|
|
461
461
|
end
|
462
462
|
end
|
463
463
|
|
464
|
-
#
|
465
|
-
#
|
466
|
-
# This is a preview feature and disabled by default. It requires Ruby 3.2+.
|
467
|
-
#
|
468
|
-
# @default `DD_PROFILING_PREVIEW_GVL_ENABLED` environment variable as a boolean, otherwise `false`
|
464
|
+
# @deprecated Use {:gvl_enabled} instead.
|
469
465
|
option :preview_gvl_enabled do |o|
|
470
466
|
o.type :bool
|
471
|
-
o.env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
|
472
467
|
o.default false
|
468
|
+
o.after_set do |_, _, precedence|
|
469
|
+
unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
|
470
|
+
Datadog.logger.warn(
|
471
|
+
'The profiling.advanced.preview_gvl_enabled setting has been deprecated for removal and ' \
|
472
|
+
'no longer does anything. Please remove it from your Datadog.configure block. ' \
|
473
|
+
'GVL profiling is now controlled by the profiling.advanced.gvl_enabled setting instead.'
|
474
|
+
)
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Controls GVL profiling. This will show when threads are waiting for GVL in the timeline view.
|
480
|
+
#
|
481
|
+
# This feature requires Ruby 3.2+.
|
482
|
+
#
|
483
|
+
# @default `DD_PROFILING_GVL_ENABLED` environment variable as a boolean, otherwise `true`
|
484
|
+
option :gvl_enabled do |o|
|
485
|
+
o.type :bool
|
486
|
+
o.deprecated_env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
|
487
|
+
o.env 'DD_PROFILING_GVL_ENABLED'
|
488
|
+
o.default true
|
473
489
|
end
|
474
490
|
|
475
491
|
# Controls the smallest time period the profiler will report a thread waiting for the GVL.
|
@@ -10,6 +10,7 @@ module Datadog
|
|
10
10
|
# Encoder interface that provides the logic to encode traces and service
|
11
11
|
# @abstract
|
12
12
|
module Encoder
|
13
|
+
# :nocov:
|
13
14
|
def content_type
|
14
15
|
raise NotImplementedError
|
15
16
|
end
|
@@ -23,6 +24,13 @@ module Datadog
|
|
23
24
|
def encode(_)
|
24
25
|
raise NotImplementedError
|
25
26
|
end
|
27
|
+
|
28
|
+
# Deserializes a value serialized with {#encode}.
|
29
|
+
# This method is used for debugging purposes.
|
30
|
+
def decode(_)
|
31
|
+
raise NotImplementedError
|
32
|
+
end
|
33
|
+
# :nocov:
|
26
34
|
end
|
27
35
|
|
28
36
|
# Encoder for the JSON format
|
@@ -41,6 +49,10 @@ module Datadog
|
|
41
49
|
JSON.dump(obj)
|
42
50
|
end
|
43
51
|
|
52
|
+
def decode(obj)
|
53
|
+
JSON.parse(obj)
|
54
|
+
end
|
55
|
+
|
44
56
|
def join(encoded_data)
|
45
57
|
"[#{encoded_data.join(',')}]"
|
46
58
|
end
|
@@ -62,6 +74,10 @@ module Datadog
|
|
62
74
|
MessagePack.pack(obj)
|
63
75
|
end
|
64
76
|
|
77
|
+
def decode(obj)
|
78
|
+
MessagePack.unpack(obj)
|
79
|
+
end
|
80
|
+
|
65
81
|
def join(encoded_data)
|
66
82
|
packer = MessagePack::Packer.new
|
67
83
|
packer.write_array_header(encoded_data.size)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Core
|
5
|
+
module Environment
|
6
|
+
# Retrieves the agent's `/info` endpoint data.
|
7
|
+
# This data can be used to determine the capabilities of the local Datadog agent.
|
8
|
+
#
|
9
|
+
# @example Example response payload
|
10
|
+
# {
|
11
|
+
# "version" : "7.57.2",
|
12
|
+
# "git_commit" : "38ba0c7",
|
13
|
+
# "endpoints" : [ "/v0.4/traces", "/v0.4/services", "/v0.7/traces", "/v0.7/config" ],
|
14
|
+
# "client_drop_p0s" : true,
|
15
|
+
# "span_meta_structs" : true,
|
16
|
+
# "long_running_spans" : true,
|
17
|
+
# "evp_proxy_allowed_headers" : [ "Content-Type", "Accept-Encoding", "Content-Encoding", "User-Agent" ],
|
18
|
+
# "config" : {
|
19
|
+
# "default_env" : "none",
|
20
|
+
# "target_tps" : 10,
|
21
|
+
# "max_eps" : 200,
|
22
|
+
# "receiver_port" : 8126,
|
23
|
+
# "receiver_socket" : "/var/run/datadog/apm.socket",
|
24
|
+
# "connection_limit" : 0,
|
25
|
+
# "receiver_timeout" : 0,
|
26
|
+
# "max_request_bytes" : 26214400,
|
27
|
+
# "statsd_port" : 8125,
|
28
|
+
# "analyzed_spans_by_service" : { },
|
29
|
+
# "obfuscation" : {
|
30
|
+
# "elastic_search" : true,
|
31
|
+
# "mongo" : true,
|
32
|
+
# "sql_exec_plan" : false,
|
33
|
+
# "sql_exec_plan_normalize" : false,
|
34
|
+
# "http" : {
|
35
|
+
# "remove_query_string" : false,
|
36
|
+
# "remove_path_digits" : false
|
37
|
+
# },
|
38
|
+
# "remove_stack_traces" : false,
|
39
|
+
# "redis" : {
|
40
|
+
# "Enabled" : true,
|
41
|
+
# "RemoveAllArgs" : false
|
42
|
+
# },
|
43
|
+
# "memcached" : {
|
44
|
+
# "Enabled" : true,
|
45
|
+
# "KeepCommand" : false
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
# },
|
49
|
+
# "peer_tags" : null
|
50
|
+
# }
|
51
|
+
#
|
52
|
+
# @see https://github.com/DataDog/datadog-agent/blob/f07df0a3c1fca0c83b5a15f553bd994091b0c8ac/pkg/trace/api/info.go#L20
|
53
|
+
class AgentInfo
|
54
|
+
attr_reader :agent_settings
|
55
|
+
|
56
|
+
def initialize(agent_settings)
|
57
|
+
@agent_settings = agent_settings
|
58
|
+
@client = Remote::Transport::HTTP.root(agent_settings: agent_settings)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fetches the information from the agent.
|
62
|
+
# @return [Datadog::Core::Remote::Transport::HTTP::Negotiation::Response] the response from the agent
|
63
|
+
# @return [nil] if an error occurred while fetching the information
|
64
|
+
def fetch
|
65
|
+
res = @client.send_info
|
66
|
+
return unless res.ok?
|
67
|
+
|
68
|
+
res
|
69
|
+
end
|
70
|
+
|
71
|
+
def ==(other)
|
72
|
+
other.is_a?(self.class) && other.agent_settings == agent_settings
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|