diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index 1b31e5e6acd..3472a160514 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -8,10 +8,7 @@ class Context ActiveContextError = Class.new(StandardError) WAFMetrics = Struct.new(:timeouts, :duration_ns, :duration_ext_ns, keyword_init: true) - attr_reader :trace, :span, :waf_metrics - - # NOTE: This is an intermediate state and will be changed - attr_reader :waf_runner + attr_reader :trace, :span, :events, :waf_metrics class << self def activate(context) @@ -35,6 +32,7 @@ def active def initialize(trace, span, security_engine) @trace = trace @span = span + @events = [] @security_engine = security_engine @waf_runner = security_engine.new_runner @waf_metrics = WAFMetrics.new(timeouts: 0, duration_ns: 0, duration_ext_ns: 0) diff --git a/lib/datadog/appsec/contrib/active_record/instrumentation.rb b/lib/datadog/appsec/contrib/active_record/instrumentation.rb index 05d312890b4..aa0cfcf3236 100644 --- a/lib/datadog/appsec/contrib/active_record/instrumentation.rb +++ b/lib/datadog/appsec/contrib/active_record/instrumentation.rb @@ -35,7 +35,7 @@ def detect_sql_injection(sql, adapter_name) sql: sql, actions: result.actions } - context.waf_runner.events << event + context.events << event end end diff --git a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb index 025b6e10359..3991a3b6669 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -38,7 +38,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) } Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end block = GraphQL::Reactive::Multiplex.publish(engine, gateway_multiplex) diff --git a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb index 338bc3269f0..f3ef9e46699 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -43,7 +43,7 @@ def watch_request(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end @@ -74,7 +74,7 @@ def watch_response(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end @@ -105,7 +105,7 @@ def watch_request_body(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index fa2c74bbd75..52cfcefc420 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -93,19 +93,19 @@ def call(env) http_response = AppSec::Response.negotiate(env, block_actions).to_rack if block_actions if AppSec.api_security_enabled? - ctx.waf_runner.events << { + ctx.events << { trace: ctx.trace, span: ctx.span, waf_result: ctx.extract_schema, } end - ctx.waf_runner.events.each do |e| + ctx.events.each do |e| e[:response] ||= gateway_response e[:request] ||= gateway_request end - AppSec::Event.record(ctx.span, *ctx.waf_runner.events) + AppSec::Event.record(ctx.span, *ctx.events) http_response ensure diff --git a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb index 92e5f8e1caf..33228b4bf9b 100644 --- a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb @@ -39,7 +39,7 @@ def watch_request_action(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end diff --git a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb index 85da254dd1f..90f7e669e9b 100644 --- a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb @@ -41,7 +41,7 @@ def watch_request_dispatch(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end @@ -72,7 +72,7 @@ def watch_request_routed(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end diff --git a/lib/datadog/appsec/monitor/gateway/watcher.rb b/lib/datadog/appsec/monitor/gateway/watcher.rb index 51f949659ed..04595ffe52c 100644 --- a/lib/datadog/appsec/monitor/gateway/watcher.rb +++ b/lib/datadog/appsec/monitor/gateway/watcher.rb @@ -37,7 +37,7 @@ def watch_user_id(gateway = Instrumentation.gateway) # We want to keep the trace in case of security event context.trace.keep! if context.trace Datadog::AppSec::Event.tag_and_keep!(context, result) - context.waf_runner.events << event + context.events << event end end diff --git a/sig/datadog/appsec/context.rbs b/sig/datadog/appsec/context.rbs index 87fe78de497..e70c0d86373 100644 --- a/sig/datadog/appsec/context.rbs +++ b/sig/datadog/appsec/context.rbs @@ -17,6 +17,8 @@ module Datadog @span: Tracing::SpanOperation + @events: ::Array[untyped] + @security_engine: Processor @waf_runner: SecurityEngine::Runner @@ -31,6 +33,8 @@ module Datadog attr_reader span: Tracing::SpanOperation + attr_reader events: ::Array[untyped] + attr_reader waf_runner: SecurityEngine::Runner attr_reader waf_metrics: WAFMetrics diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index 5087aab4a74..a5e64b60ac6 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -88,7 +88,7 @@ 'server.request.headers.no_cookies' => { 'user-agent' => 'Nessus SOAP' } } - Array.new(3) { context.run_waf(persistent_data, {}, 1_000) } + Array.new(3) { context.run_waf(persistent_data, {}, 10_000) } end it 'returns a single match and rest is ok' do @@ -110,8 +110,8 @@ } [ - context.run_waf(persistent_data_1, {}, 1_000), - context.run_waf(persistent_data_2, {}, 1_000), + context.run_waf(persistent_data_1, {}, 10_000), + context.run_waf(persistent_data_2, {}, 10_000), ] end @@ -142,7 +142,7 @@ persistent_data = { 'server.request.headers.no_cookies' => { 'user-agent' => 'Nessus SOAP' } } - Array.new(3) { context.run_waf(persistent_data, {}, 1_000) } + Array.new(3) { context.run_waf(persistent_data, {}, 10_000) } end it 'returns metrics containing 0 timeouts and cumulative durations' do diff --git a/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb b/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb index d6b420f15c7..456cdde57a4 100644 --- a/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb @@ -97,10 +97,12 @@ end it 'adds an event to processor context if waf result is a match' do - expect(Datadog::AppSec.active_context).to receive(:run_rasp) - .and_return(instance_double(Datadog::AppSec::SecurityEngine::Result::Match, actions: {})) + result = Datadog::AppSec::SecurityEngine::Result::Match.new( + events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, durations_ext_ns: 0 + ) - expect(Datadog::AppSec.active_context.waf_runner.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result) + expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original User.where(name: 'Bob').to_a end diff --git a/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb b/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb index 165b51ff321..05c4ee97d21 100644 --- a/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb @@ -104,10 +104,12 @@ end it 'adds an event to processor context if waf result is a match' do - expect(Datadog::AppSec.active_context).to receive(:run_rasp) - .and_return(instance_double(Datadog::AppSec::SecurityEngine::Result::Match, actions: {})) + result = Datadog::AppSec::SecurityEngine::Result::Match.new( + events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, durations_ext_ns: 0 + ) - expect(Datadog::AppSec.active_context.waf_runner.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result) + expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original User.where(name: 'Bob').to_a end diff --git a/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb b/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb index f89f291dd74..91e54ed3139 100644 --- a/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb @@ -91,10 +91,12 @@ end it 'adds an event to processor context if waf result is a match' do - expect(Datadog::AppSec.active_context).to receive(:run_rasp) - .and_return(instance_double(Datadog::AppSec::SecurityEngine::Result::Match, actions: {})) + result = Datadog::AppSec::SecurityEngine::Result::Match.new( + events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, durations_ext_ns: 0 + ) - expect(Datadog::AppSec.active_context.waf_runner.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result) + expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original User.where(name: 'Bob').to_a end