datadog 2.8.0 → 2.9.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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -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 +219 -122
  10. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  11. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  12. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  14. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  15. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  16. data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -54
  17. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  18. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  19. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  20. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  21. data/ext/libdatadog_api/crashtracker.c +3 -0
  22. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  23. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  24. data/lib/datadog/appsec/context.rb +54 -0
  25. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +7 -7
  26. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  27. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  28. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
  29. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
  30. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  31. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
  32. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
  33. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
  34. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
  35. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  36. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
  37. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
  38. data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
  40. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
  41. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
  42. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
  43. data/lib/datadog/appsec/event.rb +6 -6
  44. data/lib/datadog/appsec/ext.rb +3 -1
  45. data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
  47. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  48. data/lib/datadog/appsec.rb +3 -3
  49. data/lib/datadog/auto_instrument.rb +3 -0
  50. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  51. data/lib/datadog/core/configuration/components.rb +4 -2
  52. data/lib/datadog/core/configuration.rb +1 -1
  53. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  54. data/lib/datadog/core/crashtracking/component.rb +1 -3
  55. data/lib/datadog/core/telemetry/event.rb +87 -3
  56. data/lib/datadog/core/telemetry/logging.rb +2 -2
  57. data/lib/datadog/core/telemetry/metric.rb +22 -0
  58. data/lib/datadog/core/telemetry/worker.rb +33 -0
  59. data/lib/datadog/di/base.rb +115 -0
  60. data/lib/datadog/di/code_tracker.rb +7 -4
  61. data/lib/datadog/di/component.rb +17 -11
  62. data/lib/datadog/di/configuration/settings.rb +11 -1
  63. data/lib/datadog/di/contrib/railtie.rb +15 -0
  64. data/lib/datadog/di/contrib.rb +26 -0
  65. data/lib/datadog/di/error.rb +5 -0
  66. data/lib/datadog/di/instrumenter.rb +39 -18
  67. data/lib/datadog/di/{init.rb → preload.rb} +2 -4
  68. data/lib/datadog/di/probe_manager.rb +4 -4
  69. data/lib/datadog/di/probe_notification_builder.rb +16 -2
  70. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  71. data/lib/datadog/di/remote.rb +4 -4
  72. data/lib/datadog/di/transport.rb +2 -4
  73. data/lib/datadog/di.rb +5 -108
  74. data/lib/datadog/kit/appsec/events.rb +3 -3
  75. data/lib/datadog/kit/identity.rb +4 -4
  76. data/lib/datadog/profiling/component.rb +55 -53
  77. data/lib/datadog/profiling/http_transport.rb +1 -26
  78. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  79. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  80. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  81. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  82. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  83. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  84. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  85. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  86. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  87. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  88. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  89. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  90. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  91. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  92. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  93. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  94. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  95. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  96. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  97. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  98. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  99. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  100. data/lib/datadog/tracing/span.rb +12 -4
  101. data/lib/datadog/tracing/span_event.rb +123 -3
  102. data/lib/datadog/tracing/span_operation.rb +6 -0
  103. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  104. data/lib/datadog/version.rb +1 -1
  105. metadata +19 -10
  106. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  107. data/lib/datadog/appsec/scope.rb +0 -58
  108. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -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/request'
6
6
  require_relative '../reactive/request_body'
7
7
  require_relative '../reactive/response'
@@ -25,126 +25,94 @@ module Datadog
25
25
 
26
26
  def watch_request(gateway = Instrumentation.gateway)
27
27
  gateway.watch('rack.request', :appsec) do |stack, gateway_request|
28
- block = false
29
28
  event = nil
30
- scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
31
-
32
- AppSec::Reactive::Operation.new('rack.request') do |op|
33
- Rack::Reactive::Request.subscribe(op, scope.processor_context) do |result|
34
- if result.status == :match
35
- # TODO: should this hash be an Event instance instead?
36
- event = {
37
- waf_result: result,
38
- trace: scope.trace,
39
- span: scope.service_entry_span,
40
- request: gateway_request,
41
- actions: result.actions
42
- }
43
-
44
- # We want to keep the trace in case of security event
45
- scope.trace.keep! if scope.trace
46
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
47
- scope.processor_context.events << event
48
- end
29
+ context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
30
+ engine = AppSec::Reactive::Engine.new
31
+
32
+ Rack::Reactive::Request.subscribe(engine, 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: context.trace,
38
+ span: context.span,
39
+ request: gateway_request,
40
+ actions: result.actions
41
+ }
42
+
43
+ # We want to keep the trace in case of security event
44
+ context.trace.keep! if context.trace
45
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
46
+ context.waf_runner.events << event
49
47
  end
50
-
51
- block = Rack::Reactive::Request.publish(op, gateway_request)
52
48
  end
53
49
 
54
- next [nil, [[:block, event]]] if block
55
-
56
- ret, res = stack.call(gateway_request.request)
57
-
58
- if event
59
- res ||= []
60
- res << [:monitor, event]
61
- end
50
+ block = Rack::Reactive::Request.publish(engine, gateway_request)
51
+ throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
62
52
 
63
- [ret, res]
53
+ stack.call(gateway_request.request)
64
54
  end
65
55
  end
66
56
 
67
57
  def watch_response(gateway = Instrumentation.gateway)
68
58
  gateway.watch('rack.response', :appsec) do |stack, gateway_response|
69
- block = false
70
-
71
59
  event = nil
72
- scope = gateway_response.scope
73
-
74
- AppSec::Reactive::Operation.new('rack.response') do |op|
75
- Rack::Reactive::Response.subscribe(op, scope.processor_context) do |result|
76
- if result.status == :match
77
- # TODO: should this hash be an Event instance instead?
78
- event = {
79
- waf_result: result,
80
- trace: scope.trace,
81
- span: scope.service_entry_span,
82
- response: gateway_response,
83
- actions: result.actions
84
- }
85
-
86
- # We want to keep the trace in case of security event
87
- scope.trace.keep! if scope.trace
88
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
89
- scope.processor_context.events << event
90
- end
60
+ context = gateway_response.context
61
+ engine = AppSec::Reactive::Engine.new
62
+
63
+ Rack::Reactive::Response.subscribe(engine, context) do |result|
64
+ if result.status == :match
65
+ # TODO: should this hash be an Event instance instead?
66
+ event = {
67
+ waf_result: result,
68
+ trace: context.trace,
69
+ span: context.span,
70
+ response: gateway_response,
71
+ actions: result.actions
72
+ }
73
+
74
+ # We want to keep the trace in case of security event
75
+ context.trace.keep! if context.trace
76
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
77
+ context.waf_runner.events << event
91
78
  end
92
-
93
- block = Rack::Reactive::Response.publish(op, gateway_response)
94
79
  end
95
80
 
96
- next [nil, [[:block, event]]] if block
97
-
98
- ret, res = stack.call(gateway_response.response)
81
+ block = Rack::Reactive::Response.publish(engine, gateway_response)
82
+ throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
99
83
 
100
- if event
101
- res ||= []
102
- res << [:monitor, event]
103
- end
104
-
105
- [ret, res]
84
+ stack.call(gateway_response.response)
106
85
  end
107
86
  end
108
87
 
109
88
  def watch_request_body(gateway = Instrumentation.gateway)
110
89
  gateway.watch('rack.request.body', :appsec) do |stack, gateway_request|
111
- block = false
112
-
113
90
  event = nil
114
- scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
115
-
116
- AppSec::Reactive::Operation.new('rack.request.body') do |op|
117
- Rack::Reactive::RequestBody.subscribe(op, scope.processor_context) do |result|
118
- if result.status == :match
119
- # TODO: should this hash be an Event instance instead?
120
- event = {
121
- waf_result: result,
122
- trace: scope.trace,
123
- span: scope.service_entry_span,
124
- request: gateway_request,
125
- actions: result.actions
126
- }
127
-
128
- # We want to keep the trace in case of security event
129
- scope.trace.keep! if scope.trace
130
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
131
- scope.processor_context.events << event
132
- end
91
+ context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
92
+ engine = AppSec::Reactive::Engine.new
93
+
94
+ Rack::Reactive::RequestBody.subscribe(engine, context) do |result|
95
+ if result.status == :match
96
+ # TODO: should this hash be an Event instance instead?
97
+ event = {
98
+ waf_result: result,
99
+ trace: context.trace,
100
+ span: context.span,
101
+ request: gateway_request,
102
+ actions: result.actions
103
+ }
104
+
105
+ # We want to keep the trace in case of security event
106
+ context.trace.keep! if context.trace
107
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
108
+ context.waf_runner.events << event
133
109
  end
134
-
135
- block = Rack::Reactive::RequestBody.publish(op, gateway_request)
136
110
  end
137
111
 
138
- next [nil, [[:block, event]]] if block
139
-
140
- ret, res = stack.call(gateway_request.request)
141
-
142
- if event
143
- res ||= []
144
- res << [:monitor, event]
145
- end
112
+ block = Rack::Reactive::RequestBody.publish(engine, gateway_request)
113
+ throw(Datadog::AppSec::Ext::INTERRUPT, event[:actions]) if block
146
114
 
147
- [ret, res]
115
+ stack.call(gateway_request.request)
148
116
  end
149
117
  end
150
118
  end
@@ -17,21 +17,21 @@ module Datadog
17
17
  ].freeze
18
18
  private_constant :ADDRESSES
19
19
 
20
- def self.publish(op, gateway_request)
20
+ def self.publish(engine, gateway_request)
21
21
  catch(:block) do
22
- op.publish('request.query', gateway_request.query)
23
- op.publish('request.headers', gateway_request.headers)
24
- op.publish('request.uri.raw', gateway_request.fullpath)
25
- op.publish('request.cookies', gateway_request.cookies)
26
- op.publish('request.client_ip', gateway_request.client_ip)
27
- op.publish('server.request.method', gateway_request.method)
22
+ engine.publish('request.query', gateway_request.query)
23
+ engine.publish('request.headers', gateway_request.headers)
24
+ engine.publish('request.uri.raw', gateway_request.fullpath)
25
+ engine.publish('request.cookies', gateway_request.cookies)
26
+ engine.publish('request.client_ip', gateway_request.client_ip)
27
+ engine.publish('server.request.method', gateway_request.method)
28
28
 
29
29
  nil
30
30
  end
31
31
  end
32
32
 
33
- def self.subscribe(op, waf_context)
34
- op.subscribe(*ADDRESSES) do |*values|
33
+ def self.subscribe(engine, context)
34
+ engine.subscribe(*ADDRESSES) do |*values|
35
35
  Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
36
36
 
37
37
  headers = values[0]
@@ -53,7 +53,7 @@ module Datadog
53
53
  }
54
54
 
55
55
  waf_timeout = Datadog.configuration.appsec.waf_timeout
56
- result = waf_context.run(persistent_data, {}, waf_timeout)
56
+ result = context.run_waf(persistent_data, {}, waf_timeout)
57
57
 
58
58
  next if result.status != :match
59
59
 
@@ -12,17 +12,17 @@ module Datadog
12
12
  ].freeze
13
13
  private_constant :ADDRESSES
14
14
 
15
- def self.publish(op, gateway_request)
15
+ def self.publish(engine, gateway_request)
16
16
  catch(:block) do
17
17
  # params have been parsed from the request body
18
- op.publish('request.body', gateway_request.form_hash)
18
+ engine.publish('request.body', gateway_request.form_hash)
19
19
 
20
20
  nil
21
21
  end
22
22
  end
23
23
 
24
- def self.subscribe(op, waf_context)
25
- op.subscribe(*ADDRESSES) do |*values|
24
+ def self.subscribe(engine, context)
25
+ engine.subscribe(*ADDRESSES) do |*values|
26
26
  Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
27
27
  body = values[0]
28
28
 
@@ -31,7 +31,7 @@ module Datadog
31
31
  }
32
32
 
33
33
  waf_timeout = Datadog.configuration.appsec.waf_timeout
34
- result = waf_context.run(persistent_data, {}, waf_timeout)
34
+ result = context.run_waf(persistent_data, {}, waf_timeout)
35
35
 
36
36
  next if result.status != :match
37
37
 
@@ -13,17 +13,17 @@ module Datadog
13
13
  ].freeze
14
14
  private_constant :ADDRESSES
15
15
 
16
- def self.publish(op, gateway_response)
16
+ def self.publish(engine, gateway_response)
17
17
  catch(:block) do
18
- op.publish('response.status', gateway_response.status)
19
- op.publish('response.headers', gateway_response.headers)
18
+ engine.publish('response.status', gateway_response.status)
19
+ engine.publish('response.headers', gateway_response.headers)
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
 
29
29
  response_status = values[0]
@@ -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
 
@@ -17,25 +17,24 @@ module Datadog
17
17
  end
18
18
 
19
19
  def call(env)
20
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
20
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
21
21
 
22
22
  return @app.call(env) unless context
23
23
 
24
24
  # TODO: handle exceptions, except for @app.call
25
25
 
26
- request_return, request_response = Instrumentation.gateway.push(
27
- 'rack.request.body',
28
- Gateway::Request.new(env)
29
- ) do
30
- @app.call(env)
31
- end
26
+ http_response = nil
27
+ block_actions = catch(::Datadog::AppSec::Ext::INTERRUPT) do
28
+ http_response, = Instrumentation.gateway.push('rack.request.body', Gateway::Request.new(env)) do
29
+ @app.call(env)
30
+ end
32
31
 
33
- if request_response
34
- blocked_event = request_response.find { |action, _event| action == :block }
35
- request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
32
+ nil
36
33
  end
37
34
 
38
- request_return
35
+ return AppSec::Response.negotiate(env, block_actions).to_rack if block_actions
36
+
37
+ http_response
39
38
  end
40
39
  end
41
40
  end
@@ -36,7 +36,7 @@ module Datadog
36
36
  @rack_headers = {}
37
37
  end
38
38
 
39
- # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
39
+ # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
40
40
  def call(env)
41
41
  return @app.call(env) unless Datadog::AppSec.enabled?
42
42
 
@@ -45,19 +45,22 @@ module Datadog
45
45
 
46
46
  processor = nil
47
47
  ready = false
48
- scope = nil
48
+ ctx = nil
49
49
 
50
50
  # For a given request, keep using the first Rack stack scope for
51
51
  # nested apps. Don't set `context` local variable so that on popping
52
52
  # out of this nested stack we don't finalize the parent's context
53
- return @app.call(env) if active_scope(env)
53
+ return @app.call(env) if active_context(env)
54
54
 
55
55
  Datadog::AppSec.reconfigure_lock do
56
56
  processor = Datadog::AppSec.processor
57
57
 
58
58
  if !processor.nil? && processor.ready?
59
- scope = Datadog::AppSec::Scope.activate_scope(active_trace, active_span, processor)
60
- env[Datadog::AppSec::Ext::SCOPE_KEY] = scope
59
+ ctx = Datadog::AppSec::Context.activate(
60
+ Datadog::AppSec::Context.new(active_trace, active_span, processor)
61
+ )
62
+
63
+ env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx
61
64
  ready = true
62
65
  end
63
66
  end
@@ -66,66 +69,57 @@ module Datadog
66
69
 
67
70
  return @app.call(env) unless ready
68
71
 
69
- gateway_request = Gateway::Request.new(env)
72
+ add_appsec_tags(processor, ctx)
73
+ add_request_tags(ctx, env)
70
74
 
71
- add_appsec_tags(processor, scope)
72
- add_request_tags(scope, env)
75
+ http_response = nil
76
+ gateway_request = Gateway::Request.new(env)
77
+ gateway_response = nil
73
78
 
74
- request_return, request_response = catch(::Datadog::AppSec::Ext::INTERRUPT) do
75
- Instrumentation.gateway.push('rack.request', gateway_request) do
79
+ block_actions = catch(::Datadog::AppSec::Ext::INTERRUPT) do
80
+ http_response, = Instrumentation.gateway.push('rack.request', gateway_request) do
76
81
  @app.call(env)
77
82
  end
78
- end
79
83
 
80
- if request_response
81
- blocked_event = request_response.find { |action, _options| action == :block }
82
- request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
83
- end
84
+ gateway_response = Gateway::Response.new(
85
+ http_response[2], http_response[0], http_response[1], context: ctx
86
+ )
84
87
 
85
- gateway_response = Gateway::Response.new(
86
- request_return[2],
87
- request_return[0],
88
- request_return[1],
89
- scope: scope,
90
- )
88
+ Instrumentation.gateway.push('rack.response', gateway_response)
91
89
 
92
- _response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response)
90
+ nil
91
+ end
93
92
 
94
- result = scope.processor_context.extract_schema
93
+ http_response = AppSec::Response.negotiate(env, block_actions).to_rack if block_actions
95
94
 
96
- if result
97
- scope.processor_context.events << {
98
- trace: scope.trace,
99
- span: scope.service_entry_span,
95
+ if (result = ctx.waf_runner.extract_schema)
96
+ ctx.waf_runner.events << {
97
+ trace: ctx.trace,
98
+ span: ctx.span,
100
99
  waf_result: result,
101
100
  }
102
101
  end
103
102
 
104
- scope.processor_context.events.each do |e|
103
+ ctx.waf_runner.events.each do |e|
105
104
  e[:response] ||= gateway_response
106
105
  e[:request] ||= gateway_request
107
106
  end
108
107
 
109
- AppSec::Event.record(scope.service_entry_span, *scope.processor_context.events)
110
-
111
- if response_response
112
- blocked_event = response_response.find { |action, _options| action == :block }
113
- request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
114
- end
108
+ AppSec::Event.record(ctx.span, *ctx.waf_runner.events)
115
109
 
116
- request_return
110
+ http_response
117
111
  ensure
118
- if scope
119
- add_waf_runtime_tags(scope)
120
- Datadog::AppSec::Scope.deactivate_scope
112
+ if ctx
113
+ add_waf_runtime_tags(ctx)
114
+ Datadog::AppSec::Context.deactivate
121
115
  end
122
116
  end
123
- # rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength
117
+ # rubocop:enable Metrics/AbcSize,Metrics/MethodLength
124
118
 
125
119
  private
126
120
 
127
- def active_scope(env)
128
- env[Datadog::AppSec::Ext::SCOPE_KEY]
121
+ def active_context(env)
122
+ env[Datadog::AppSec::Ext::CONTEXT_KEY]
129
123
  end
130
124
 
131
125
  def active_trace
@@ -144,9 +138,9 @@ module Datadog
144
138
  Datadog::Tracing.active_span
145
139
  end
146
140
 
147
- def add_appsec_tags(processor, scope)
148
- span = scope.service_entry_span
149
- trace = scope.trace
141
+ def add_appsec_tags(processor, context)
142
+ span = context.span
143
+ trace = context.trace
150
144
 
151
145
  return unless trace && span
152
146
 
@@ -181,8 +175,8 @@ module Datadog
181
175
  end
182
176
  end
183
177
 
184
- def add_request_tags(scope, env)
185
- span = scope.service_entry_span
178
+ def add_request_tags(context, env)
179
+ span = context.span
186
180
 
187
181
  return unless span
188
182
 
@@ -204,9 +198,9 @@ module Datadog
204
198
  end
205
199
  end
206
200
 
207
- def add_waf_runtime_tags(scope)
208
- span = scope.service_entry_span
209
- context = scope.processor_context
201
+ def add_waf_runtime_tags(context)
202
+ span = context.span
203
+ context = context.waf_runner
210
204
 
211
205
  return unless span && context
212
206
 
@@ -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/action'
6
6
  require_relative '../../../event'
7
7
 
@@ -21,43 +21,32 @@ module Datadog
21
21
 
22
22
  def watch_request_action(gateway = Instrumentation.gateway)
23
23
  gateway.watch('rails.request.action', :appsec) do |stack, gateway_request|
24
- block = false
25
-
26
24
  event = nil
27
- scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY]
28
-
29
- AppSec::Reactive::Operation.new('rails.request.action') do |op|
30
- Rails::Reactive::Action.subscribe(op, scope.processor_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: scope.trace,
36
- span: scope.service_entry_span,
37
- request: gateway_request,
38
- actions: result.actions
39
- }
40
-
41
- # We want to keep the trace in case of security event
42
- scope.trace.keep! if scope.trace
43
- Datadog::AppSec::Event.tag_and_keep!(scope, result)
44
- scope.processor_context.events << event
45
- end
25
+ context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY]
26
+ engine = AppSec::Reactive::Engine.new
27
+
28
+ Rails::Reactive::Action.subscribe(engine, context) do |result|
29
+ if result.status == :match
30
+ # TODO: should this hash be an Event instance instead?
31
+ event = {
32
+ waf_result: result,
33
+ trace: context.trace,
34
+ span: context.span,
35
+ request: gateway_request,
36
+ actions: result.actions
37
+ }
38
+
39
+ # We want to keep the trace in case of security event
40
+ context.trace.keep! if context.trace
41
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
42
+ context.waf_runner.events << event
46
43
  end
47
-
48
- block = Rails::Reactive::Action.publish(op, gateway_request)
49
44
  end
50
45
 
46
+ block = Rails::Reactive::Action.publish(engine, gateway_request)
51
47
  next [nil, [[:block, event]]] if block
52
48
 
53
- ret, res = stack.call(gateway_request.request)
54
-
55
- if event
56
- res ||= []
57
- res << [:monitor, event]
58
- end
59
-
60
- [ret, res]
49
+ stack.call(gateway_request.request)
61
50
  end
62
51
  end
63
52
  end
@@ -73,7 +73,7 @@ module Datadog
73
73
  def process_action(*args)
74
74
  env = request.env
75
75
 
76
- context = env[Datadog::AppSec::Ext::SCOPE_KEY]
76
+ context = env[Datadog::AppSec::Ext::CONTEXT_KEY]
77
77
 
78
78
  return super unless context
79
79
 
@@ -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