datadog 2.7.1 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +259 -132
  10. data/ext/datadog_profiling_native_extension/extconf.rb +0 -8
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +11 -89
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  13. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +4 -1
  15. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  16. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  18. data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -88
  19. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  20. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  21. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  22. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  23. data/ext/libdatadog_api/crashtracker.c +3 -0
  24. data/ext/libdatadog_extconf_helpers.rb +1 -1
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  26. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  27. data/lib/datadog/appsec/component.rb +1 -8
  28. data/lib/datadog/appsec/context.rb +54 -0
  29. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +73 -0
  30. data/lib/datadog/appsec/contrib/active_record/integration.rb +41 -0
  31. data/lib/datadog/appsec/contrib/active_record/patcher.rb +53 -0
  32. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  33. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  34. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
  35. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
  36. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
  38. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
  39. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
  40. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
  41. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  42. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
  43. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
  44. data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
  46. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
  47. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
  48. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
  49. data/lib/datadog/appsec/event.rb +6 -6
  50. data/lib/datadog/appsec/ext.rb +3 -1
  51. data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
  52. data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
  53. data/lib/datadog/appsec/processor/context.rb +2 -2
  54. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  55. data/lib/datadog/appsec/remote.rb +1 -3
  56. data/lib/datadog/appsec/response.rb +7 -11
  57. data/lib/datadog/appsec.rb +6 -5
  58. data/lib/datadog/auto_instrument.rb +3 -0
  59. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  60. data/lib/datadog/core/configuration/components.rb +20 -2
  61. data/lib/datadog/core/configuration/settings.rb +10 -0
  62. data/lib/datadog/core/configuration.rb +10 -2
  63. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  64. data/lib/datadog/core/crashtracking/component.rb +1 -3
  65. data/lib/datadog/core/remote/client/capabilities.rb +6 -0
  66. data/lib/datadog/core/remote/client.rb +65 -59
  67. data/lib/datadog/core/telemetry/component.rb +9 -3
  68. data/lib/datadog/core/telemetry/event.rb +87 -3
  69. data/lib/datadog/core/telemetry/ext.rb +1 -0
  70. data/lib/datadog/core/telemetry/logging.rb +2 -2
  71. data/lib/datadog/core/telemetry/metric.rb +22 -0
  72. data/lib/datadog/core/telemetry/worker.rb +33 -0
  73. data/lib/datadog/di/base.rb +115 -0
  74. data/lib/datadog/di/code_tracker.rb +11 -7
  75. data/lib/datadog/di/component.rb +21 -11
  76. data/lib/datadog/di/configuration/settings.rb +11 -1
  77. data/lib/datadog/di/contrib/active_record.rb +1 -0
  78. data/lib/datadog/di/contrib/railtie.rb +15 -0
  79. data/lib/datadog/di/contrib.rb +26 -0
  80. data/lib/datadog/di/error.rb +5 -0
  81. data/lib/datadog/di/instrumenter.rb +111 -20
  82. data/lib/datadog/di/preload.rb +18 -0
  83. data/lib/datadog/di/probe.rb +11 -1
  84. data/lib/datadog/di/probe_builder.rb +1 -0
  85. data/lib/datadog/di/probe_manager.rb +8 -5
  86. data/lib/datadog/di/probe_notification_builder.rb +27 -7
  87. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  88. data/lib/datadog/di/remote.rb +124 -0
  89. data/lib/datadog/di/serializer.rb +14 -7
  90. data/lib/datadog/di/transport.rb +3 -5
  91. data/lib/datadog/di/utils.rb +7 -0
  92. data/lib/datadog/di.rb +23 -62
  93. data/lib/datadog/kit/appsec/events.rb +3 -3
  94. data/lib/datadog/kit/identity.rb +4 -4
  95. data/lib/datadog/profiling/component.rb +59 -69
  96. data/lib/datadog/profiling/http_transport.rb +1 -26
  97. data/lib/datadog/tracing/configuration/settings.rb +4 -8
  98. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  99. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  100. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  101. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  102. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  103. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  104. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  105. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  106. data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +16 -4
  107. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  108. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  109. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  110. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  111. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  112. data/lib/datadog/tracing/contrib/elasticsearch/configuration/settings.rb +4 -0
  113. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  114. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  115. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  116. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  117. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  118. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  119. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  120. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  121. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  122. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  123. data/lib/datadog/tracing/span.rb +12 -4
  124. data/lib/datadog/tracing/span_event.rb +123 -3
  125. data/lib/datadog/tracing/span_operation.rb +6 -0
  126. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  127. data/lib/datadog/version.rb +2 -2
  128. data/lib/datadog.rb +3 -0
  129. metadata +30 -17
  130. data/lib/datadog/appsec/processor/actions.rb +0 -49
  131. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  132. data/lib/datadog/appsec/scope.rb +0 -58
  133. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -15,18 +15,18 @@ module Datadog
15
15
  ].freeze
16
16
  private_constant :ADDRESSES
17
17
 
18
- def self.publish(op, gateway_request)
18
+ def self.publish(engine, gateway_request)
19
19
  catch(:block) do
20
20
  # params have been parsed from the request body
21
- op.publish('rails.request.body', gateway_request.parsed_body)
22
- op.publish('rails.request.route_params', gateway_request.route_params)
21
+ engine.publish('rails.request.body', gateway_request.parsed_body)
22
+ engine.publish('rails.request.route_params', gateway_request.route_params)
23
23
 
24
24
  nil
25
25
  end
26
26
  end
27
27
 
28
- def self.subscribe(op, waf_context)
29
- op.subscribe(*ADDRESSES) do |*values|
28
+ def self.subscribe(engine, context)
29
+ engine.subscribe(*ADDRESSES) do |*values|
30
30
  Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
31
31
  body = values[0]
32
32
  path_params = values[1]
@@ -37,7 +37,7 @@ module Datadog
37
37
  }
38
38
 
39
39
  waf_timeout = Datadog.configuration.appsec.waf_timeout
40
- result = waf_context.run(persistent_data, {}, waf_timeout)
40
+ result = context.run_waf(persistent_data, {}, waf_timeout)
41
41
 
42
42
  next if result.status != :match
43
43
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../../instrumentation/gateway'
4
- require_relative '../../../reactive/operation'
4
+ require_relative '../../../reactive/engine'
5
5
  require_relative '../../rack/reactive/request_body'
6
6
  require_relative '../reactive/routed'
7
7
  require_relative '../../../event'
@@ -23,85 +23,63 @@ module Datadog
23
23
 
24
24
  def watch_request_dispatch(gateway = Instrumentation.gateway)
25
25
  gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request|
26
- block = false
27
-
28
26
  event = nil
29
- scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
30
-
31
- AppSec::Reactive::Operation.new('sinatra.request.dispatch') do |op|
32
- Rack::Reactive::RequestBody.subscribe(op, scope.processor_context) do |result|
33
- if result.status == :match
34
- # TODO: should this hash be an Event instance instead?
35
- event = {
36
- waf_result: result,
37
- trace: scope.trace,
38
- span: scope.service_entry_span,
39
- request: gateway_request,
40
- actions: result.actions
41
- }
42
-
43
- # We want to keep the trace in case of security event
44
- scope.trace.keep! if scope.trace
45
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
46
- scope.processor_context.events << event
47
- end
27
+ context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
28
+ engine = AppSec::Reactive::Engine.new
29
+
30
+ Rack::Reactive::RequestBody.subscribe(engine, context) do |result|
31
+ if result.status == :match
32
+ # TODO: should this hash be an Event instance instead?
33
+ event = {
34
+ waf_result: result,
35
+ trace: context.trace,
36
+ span: context.span,
37
+ request: gateway_request,
38
+ actions: result.actions
39
+ }
40
+
41
+ # We want to keep the trace in case of security event
42
+ context.trace.keep! if context.trace
43
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
44
+ context.waf_runner.events << event
48
45
  end
49
-
50
- block = Rack::Reactive::RequestBody.publish(op, gateway_request)
51
46
  end
52
47
 
48
+ block = Rack::Reactive::RequestBody.publish(engine, gateway_request)
53
49
  next [nil, [[:block, event]]] if block
54
50
 
55
- ret, res = stack.call(gateway_request.request)
56
-
57
- if event
58
- res ||= []
59
- res << [:monitor, event]
60
- end
61
-
62
- [ret, res]
51
+ stack.call(gateway_request.request)
63
52
  end
64
53
  end
65
54
 
66
55
  def watch_request_routed(gateway = Instrumentation.gateway)
67
56
  gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)|
68
- block = false
69
-
70
57
  event = nil
71
- scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
72
-
73
- AppSec::Reactive::Operation.new('sinatra.request.routed') do |op|
74
- Sinatra::Reactive::Routed.subscribe(op, scope.processor_context) do |result|
75
- if result.status == :match
76
- # TODO: should this hash be an Event instance instead?
77
- event = {
78
- waf_result: result,
79
- trace: scope.trace,
80
- span: scope.service_entry_span,
81
- request: gateway_request,
82
- actions: result.actions
83
- }
84
-
85
- # We want to keep the trace in case of security event
86
- scope.trace.keep! if scope.trace
87
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
88
- scope.processor_context.events << event
89
- end
58
+ context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
59
+ engine = AppSec::Reactive::Engine.new
60
+
61
+ Sinatra::Reactive::Routed.subscribe(engine, context) do |result|
62
+ if result.status == :match
63
+ # TODO: should this hash be an Event instance instead?
64
+ event = {
65
+ waf_result: result,
66
+ trace: context.trace,
67
+ span: context.span,
68
+ request: gateway_request,
69
+ actions: result.actions
70
+ }
71
+
72
+ # We want to keep the trace in case of security event
73
+ context.trace.keep! if context.trace
74
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
75
+ context.waf_runner.events << event
90
76
  end
91
-
92
- block = Sinatra::Reactive::Routed.publish(op, [gateway_request, gateway_route_params])
93
77
  end
94
78
 
79
+ block = Sinatra::Reactive::Routed.publish(engine, [gateway_request, gateway_route_params])
95
80
  next [nil, [[:block, event]]] if block
96
81
 
97
- ret, res = stack.call(gateway_request.request)
98
-
99
- if event
100
- res ||= []
101
- res << [:monitor, event]
102
- end
103
-
104
- [ret, res]
82
+ stack.call(gateway_request.request)
105
83
  end
106
84
  end
107
85
  end
@@ -54,7 +54,7 @@ module Datadog
54
54
  def dispatch!
55
55
  env = @request.env
56
56
 
57
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
57
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
58
58
 
59
59
  return super unless context
60
60
 
@@ -86,7 +86,7 @@ module Datadog
86
86
  def process_route(*)
87
87
  env = @request.env
88
88
 
89
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
89
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
90
90
 
91
91
  return super unless context
92
92
 
@@ -12,18 +12,18 @@ module Datadog
12
12
  ].freeze
13
13
  private_constant :ADDRESSES
14
14
 
15
- def self.publish(op, data)
15
+ def self.publish(engine, data)
16
16
  _request, route_params = data
17
17
 
18
18
  catch(:block) do
19
- op.publish('sinatra.request.route_params', route_params.params)
19
+ engine.publish('sinatra.request.route_params', route_params.params)
20
20
 
21
21
  nil
22
22
  end
23
23
  end
24
24
 
25
- def self.subscribe(op, waf_context)
26
- op.subscribe(*ADDRESSES) do |*values|
25
+ def self.subscribe(engine, context)
26
+ engine.subscribe(*ADDRESSES) do |*values|
27
27
  Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
28
28
  path_params = values[0]
29
29
 
@@ -32,7 +32,7 @@ module Datadog
32
32
  }
33
33
 
34
34
  waf_timeout = Datadog.configuration.appsec.waf_timeout
35
- result = waf_context.run(persistent_data, {}, waf_timeout)
35
+ result = context.run_waf(persistent_data, {}, waf_timeout)
36
36
 
37
37
  next if result.status != :match
38
38
 
@@ -137,16 +137,16 @@ module Datadog
137
137
  end
138
138
  # rubocop:enable Metrics/MethodLength
139
139
 
140
- def tag_and_keep!(scope, waf_result)
140
+ def tag_and_keep!(context, waf_result)
141
141
  # We want to keep the trace in case of security event
142
- scope.trace.keep! if scope.trace
142
+ context.trace.keep! if context.trace
143
143
 
144
- if scope.service_entry_span
145
- scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.include?('block')
146
- scope.service_entry_span.set_tag('appsec.event', 'true')
144
+ if context.span
145
+ context.span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request')
146
+ context.span.set_tag('appsec.event', 'true')
147
147
  end
148
148
 
149
- add_distributed_tags(scope.trace)
149
+ add_distributed_tags(context.trace)
150
150
  end
151
151
 
152
152
  private
@@ -3,8 +3,10 @@
3
3
  module Datadog
4
4
  module AppSec
5
5
  module Ext
6
+ RASP_SQLI = :sql_injection
6
7
  INTERRUPT = :datadog_appsec_interrupt
7
- SCOPE_KEY = 'datadog.appsec.scope'
8
+ CONTEXT_KEY = 'datadog.appsec.context'
9
+ ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context
8
10
 
9
11
  TAG_APPSEC_ENABLED = '_dd.appsec.enabled'
10
12
  TAG_APM_ENABLED = '_dd.apm.enabled'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../instrumentation/gateway'
4
- require_relative '../../reactive/operation'
4
+ require_relative '../../reactive/engine'
5
5
  require_relative '../reactive/set_user'
6
6
 
7
7
  module Datadog
@@ -19,42 +19,32 @@ module Datadog
19
19
 
20
20
  def watch_user_id(gateway = Instrumentation.gateway)
21
21
  gateway.watch('identity.set_user', :appsec) do |stack, user|
22
- block = false
23
22
  event = nil
24
- scope = Datadog::AppSec.active_scope
25
-
26
- AppSec::Reactive::Operation.new('identity.set_user') do |op|
27
- Monitor::Reactive::SetUser.subscribe(op, scope.processor_context) do |result|
28
- if result.status == :match
29
- # TODO: should this hash be an Event instance instead?
30
- event = {
31
- waf_result: result,
32
- trace: scope.trace,
33
- span: scope.service_entry_span,
34
- user: user,
35
- actions: result.actions
36
- }
37
-
38
- # We want to keep the trace in case of security event
39
- scope.trace.keep! if scope.trace
40
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
41
- scope.processor_context.events << event
42
- end
23
+ 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
43
41
  end
44
-
45
- block = Monitor::Reactive::SetUser.publish(op, user)
46
42
  end
47
43
 
48
- throw(Datadog::AppSec::Ext::INTERRUPT, [nil, [[:block, event]]]) if block
49
-
50
- ret, res = stack.call(user)
51
-
52
- if event
53
- res ||= []
54
- res << [:monitor, event]
55
- end
44
+ block = Monitor::Reactive::SetUser.publish(engine, user)
45
+ throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
56
46
 
57
- [ret, res]
47
+ stack.call(user)
58
48
  end
59
49
  end
60
50
  end
@@ -11,16 +11,16 @@ module Datadog
11
11
  ].freeze
12
12
  private_constant :ADDRESSES
13
13
 
14
- def self.publish(op, user)
14
+ def self.publish(engine, user)
15
15
  catch(:block) do
16
- op.publish('usr.id', user.id)
16
+ engine.publish('usr.id', user.id)
17
17
 
18
18
  nil
19
19
  end
20
20
  end
21
21
 
22
- def self.subscribe(op, waf_context)
23
- op.subscribe(*ADDRESSES) do |*values|
22
+ def self.subscribe(engine, context)
23
+ engine.subscribe(*ADDRESSES) do |*values|
24
24
  Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
25
25
 
26
26
  user_id = values[0]
@@ -30,7 +30,7 @@ module Datadog
30
30
  }
31
31
 
32
32
  waf_timeout = Datadog.configuration.appsec.waf_timeout
33
- result = waf_context.run(persistent_data, {}, waf_timeout)
33
+ result = context.run_waf(persistent_data, {}, waf_timeout)
34
34
 
35
35
  next if result.status != :match
36
36
 
@@ -19,7 +19,7 @@ module Datadog
19
19
  @events = []
20
20
  @run_mutex = Mutex.new
21
21
 
22
- @libddwaf_debug_tag = "libddwaf:#{WAF::VERSION::STRING}"
22
+ @libddwaf_debug_tag = "libddwaf:#{WAF::VERSION::STRING} method:ddwaf_run"
23
23
  end
24
24
 
25
25
  def run(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
@@ -79,7 +79,7 @@ module Datadog
79
79
  @context.run(persistent_data, ephemeral_data, timeout)
80
80
  rescue WAF::LibDDWAF::Error => e
81
81
  Datadog.logger.debug { "#{@libddwaf_debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
82
- @telemetry.report(e, description: 'libddwaf internal low-level error')
82
+ @telemetry.report(e, description: 'libddwaf-rb internal low-level error')
83
83
 
84
84
  [:err_internal, WAF::Result.new(:err_internal, [], 0.0, false, [], [])]
85
85
  end
@@ -74,9 +74,6 @@ module Datadog
74
74
  when Hash
75
75
  pass = ip_passlist[:pass]
76
76
  monitor = ip_passlist[:monitor]
77
- else
78
- pass = []
79
- monitor = []
80
77
  end
81
78
 
82
79
  exclusions = []
@@ -67,7 +67,6 @@ module Datadog
67
67
  data = []
68
68
  overrides = []
69
69
  exclusions = []
70
- actions = []
71
70
 
72
71
  repository.contents.each do |content|
73
72
  parsed_content = parse_content(content)
@@ -81,7 +80,6 @@ module Datadog
81
80
  overrides << parsed_content['rules_override'] if parsed_content['rules_override']
82
81
  exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
83
82
  custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
84
- actions.concat(parsed_content['actions']) if parsed_content['actions']
85
83
  end
86
84
  end
87
85
 
@@ -105,7 +103,7 @@ module Datadog
105
103
  telemetry: telemetry
106
104
  )
107
105
 
108
- Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
106
+ Datadog::AppSec.reconfigure(ruleset: ruleset, telemetry: telemetry)
109
107
  end
110
108
 
111
109
  [receiver]
@@ -31,19 +31,16 @@ module Datadog
31
31
  def negotiate(env, actions)
32
32
  # @type var configured_response: Response?
33
33
  configured_response = nil
34
- actions.each do |action|
34
+ actions.each do |type, parameters|
35
35
  # Need to use next to make steep happy :(
36
36
  # I rather use break to stop the execution
37
37
  next if configured_response
38
38
 
39
- action_configuration = AppSec::Processor::Actions.fetch_configuration(action)
40
- next unless action_configuration
41
-
42
- configured_response = case action_configuration['type']
39
+ configured_response = case type
43
40
  when 'block_request'
44
- block_response(env, action_configuration['parameters'])
41
+ block_response(env, parameters)
45
42
  when 'redirect_request'
46
- redirect_response(env, action_configuration['parameters'])
43
+ redirect_response(env, parameters)
47
44
  end
48
45
  end
49
46
 
@@ -90,7 +87,7 @@ module Datadog
90
87
  body << content(content_type)
91
88
 
92
89
  Response.new(
93
- status: options['status_code'] || 403,
90
+ status: options['status_code']&.to_i || 403,
94
91
  headers: { 'Content-Type' => content_type },
95
92
  body: body,
96
93
  )
@@ -100,15 +97,14 @@ module Datadog
100
97
  if options['location'] && !options['location'].empty?
101
98
  content_type = content_type(env)
102
99
 
103
- status = options['status_code'] >= 300 && options['status_code'] < 400 ? options['status_code'] : 303
104
-
105
100
  headers = {
106
101
  'Content-Type' => content_type,
107
102
  'Location' => options['location']
108
103
  }
109
104
 
105
+ status_code = options['status_code'].to_i
110
106
  Response.new(
111
- status: status,
107
+ status: (status_code >= 300 && status_code < 400 ? status_code : 303),
112
108
  headers: headers,
113
109
  body: [],
114
110
  )
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative 'appsec/configuration'
4
4
  require_relative 'appsec/extensions'
5
- require_relative 'appsec/scope'
5
+ require_relative 'appsec/context'
6
6
  require_relative 'appsec/ext'
7
7
  require_relative 'appsec/utils'
8
8
 
@@ -14,8 +14,8 @@ module Datadog
14
14
  Datadog.configuration.appsec.enabled
15
15
  end
16
16
 
17
- def active_scope
18
- Datadog::AppSec::Scope.active_scope
17
+ def active_context
18
+ Datadog::AppSec::Context.active
19
19
  end
20
20
 
21
21
  def processor
@@ -24,12 +24,12 @@ module Datadog
24
24
  appsec_component.processor if appsec_component
25
25
  end
26
26
 
27
- def reconfigure(ruleset:, actions:, telemetry:)
27
+ def reconfigure(ruleset:, telemetry:)
28
28
  appsec_component = components.appsec
29
29
 
30
30
  return unless appsec_component
31
31
 
32
- appsec_component.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
32
+ appsec_component.reconfigure(ruleset: ruleset, telemetry: telemetry)
33
33
  end
34
34
 
35
35
  def reconfigure_lock(&block)
@@ -56,6 +56,7 @@ end
56
56
  require_relative 'appsec/contrib/rack/integration'
57
57
  require_relative 'appsec/contrib/sinatra/integration'
58
58
  require_relative 'appsec/contrib/rails/integration'
59
+ require_relative 'appsec/contrib/active_record/integration'
59
60
  require_relative 'appsec/contrib/devise/integration'
60
61
  require_relative 'appsec/contrib/graphql/integration'
61
62
 
@@ -6,6 +6,9 @@
6
6
  require_relative '../datadog'
7
7
  require_relative 'tracing/contrib/auto_instrument'
8
8
 
9
+ # DI is not loaded on Ruby 2.5 and JRuby
10
+ Datadog::DI::Contrib.load_now_or_later if defined?(Datadog::DI::Contrib)
11
+
9
12
  Datadog::Profiling.start_if_enabled
10
13
 
11
14
  module Datadog
@@ -19,21 +19,49 @@ module Datadog
19
19
  # Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users
20
20
  # about it and pick a value based on the following priority: code > environment variable > defaults.
21
21
  class AgentSettingsResolver
22
- AgentSettings = Struct.new(
23
- :adapter,
24
- :ssl,
25
- :hostname,
26
- :port,
27
- :uds_path,
28
- :timeout_seconds,
29
- keyword_init: true
30
- ) do
31
- def initialize(*)
32
- super
22
+ # Immutable container for the resulting settings
23
+ class AgentSettings
24
+ attr_reader :adapter, :ssl, :hostname, :port, :uds_path, :timeout_seconds
25
+
26
+ def initialize(adapter: nil, ssl: nil, hostname: nil, port: nil, uds_path: nil, timeout_seconds: nil)
27
+ @adapter = adapter
28
+ @ssl = ssl
29
+ @hostname = hostname
30
+ @port = port
31
+ @uds_path = uds_path
32
+ @timeout_seconds = timeout_seconds
33
33
  freeze
34
34
  end
35
+
36
+ def url
37
+ case adapter
38
+ when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
39
+ hostname = self.hostname
40
+ hostname = "[#{hostname}]" if hostname =~ IPV6_REGEXP
41
+ "#{ssl ? 'https' : 'http'}://#{hostname}:#{port}/"
42
+ when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
43
+ "unix://#{uds_path}"
44
+ else
45
+ raise ArgumentError, "Unexpected adapter: #{adapter}"
46
+ end
47
+ end
48
+
49
+ def ==(other)
50
+ self.class == other.class &&
51
+ adapter == other.adapter &&
52
+ ssl == other.ssl &&
53
+ hostname == other.hostname &&
54
+ port == other.port &&
55
+ uds_path == other.uds_path &&
56
+ timeout_seconds == other.timeout_seconds
57
+ end
35
58
  end
36
59
 
60
+ # IPv6 regular expression from
61
+ # https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
62
+ # Does not match IPv4 addresses.
63
+ IPV6_REGEXP = /\A(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\z)/.freeze # rubocop:disable Layout/LineLength
64
+
37
65
  def self.call(settings, logger: Datadog.logger)
38
66
  new(settings, logger: logger).send(:call)
39
67
  end
@@ -13,6 +13,7 @@ require_relative '../remote/component'
13
13
  require_relative '../../tracing/component'
14
14
  require_relative '../../profiling/component'
15
15
  require_relative '../../appsec/component'
16
+ require_relative '../../di/component'
16
17
  require_relative '../crashtracking/component'
17
18
 
18
19
  module Datadog
@@ -83,6 +84,7 @@ module Datadog
83
84
  :telemetry,
84
85
  :tracer,
85
86
  :crashtracker,
87
+ :dynamic_instrumentation,
86
88
  :appsec
87
89
 
88
90
  def initialize(settings)
@@ -103,19 +105,22 @@ module Datadog
103
105
  @profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component(
104
106
  settings: settings,
105
107
  agent_settings: agent_settings,
106
- optional_tracer: @tracer
108
+ optional_tracer: @tracer,
109
+ logger: @logger,
107
110
  )
108
111
  @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
109
112
 
110
113
  @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
111
114
  @health_metrics = self.class.build_health_metrics(settings)
112
115
  @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
116
+ @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
117
+ @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
113
118
 
114
119
  self.class.configure_tracing(settings)
115
120
  end
116
121
 
117
122
  # Starts up components
118
- def startup!(settings)
123
+ def startup!(settings, old_state: nil)
119
124
  if settings.profiling.enabled
120
125
  if profiler
121
126
  profiler.start
@@ -126,6 +131,16 @@ module Datadog
126
131
  end
127
132
  end
128
133
 
134
+ if settings.remote.enabled && old_state&.[](:remote_started)
135
+ # The library was reconfigured and previously it already started
136
+ # the remote component (i.e., it received at least one request
137
+ # through the installed Rack middleware which started the remote).
138
+ # If the new configuration also has remote enabled, start the
139
+ # new remote right away.
140
+ # remote should always be not nil here but steep doesn't know this.
141
+ remote&.start
142
+ end
143
+
129
144
  Core::Diagnostics::EnvironmentLogger.collect_and_log!(@environment_logger_extra)
130
145
  end
131
146
 
@@ -136,6 +151,9 @@ module Datadog
136
151
  # Shutdown remote configuration
137
152
  remote.shutdown! if remote
138
153
 
154
+ # Shutdown DI after remote, since remote config triggers DI operations.
155
+ dynamic_instrumentation&.shutdown!
156
+
139
157
  # Decommission AppSec
140
158
  appsec.shutdown! if appsec
141
159