From 3eae4aa100adb8d0a63f5599bdbdb325c5ec9b0c Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 11:46:22 +0100 Subject: [PATCH 01/11] Add AppSec::Context class --- lib/datadog/appsec/context.rb | 58 +++++++++++++++++ spec/datadog/appsec/context_spec.rb | 96 +++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 lib/datadog/appsec/context.rb create mode 100644 spec/datadog/appsec/context_spec.rb diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb new file mode 100644 index 00000000000..28a8605c427 --- /dev/null +++ b/lib/datadog/appsec/context.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Datadog + module AppSec + # Write desciption TODO + class Context + attr_reader :trace, :service_entry_span, :processor_context + + def initialize(trace, service_entry_span, processor_context) + @trace = trace + @service_entry_span = service_entry_span + @processor_context = processor_context + end + + def finalize + @processor_context.finalize + end + + class << self + def activate_scope(trace, service_entry_span, processor) + raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_scope + + context = processor.new_context + self.active_scope = new(trace, service_entry_span, context) + end + + def deactivate_scope + raise InactiveScopeError, 'no scope is active, nested scopes are not supported' unless active_scope + + scope = active_scope + + reset_active_scope + + scope.finalize + end + + def active_scope + Thread.current[:datadog_appsec_active_scope] + end + + private + + def active_scope=(scope) + raise ArgumentError, 'not a Datadog::AppSec::Scope' unless scope.instance_of?(Context) + + Thread.current[:datadog_appsec_active_scope] = scope + end + + def reset_active_scope + Thread.current[:datadog_appsec_active_scope] = nil + end + end + + class InactiveScopeError < StandardError; end + class ActiveScopeError < StandardError; end + end + end +end diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb new file mode 100644 index 00000000000..0161d0124ea --- /dev/null +++ b/spec/datadog/appsec/context_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'datadog/appsec/spec_helper' +require 'datadog/appsec/context' + +RSpec.describe Datadog::AppSec::Context do + let(:trace) { double } + let(:span) { double } + let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } + + let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } + let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } + + after do + described_class.send(:reset_active_scope) + processor.finalize + end + + describe '.activate_scope' do + context 'with no active scope' do + subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } + + it 'returns a new scope' do + expect(activate_scope).to be_a described_class + end + + it 'sets the active scope' do + expect { activate_scope }.to change { described_class.active_scope }.from(nil).to be_a described_class + end + end + + context 'with an active scope' do + before do + described_class.activate_scope(trace, span, processor) + end + + subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } + + it 'raises ActiveScopeError' do + expect { activate_scope }.to raise_error Datadog::AppSec::Context::ActiveScopeError + end + + it 'does not change the active scope' do + expect { activate_scope rescue nil }.to_not(change { described_class.active_scope }) + end + end + end + + describe '.deactivate_scope' do + context 'with no active scope' do + subject(:deactivate_scope) { described_class.deactivate_scope } + + it 'raises ActiveContextError' do + expect { deactivate_scope }.to raise_error Datadog::AppSec::Context::InactiveScopeError + end + + it 'does not change the active scope' do + expect { deactivate_scope rescue nil }.to_not(change { described_class.active_scope }) + end + end + + context 'with an active scope' do + let(:active_scope) { described_class.active_scope } + + subject(:deactivate_scope) { described_class.deactivate_scope } + + before do + allow(described_class).to receive(:new).and_call_original + + described_class.activate_scope(trace, span, processor) + + expect(active_scope).to receive(:finalize).and_call_original + end + + it 'unsets the active scope' do + expect { deactivate_scope }.to change { described_class.active_scope }.from(active_scope).to nil + end + end + end + + describe '.active_scope' do + subject(:active_scope) { described_class.active_scope } + + context 'with no active scope' do + it { is_expected.to be_nil } + end + + context 'with an active scope' do + before do + described_class.activate_scope(trace, span, processor) + end + + it { is_expected.to be_a described_class } + end + end +end From 57ca8badda072b5811c89d97c79bec698408f30e Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 11:52:34 +0100 Subject: [PATCH 02/11] Remove AppSec::Scope class and its tests --- lib/datadog/appsec/scope.rb | 58 ------------------- spec/datadog/appsec/scope_spec.rb | 96 ------------------------------- 2 files changed, 154 deletions(-) delete mode 100644 lib/datadog/appsec/scope.rb delete mode 100644 spec/datadog/appsec/scope_spec.rb diff --git a/lib/datadog/appsec/scope.rb b/lib/datadog/appsec/scope.rb deleted file mode 100644 index 5fa27bf78fc..00000000000 --- a/lib/datadog/appsec/scope.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -module Datadog - module AppSec - # Capture context essential to consistently call processor and report via traces - class Scope - attr_reader :trace, :service_entry_span, :processor_context - - def initialize(trace, service_entry_span, processor_context) - @trace = trace - @service_entry_span = service_entry_span - @processor_context = processor_context - end - - def finalize - @processor_context.finalize - end - - class << self - def activate_scope(trace, service_entry_span, processor) - raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_scope - - context = processor.new_context - self.active_scope = new(trace, service_entry_span, context) - end - - def deactivate_scope - raise InactiveScopeError, 'no scope is active, nested scopes are not supported' unless active_scope - - scope = active_scope - - reset_active_scope - - scope.finalize - end - - def active_scope - Thread.current[:datadog_appsec_active_scope] - end - - private - - def active_scope=(scope) - raise ArgumentError, 'not a Datadog::AppSec::Scope' unless scope.instance_of?(Scope) - - Thread.current[:datadog_appsec_active_scope] = scope - end - - def reset_active_scope - Thread.current[:datadog_appsec_active_scope] = nil - end - end - - class InactiveScopeError < StandardError; end - class ActiveScopeError < StandardError; end - end - end -end diff --git a/spec/datadog/appsec/scope_spec.rb b/spec/datadog/appsec/scope_spec.rb deleted file mode 100644 index 540e7fc3546..00000000000 --- a/spec/datadog/appsec/scope_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -# frozen_string_literal: true - -require 'datadog/appsec/spec_helper' -require 'datadog/appsec/scope' - -RSpec.describe Datadog::AppSec::Scope do - let(:trace) { double } - let(:span) { double } - let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } - - let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } - let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } - - after do - described_class.send(:reset_active_scope) - processor.finalize - end - - describe '.activate_scope' do - context 'with no active scope' do - subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } - - it 'returns a new scope' do - expect(activate_scope).to be_a described_class - end - - it 'sets the active scope' do - expect { activate_scope }.to change { described_class.active_scope }.from(nil).to be_a described_class - end - end - - context 'with an active scope' do - before do - described_class.activate_scope(trace, span, processor) - end - - subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } - - it 'raises ActiveScopeError' do - expect { activate_scope }.to raise_error Datadog::AppSec::Scope::ActiveScopeError - end - - it 'does not change the active scope' do - expect { activate_scope rescue nil }.to_not(change { described_class.active_scope }) - end - end - end - - describe '.deactivate_scope' do - context 'with no active scope' do - subject(:deactivate_scope) { described_class.deactivate_scope } - - it 'raises ActiveScopeError' do - expect { deactivate_scope }.to raise_error Datadog::AppSec::Scope::InactiveScopeError - end - - it 'does not change the active scope' do - expect { deactivate_scope rescue nil }.to_not(change { described_class.active_scope }) - end - end - - context 'with an active scope' do - let(:active_scope) { described_class.active_scope } - - subject(:deactivate_scope) { described_class.deactivate_scope } - - before do - allow(described_class).to receive(:new).and_call_original - - described_class.activate_scope(trace, span, processor) - - expect(active_scope).to receive(:finalize).and_call_original - end - - it 'unsets the active scope' do - expect { deactivate_scope }.to change { described_class.active_scope }.from(active_scope).to nil - end - end - end - - describe '.active_scope' do - subject(:active_scope) { described_class.active_scope } - - context 'with no active scope' do - it { is_expected.to be_nil } - end - - context 'with an active scope' do - before do - described_class.activate_scope(trace, span, processor) - end - - it { is_expected.to be_a described_class } - end - end -end From e900c0f84064c072f120bdbc8461f0c0e2bd06f3 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 12:03:06 +0100 Subject: [PATCH 03/11] Rename scope variables into context --- lib/datadog/appsec.rb | 4 +- .../contrib/active_record/instrumentation.rb | 14 +++--- .../devise/patcher/authenticatable_patch.rb | 12 ++--- .../patcher/registration_controller_patch.rb | 8 +-- .../appsec/contrib/graphql/gateway/watcher.rb | 14 +++--- .../appsec/contrib/rack/gateway/watcher.rb | 42 ++++++++-------- .../appsec/contrib/rack/request_middleware.rb | 46 ++++++++--------- .../appsec/contrib/rails/gateway/watcher.rb | 14 +++--- .../appsec/contrib/sinatra/gateway/watcher.rb | 28 +++++------ lib/datadog/appsec/event.rb | 12 ++--- lib/datadog/appsec/monitor/gateway/watcher.rb | 14 +++--- lib/datadog/kit/appsec/events.rb | 6 +-- lib/datadog/kit/identity.rb | 6 +-- spec/datadog/appsec/context_spec.rb | 9 ++-- .../active_record/mysql2_adapter_spec.rb | 4 +- .../active_record/postgresql_adapter_spec.rb | 4 +- .../active_record/sqlite3_adapter_spec.rb | 4 +- .../patcher/authenticatable_patch_spec.rb | 42 ++++++++-------- .../registration_controller_patch_spec.rb | 40 +++++++-------- .../contrib/rack/gateway/response_spec.rb | 4 +- .../contrib/rack/reactive/response_spec.rb | 6 +-- spec/datadog/appsec/event_spec.rb | 50 +++++++++---------- spec/datadog/kit/appsec/events_spec.rb | 18 +++---- spec/datadog/kit/identity_spec.rb | 10 ++-- 24 files changed, 204 insertions(+), 207 deletions(-) diff --git a/lib/datadog/appsec.rb b/lib/datadog/appsec.rb index 5f96dbdd5fa..3faed0980d0 100644 --- a/lib/datadog/appsec.rb +++ b/lib/datadog/appsec.rb @@ -2,7 +2,7 @@ require_relative 'appsec/configuration' require_relative 'appsec/extensions' -require_relative 'appsec/scope' +require_relative 'appsec/context' require_relative 'appsec/ext' require_relative 'appsec/utils' @@ -15,7 +15,7 @@ def enabled? end def active_scope - Datadog::AppSec::Scope.active_scope + Datadog::AppSec::Context.active_scope end def processor diff --git a/lib/datadog/appsec/contrib/active_record/instrumentation.rb b/lib/datadog/appsec/contrib/active_record/instrumentation.rb index 3b226a9aafb..1969e5df365 100644 --- a/lib/datadog/appsec/contrib/active_record/instrumentation.rb +++ b/lib/datadog/appsec/contrib/active_record/instrumentation.rb @@ -9,8 +9,8 @@ module Instrumentation module_function def detect_sql_injection(sql, adapter_name) - scope = AppSec.active_scope - return unless scope + context = AppSec.active_scope + return unless context # libddwaf expects db system to be lowercase, # in case of sqlite adapter, libddwaf expects 'sqlite' as db system @@ -23,19 +23,19 @@ def detect_sql_injection(sql, adapter_name) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = scope.processor_context.run({}, ephemeral_data, waf_timeout) + result = context.processor_context.run({}, ephemeral_data, waf_timeout) if result.status == :match - Datadog::AppSec::Event.tag_and_keep!(scope, result) + Datadog::AppSec::Event.tag_and_keep!(context, result) event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, sql: sql, actions: result.actions } - scope.processor_context.events << event + context.processor_context.events << event end end diff --git a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb index ecd5b186821..401fa44e66d 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb @@ -23,9 +23,9 @@ def validate(resource, &block) automated_track_user_events_mode = track_user_events_configuration.mode - appsec_scope = Datadog::AppSec.active_scope + appsec_context = Datadog::AppSec.active_scope - return result unless appsec_scope + return result unless appsec_context devise_resource = resource ? Resource.new(resource) : nil @@ -39,8 +39,8 @@ def validate(resource, &block) end Tracking.track_login_success( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: event_information.user_id, **event_information.to_h ) @@ -59,8 +59,8 @@ def validate(resource, &block) end Tracking.track_login_failure( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: event_information.user_id, user_exists: user_exists, **event_information.to_h diff --git a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb index 1b8fae31266..409a7606f71 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb @@ -20,8 +20,8 @@ def create automated_track_user_events_mode = track_user_events_configuration.mode - appsec_scope = Datadog::AppSec.active_scope - return super unless appsec_scope + appsec_context = Datadog::AppSec.active_scope + return super unless appsec_context super do |resource| if resource.persisted? @@ -36,8 +36,8 @@ def create end Tracking.track_signup( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: event_information.user_id, **event_information.to_h ) diff --git a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb index 7fae08aad72..b98d3de9581 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -24,21 +24,21 @@ def watch_multiplex(gateway = Instrumentation.gateway) gateway.watch('graphql.multiplex', :appsec) do |stack, gateway_multiplex| block = false event = nil - scope = AppSec::Scope.active_scope + context = AppSec::Context.active_scope engine = AppSec::Reactive::Engine.new - if scope - GraphQL::Reactive::Multiplex.subscribe(engine, scope.processor_context) do |result| + if context + GraphQL::Reactive::Multiplex.subscribe(engine, context.processor_context) do |result| event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, multiplex: gateway_multiplex, actions: result.actions } - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_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 b5c55a15ac9..30d3444bda4 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -26,24 +26,24 @@ def watch def watch_request(gateway = Instrumentation.gateway) gateway.watch('rack.request', :appsec) do |stack, gateway_request| event = nil - scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::Request.subscribe(engine, scope.processor_context) do |result| + Rack::Reactive::Request.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, request: gateway_request, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_context.events << event end end @@ -57,24 +57,24 @@ def watch_request(gateway = Instrumentation.gateway) def watch_response(gateway = Instrumentation.gateway) gateway.watch('rack.response', :appsec) do |stack, gateway_response| event = nil - scope = gateway_response.scope + context = gateway_response.scope engine = AppSec::Reactive::Engine.new - Rack::Reactive::Response.subscribe(engine, scope.processor_context) do |result| + Rack::Reactive::Response.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, response: gateway_response, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_context.events << event end end @@ -88,24 +88,24 @@ def watch_response(gateway = Instrumentation.gateway) def watch_request_body(gateway = Instrumentation.gateway) gateway.watch('rack.request.body', :appsec) do |stack, gateway_request| event = nil - scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::RequestBody.subscribe(engine, scope.processor_context) do |result| + Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, request: gateway_request, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_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 cbb232c00e3..7bcbf73c827 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -45,7 +45,7 @@ def call(env) processor = nil ready = false - scope = nil + ctx = nil # For a given request, keep using the first Rack stack scope for # nested apps. Don't set `context` local variable so that on popping @@ -56,8 +56,8 @@ def call(env) processor = Datadog::AppSec.processor if !processor.nil? && processor.ready? - scope = Datadog::AppSec::Scope.activate_scope(active_trace, active_span, processor) - env[Datadog::AppSec::Ext::SCOPE_KEY] = scope + ctx = Datadog::AppSec::Context.activate_scope(active_trace, active_span, processor) + env[Datadog::AppSec::Ext::SCOPE_KEY] = ctx ready = true end end @@ -68,8 +68,8 @@ def call(env) gateway_request = Gateway::Request.new(env) - add_appsec_tags(processor, scope) - add_request_tags(scope, env) + add_appsec_tags(processor, ctx) + add_request_tags(ctx, env) request_return, request_response = catch(::Datadog::AppSec::Ext::INTERRUPT) do Instrumentation.gateway.push('rack.request', gateway_request) do @@ -86,27 +86,27 @@ def call(env) request_return[2], request_return[0], request_return[1], - scope: scope, + scope: ctx, ) _response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response) - result = scope.processor_context.extract_schema + result = ctx.processor_context.extract_schema if result - scope.processor_context.events << { - trace: scope.trace, - span: scope.service_entry_span, + ctx.processor_context.events << { + trace: ctx.trace, + span: ctx.service_entry_span, waf_result: result, } end - scope.processor_context.events.each do |e| + ctx.processor_context.events.each do |e| e[:response] ||= gateway_response e[:request] ||= gateway_request end - AppSec::Event.record(scope.service_entry_span, *scope.processor_context.events) + AppSec::Event.record(ctx.service_entry_span, *ctx.processor_context.events) if response_response blocked_event = response_response.find { |action, _options| action == :block } @@ -115,9 +115,9 @@ def call(env) request_return ensure - if scope - add_waf_runtime_tags(scope) - Datadog::AppSec::Scope.deactivate_scope + if ctx + add_waf_runtime_tags(ctx) + Datadog::AppSec::Context.deactivate_scope end end # rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength @@ -144,9 +144,9 @@ def active_span Datadog::Tracing.active_span end - def add_appsec_tags(processor, scope) - span = scope.service_entry_span - trace = scope.trace + def add_appsec_tags(processor, context) + span = context.service_entry_span + trace = context.trace return unless trace && span @@ -181,8 +181,8 @@ def add_appsec_tags(processor, scope) end end - def add_request_tags(scope, env) - span = scope.service_entry_span + def add_request_tags(context, env) + span = context.service_entry_span return unless span @@ -204,9 +204,9 @@ def add_request_tags(scope, env) end end - def add_waf_runtime_tags(scope) - span = scope.service_entry_span - context = scope.processor_context + def add_waf_runtime_tags(context) + span = context.service_entry_span + context = context.processor_context return unless span && context diff --git a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb index 0a1bd7ea9f5..ba1105fe58a 100644 --- a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb @@ -22,24 +22,24 @@ def watch def watch_request_action(gateway = Instrumentation.gateway) gateway.watch('rails.request.action', :appsec) do |stack, gateway_request| event = nil - scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] engine = AppSec::Reactive::Engine.new - Rails::Reactive::Action.subscribe(engine, scope.processor_context) do |result| + Rails::Reactive::Action.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, request: gateway_request, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_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 6524fef0ada..5bd14e38792 100644 --- a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb @@ -24,24 +24,24 @@ def watch def watch_request_dispatch(gateway = Instrumentation.gateway) gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request| event = nil - scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::RequestBody.subscribe(engine, scope.processor_context) do |result| + Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, request: gateway_request, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_context.events << event end end @@ -55,24 +55,24 @@ def watch_request_dispatch(gateway = Instrumentation.gateway) def watch_request_routed(gateway = Instrumentation.gateway) gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)| event = nil - scope = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] engine = AppSec::Reactive::Engine.new - Sinatra::Reactive::Routed.subscribe(engine, scope.processor_context) do |result| + Sinatra::Reactive::Routed.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, request: gateway_request, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_context.events << event end end diff --git a/lib/datadog/appsec/event.rb b/lib/datadog/appsec/event.rb index d3537f30d8f..37ab9da4e8a 100644 --- a/lib/datadog/appsec/event.rb +++ b/lib/datadog/appsec/event.rb @@ -137,16 +137,16 @@ def build_service_entry_tags(event_group) end # rubocop:enable Metrics/MethodLength - def tag_and_keep!(scope, waf_result) + def tag_and_keep!(context, waf_result) # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace + context.trace.keep! if context.trace - if scope.service_entry_span - scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request') - scope.service_entry_span.set_tag('appsec.event', 'true') + if context.service_entry_span + context.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request') + context.service_entry_span.set_tag('appsec.event', 'true') end - add_distributed_tags(scope.trace) + add_distributed_tags(context.trace) end private diff --git a/lib/datadog/appsec/monitor/gateway/watcher.rb b/lib/datadog/appsec/monitor/gateway/watcher.rb index 3a17b7dc831..7f31052e1cb 100644 --- a/lib/datadog/appsec/monitor/gateway/watcher.rb +++ b/lib/datadog/appsec/monitor/gateway/watcher.rb @@ -20,24 +20,24 @@ def watch def watch_user_id(gateway = Instrumentation.gateway) gateway.watch('identity.set_user', :appsec) do |stack, user| event = nil - scope = Datadog::AppSec.active_scope + context = Datadog::AppSec.active_scope engine = AppSec::Reactive::Engine.new - Monitor::Reactive::SetUser.subscribe(engine, scope.processor_context) do |result| + Monitor::Reactive::SetUser.subscribe(engine, context.processor_context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { waf_result: result, - trace: scope.trace, - span: scope.service_entry_span, + trace: context.trace, + span: context.service_entry_span, user: user, actions: result.actions } # We want to keep the trace in case of security event - scope.trace.keep! if scope.trace - Datadog::AppSec::Event.tag_and_keep!(scope, result) - scope.processor_context.events << event + context.trace.keep! if context.trace + Datadog::AppSec::Event.tag_and_keep!(context, result) + context.processor_context.events << event end end diff --git a/lib/datadog/kit/appsec/events.rb b/lib/datadog/kit/appsec/events.rb index be0b0f049c1..1e7ed0406a9 100644 --- a/lib/datadog/kit/appsec/events.rb +++ b/lib/datadog/kit/appsec/events.rb @@ -136,9 +136,9 @@ def track(event, trace = nil, span = nil, **others) private def set_trace_and_span_context(method, trace = nil, span = nil) - if (appsec_scope = Datadog::AppSec.active_scope) - trace = appsec_scope.trace - span = appsec_scope.service_entry_span + if (appsec_context = Datadog::AppSec.active_scope) + trace = appsec_context.trace + span = appsec_context.service_entry_span end trace ||= Datadog::Tracing.active_trace diff --git a/lib/datadog/kit/identity.rb b/lib/datadog/kit/identity.rb index a9b122d80c4..8a9711fe703 100644 --- a/lib/datadog/kit/identity.rb +++ b/lib/datadog/kit/identity.rb @@ -78,9 +78,9 @@ def set_user( private def set_trace_and_span_context(method, trace = nil, span = nil) - if (appsec_scope = Datadog::AppSec.active_scope) - trace = appsec_scope.trace - span = appsec_scope.service_entry_span + if (appsec_context = Datadog::AppSec.active_scope) + trace = appsec_context.trace + span = appsec_context.service_entry_span end trace ||= Datadog::Tracing.active_trace diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index 0161d0124ea..637f63ad2eb 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -61,7 +61,6 @@ context 'with an active scope' do let(:active_scope) { described_class.active_scope } - subject(:deactivate_scope) { described_class.deactivate_scope } before do @@ -81,14 +80,12 @@ describe '.active_scope' do subject(:active_scope) { described_class.active_scope } - context 'with no active scope' do + context 'with no active context' do it { is_expected.to be_nil } end - context 'with an active scope' do - before do - described_class.activate_scope(trace, span, processor) - end + context 'with an active context' do + before { described_class.activate_scope(trace, span, processor) } it { is_expected.to be_a described_class } end 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 6c5777adc1f..60e9138d885 100644 --- a/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb @@ -52,7 +52,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Scope.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_scope(trace, span, processor) raise_on_rails_deprecation! end @@ -60,7 +60,7 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Scope.deactivate_scope + Datadog::AppSec::Context.deactivate_scope processor.finalize 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 5ebd8e0cacb..ee8249c72c6 100644 --- a/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb @@ -53,7 +53,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Scope.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_scope(trace, span, processor) raise_on_rails_deprecation! end @@ -61,7 +61,7 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Scope.deactivate_scope + Datadog::AppSec::Context.deactivate_scope processor.finalize 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 778fe952a30..346d18e1e3b 100644 --- a/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb @@ -49,7 +49,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Scope.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_scope(trace, span, processor) raise_on_rails_deprecation! end @@ -57,7 +57,7 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Scope.deactivate_scope + Datadog::AppSec::Context.deactivate_scope processor.finalize end diff --git a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb index 7985e8dde31..e0efba2c2d8 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb @@ -43,7 +43,7 @@ def initialize(id, email, username) if appsec_enabled allow(Datadog.configuration.appsec).to receive(:track_user_events).and_return(automated_track_user_events) - allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_scope) if track_user_events_enabled + allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_context) if track_user_events_enabled end end @@ -71,7 +71,7 @@ def initialize(id, email, username) let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } let(:mode) { 'safe' } - let(:appsec_scope) { nil } + let(:appsec_context) { nil } it 'do not tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to_not receive(:track_login_success) @@ -82,7 +82,7 @@ def initialize(id, email, username) context 'when logging in from Rememberable devise strategy' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_scope) { instance_double(Datadog::AppSec::Scope, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } let(:mock_klass) do Class.new do @@ -109,7 +109,7 @@ def initialize(result) context 'successful login' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_scope) { instance_double(Datadog::AppSec::Scope, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } context 'with resource ID' do context 'safe mode' do @@ -117,8 +117,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{} ) @@ -131,8 +131,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{ username: 'John', email: 'hello@gmail.com' } ) @@ -149,8 +149,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{} ) @@ -163,8 +163,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{ username: 'John', email: 'hello@gmail.com' } ) @@ -177,7 +177,7 @@ def initialize(result) context 'unsuccessful login' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_scope) { instance_double(Datadog::AppSec::Scope, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } context 'with resource' do context 'safe mode' do @@ -185,8 +185,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, user_exists: true, **{} @@ -200,8 +200,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, user_exists: true, **{ username: 'John', email: 'hello@gmail.com' } @@ -217,8 +217,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, user_exists: false, **{} @@ -232,8 +232,8 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, user_exists: false, **{} diff --git a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb index daeb24569cf..b404fe264c0 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb @@ -54,7 +54,7 @@ def try(value) if appsec_enabled expect(Datadog.configuration.appsec).to receive(:track_user_events).and_return(automated_track_user_events) - expect(Datadog::AppSec).to receive(:active_scope).and_return(appsec_scope) if track_user_events_enabled + expect(Datadog::AppSec).to receive(:active_scope).and_return(appsec_context) if track_user_events_enabled end end @@ -105,7 +105,7 @@ def try(value) let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } let(:mode) { 'safe' } - let(:appsec_scope) { nil } + let(:appsec_context) { nil } it 'do not tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to_not receive(:track_signup) @@ -127,7 +127,7 @@ def try(value) context 'with persisted resource' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_scope) { instance_double(Datadog::AppSec::Scope, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } context 'with resource ID' do let(:resource) { persited_resource } @@ -141,8 +141,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{} ) @@ -156,8 +156,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -172,8 +172,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{} ) @@ -186,8 +186,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: resource.id, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -208,8 +208,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{} ) @@ -223,8 +223,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -239,8 +239,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{} ) @@ -253,8 +253,8 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( - appsec_scope.trace, - appsec_scope.service_entry_span, + appsec_context.trace, + appsec_context.service_entry_span, user_id: nil, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -267,7 +267,7 @@ def try(value) context 'with non persisted resource' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_scope) { instance_double(Datadog::AppSec::Scope, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } let(:resource) { non_persisted_resource } context 'safe mode' do diff --git a/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb b/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb index dc87c31be9d..52455ff8afd 100644 --- a/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb +++ b/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb @@ -2,7 +2,7 @@ require 'datadog/appsec/spec_helper' require 'datadog/appsec/contrib/rack/gateway/response' -require 'datadog/appsec/scope' +require 'datadog/appsec/context' require 'rack' RSpec.describe Datadog::AppSec::Contrib::Rack::Gateway::Response do @@ -15,7 +15,7 @@ body, 200, headers, - scope: instance_double(Datadog::AppSec::Scope) + scope: instance_double(Datadog::AppSec::Context) ) end diff --git a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb index ca51117f5e1..84ecc4cf518 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'datadog/appsec/spec_helper' -require 'datadog/appsec/scope' +require 'datadog/appsec/context' require 'datadog/appsec/contrib/rack/gateway/response' require 'datadog/appsec/contrib/rack/reactive/response' require 'datadog/appsec/reactive/engine' @@ -10,7 +10,7 @@ RSpec.describe Datadog::AppSec::Contrib::Rack::Reactive::Response do let(:engine) { Datadog::AppSec::Reactive::Engine.new } let(:processor_context) { instance_double(Datadog::AppSec::Processor::Context) } - let(:scope) { instance_double(Datadog::AppSec::Scope, processor_context: processor_context) } + let(:context) { instance_double(Datadog::AppSec::Context, processor_context: processor_context) } let(:body) { ['Ok'] } let(:headers) { { 'content-type' => 'text/html', 'set-cookie' => 'foo' } } @@ -19,7 +19,7 @@ body, 200, headers, - scope: scope, + scope: context, ) end diff --git a/spec/datadog/appsec/event_spec.rb b/spec/datadog/appsec/event_spec.rb index f07415b4063..194381ea4e1 100644 --- a/spec/datadog/appsec/event_spec.rb +++ b/spec/datadog/appsec/event_spec.rb @@ -375,20 +375,20 @@ dbl end - let(:scope) do - scope_trace = nil - scope_span = nil + let(:context) do + context_trace = nil + context_span = nil trace_operation = Datadog::Tracing::TraceOperation.new trace_operation.measure('root') do |span, trace| - scope_trace = trace if with_trace - scope_span = span if with_span + context_trace = trace if with_trace + context_span = span if with_span end dbl = double - allow(dbl).to receive(:trace).and_return(scope_trace) - allow(dbl).to receive(:service_entry_span).and_return(scope_span) + allow(dbl).to receive(:trace).and_return(context_trace) + allow(dbl).to receive(:service_entry_span).and_return(context_span) dbl end @@ -397,15 +397,15 @@ # prevent rate limiter to bias tests Datadog::AppSec::RateLimiter.reset! - described_class.tag_and_keep!(scope, waf_result) + described_class.tag_and_keep!(context, waf_result) end context 'with no actions' do it 'does not add appsec.blocked tag to span' do - expect(scope.service_entry_span.send(:meta)).to_not include('appsec.blocked') - expect(scope.service_entry_span.send(:meta)['appsec.event']).to eq('true') - expect(scope.trace.send(:meta)['_dd.p.dm']).to eq('-5') - expect(scope.trace.send(:meta)['_dd.p.appsec']).to eq('1') + expect(context.service_entry_span.send(:meta)).to_not include('appsec.blocked') + expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') + expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end end @@ -415,10 +415,10 @@ end it 'adds appsec.blocked tag to span' do - expect(scope.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') - expect(scope.service_entry_span.send(:meta)['appsec.event']).to eq('true') - expect(scope.trace.send(:meta)['_dd.p.dm']).to eq('-5') - expect(scope.trace.send(:meta)['_dd.p.appsec']).to eq('1') + expect(context.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') + expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') + expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end end @@ -426,9 +426,9 @@ let(:with_span) { false } it 'does not add appsec span tags but still add distributed tags' do - expect(scope.service_entry_span).to be nil - expect(scope.trace.send(:meta)['_dd.p.dm']).to eq('-5') - expect(scope.trace.send(:meta)['_dd.p.appsec']).to eq('1') + expect(context.service_entry_span).to be nil + expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') + expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end end @@ -437,9 +437,9 @@ context 'with no actions' do it 'does not add distributed tags but still add appsec span tags' do - expect(scope.trace).to be nil - expect(scope.service_entry_span.send(:meta)['appsec.blocked']).to be nil - expect(scope.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.trace).to be nil + expect(context.service_entry_span.send(:meta)['appsec.blocked']).to be nil + expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') end end @@ -449,9 +449,9 @@ end it 'does not add distributed tags but still add appsec span tags' do - expect(scope.trace).to be nil - expect(scope.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') - expect(scope.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.trace).to be nil + expect(context.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') + expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') end end end diff --git a/spec/datadog/kit/appsec/events_spec.rb b/spec/datadog/kit/appsec/events_spec.rb index 5a296104cac..c95276b9d43 100644 --- a/spec/datadog/kit/appsec/events_spec.rb +++ b/spec/datadog/kit/appsec/events_spec.rb @@ -8,15 +8,15 @@ RSpec.describe Datadog::Kit::AppSec::Events do let(:trace_op) { Datadog::Tracing::TraceOperation.new } - shared_context 'uses AppSec scope' do - before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_scope) } + shared_context 'uses AppSec context' do + before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_context) } let(:appsec_span) { trace_op.build_span('root') } context 'when is present' do - let(:appsec_active_scope) do + let(:appsec_active_context) do processor = instance_double('Datadog::Appsec::Processor') - Datadog::AppSec::Scope.new(trace_op, appsec_span, processor) + Datadog::AppSec::Context.new(trace_op, appsec_span, processor) end it 'sets tags on AppSec scope' do @@ -26,7 +26,7 @@ end context 'when is not present' do - let(:appsec_active_scope) { nil } + let(:appsec_active_context) { nil } it 'sets tags on active_span' do trace_op.measure('root') do |span, _trace| @@ -87,7 +87,7 @@ expect(user_argument).to eql(user_argument_dup) end - it_behaves_like 'uses AppSec scope' do + it_behaves_like 'uses AppSec context' do let(:event_tag) { 'appsec.events.users.login.success.track' } subject(:event) { described_class.track_login_success(trace_op, user: { id: '42' }) } end @@ -143,7 +143,7 @@ end end - it_behaves_like 'uses AppSec scope' do + it_behaves_like 'uses AppSec context' do let(:event_tag) { 'appsec.events.users.login.failure.track' } subject(:event) { described_class.track_login_failure(trace_op, user_id: '42', user_exists: true) } end @@ -193,7 +193,7 @@ expect(user_argument).to eql(user_argument_dup) end - it_behaves_like 'uses AppSec scope' do + it_behaves_like 'uses AppSec context' do let(:event_tag) { 'appsec.events.users.signup.track' } subject(:event) { described_class.track_signup(trace_op, user: { id: '42' }, foo: 'bar') } end @@ -219,7 +219,7 @@ end end - it_behaves_like 'uses AppSec scope' do + it_behaves_like 'uses AppSec context' do let(:event_tag) { 'appsec.events.foo.track' } subject(:event) { described_class.track('foo', trace_op) } end diff --git a/spec/datadog/kit/identity_spec.rb b/spec/datadog/kit/identity_spec.rb index 1f276c30e3c..c3d9fb15858 100644 --- a/spec/datadog/kit/identity_spec.rb +++ b/spec/datadog/kit/identity_spec.rb @@ -5,7 +5,7 @@ require 'datadog/tracing/trace_operation' require 'datadog/kit/identity' -require 'datadog/appsec/scope' +require 'datadog/appsec/context' RSpec.describe Datadog::Kit::Identity do subject(:trace_op) { Datadog::Tracing::TraceOperation.new } @@ -212,16 +212,16 @@ end context 'appsec' do - let(:appsec_active_scope) { nil } - before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_scope) } + let(:appsec_active_context) { nil } + before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_context) } context 'when is enabled' do - let(:appsec_active_scope) do + let(:appsec_active_context) do processor = instance_double('Datadog::Appsec::Processor') trace = trace_op span = trace.build_span('root') - Datadog::AppSec::Scope.new(trace, span, processor) + Datadog::AppSec::Context.new(trace, span, processor) end before do From 71d8d7779463ecc45a366d93d95653f22cb0a9cd Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 12:43:03 +0100 Subject: [PATCH 04/11] Rename AppSec::Ext::SCOPE_KEY into CONTEXT_KEY --- lib/datadog/appsec/contrib/rack/gateway/watcher.rb | 4 ++-- lib/datadog/appsec/contrib/rack/request_body_middleware.rb | 2 +- lib/datadog/appsec/contrib/rack/request_middleware.rb | 4 ++-- lib/datadog/appsec/contrib/rails/gateway/watcher.rb | 2 +- lib/datadog/appsec/contrib/rails/patcher.rb | 2 +- lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb | 4 ++-- lib/datadog/appsec/contrib/sinatra/patcher.rb | 4 ++-- lib/datadog/appsec/ext.rb | 2 +- spec/datadog/appsec/contrib/rack/integration_test_spec.rb | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb index 30d3444bda4..d9c3ad49b20 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -26,7 +26,7 @@ def watch def watch_request(gateway = Instrumentation.gateway) gateway.watch('rack.request', :appsec) do |stack, gateway_request| event = nil - context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new Rack::Reactive::Request.subscribe(engine, context.processor_context) do |result| @@ -88,7 +88,7 @@ def watch_response(gateway = Instrumentation.gateway) def watch_request_body(gateway = Instrumentation.gateway) gateway.watch('rack.request.body', :appsec) do |stack, gateway_request| event = nil - context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| diff --git a/lib/datadog/appsec/contrib/rack/request_body_middleware.rb b/lib/datadog/appsec/contrib/rack/request_body_middleware.rb index 01a0b9d1fa3..6ba2f5dfa9a 100644 --- a/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_body_middleware.rb @@ -17,7 +17,7 @@ def initialize(app, opt = {}) end def call(env) - context = env[Datadog::AppSec::Ext::SCOPE_KEY] + context = env[Datadog::AppSec::Ext::CONTEXT_KEY] return @app.call(env) unless context diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index 7bcbf73c827..15fc50c28e8 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -57,7 +57,7 @@ def call(env) if !processor.nil? && processor.ready? ctx = Datadog::AppSec::Context.activate_scope(active_trace, active_span, processor) - env[Datadog::AppSec::Ext::SCOPE_KEY] = ctx + env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx ready = true end end @@ -125,7 +125,7 @@ def call(env) private def active_scope(env) - env[Datadog::AppSec::Ext::SCOPE_KEY] + env[Datadog::AppSec::Ext::CONTEXT_KEY] end def active_trace diff --git a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb index ba1105fe58a..87adb30a555 100644 --- a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb @@ -22,7 +22,7 @@ def watch def watch_request_action(gateway = Instrumentation.gateway) gateway.watch('rails.request.action', :appsec) do |stack, gateway_request| event = nil - context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new Rails::Reactive::Action.subscribe(engine, context.processor_context) do |result| diff --git a/lib/datadog/appsec/contrib/rails/patcher.rb b/lib/datadog/appsec/contrib/rails/patcher.rb index 9b88c9c8862..479f65355d8 100644 --- a/lib/datadog/appsec/contrib/rails/patcher.rb +++ b/lib/datadog/appsec/contrib/rails/patcher.rb @@ -73,7 +73,7 @@ module ProcessActionPatch def process_action(*args) env = request.env - context = env[Datadog::AppSec::Ext::SCOPE_KEY] + context = env[Datadog::AppSec::Ext::CONTEXT_KEY] return super unless context diff --git a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb index 5bd14e38792..3bf5837e2a2 100644 --- a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb @@ -24,7 +24,7 @@ def watch def watch_request_dispatch(gateway = Instrumentation.gateway) gateway.watch('sinatra.request.dispatch', :appsec) do |stack, gateway_request| event = nil - context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| @@ -55,7 +55,7 @@ def watch_request_dispatch(gateway = Instrumentation.gateway) def watch_request_routed(gateway = Instrumentation.gateway) gateway.watch('sinatra.request.routed', :appsec) do |stack, (gateway_request, gateway_route_params)| event = nil - context = gateway_request.env[Datadog::AppSec::Ext::SCOPE_KEY] + context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new Sinatra::Reactive::Routed.subscribe(engine, context.processor_context) do |result| diff --git a/lib/datadog/appsec/contrib/sinatra/patcher.rb b/lib/datadog/appsec/contrib/sinatra/patcher.rb index 33345f30079..be4b4a73107 100644 --- a/lib/datadog/appsec/contrib/sinatra/patcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/patcher.rb @@ -54,7 +54,7 @@ module DispatchPatch def dispatch! env = @request.env - context = env[Datadog::AppSec::Ext::SCOPE_KEY] + context = env[Datadog::AppSec::Ext::CONTEXT_KEY] return super unless context @@ -86,7 +86,7 @@ module RoutePatch def process_route(*) env = @request.env - context = env[Datadog::AppSec::Ext::SCOPE_KEY] + context = env[Datadog::AppSec::Ext::CONTEXT_KEY] return super unless context diff --git a/lib/datadog/appsec/ext.rb b/lib/datadog/appsec/ext.rb index 30c21b7d240..30e83d3fe4b 100644 --- a/lib/datadog/appsec/ext.rb +++ b/lib/datadog/appsec/ext.rb @@ -4,7 +4,7 @@ module Datadog module AppSec module Ext INTERRUPT = :datadog_appsec_interrupt - SCOPE_KEY = 'datadog.appsec.scope' + CONTEXT_KEY = 'datadog.appsec.context' TAG_APPSEC_ENABLED = '_dd.appsec.enabled' TAG_APM_ENABLED = '_dd.apm.enabled' diff --git a/spec/datadog/appsec/contrib/rack/integration_test_spec.rb b/spec/datadog/appsec/contrib/rack/integration_test_spec.rb index 325541ed0b1..207696f23b2 100644 --- a/spec/datadog/appsec/contrib/rack/integration_test_spec.rb +++ b/spec/datadog/appsec/contrib/rack/integration_test_spec.rb @@ -633,7 +633,7 @@ run( proc do |env| # When appsec is enabled we want to force the 404 to trigger a rule match - if env[Datadog::AppSec::Ext::SCOPE_KEY] + if env[Datadog::AppSec::Ext::CONTEXT_KEY] [404, { 'Content-Type' => 'text/html' }, ['NOT FOUND']] else [200, { 'Content-Type' => 'text/html' }, ['OK']] From 39389a236cac92bcd6ef80d174edacd55c87017d Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 15:34:17 +0100 Subject: [PATCH 05/11] Rename AppSec::Context methods to match the class --- lib/datadog/appsec/context.rb | 36 ++++++++-------- .../contrib/active_record/instrumentation.rb | 2 +- .../devise/patcher/authenticatable_patch.rb | 2 +- .../patcher/registration_controller_patch.rb | 2 +- .../appsec/contrib/graphql/gateway/watcher.rb | 2 +- .../appsec/contrib/rack/request_middleware.rb | 8 ++-- lib/datadog/appsec/ext.rb | 1 + lib/datadog/appsec/monitor/gateway/watcher.rb | 2 +- spec/datadog/appsec/context_spec.rb | 42 +++++++++---------- .../active_record/mysql2_adapter_spec.rb | 12 +++--- .../active_record/postgresql_adapter_spec.rb | 12 +++--- .../active_record/sqlite3_adapter_spec.rb | 12 +++--- .../patcher/authenticatable_patch_spec.rb | 2 +- .../registration_controller_patch_spec.rb | 2 +- 14 files changed, 69 insertions(+), 68 deletions(-) diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index 28a8605c427..4f23cb8326b 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -4,6 +4,9 @@ module Datadog module AppSec # Write desciption TODO class Context + InactiveScopeError = Class.new(StandardError) + ActiveScopeError = Class.new(StandardError) + attr_reader :trace, :service_entry_span, :processor_context def initialize(trace, service_entry_span, processor_context) @@ -17,42 +20,39 @@ def finalize end class << self - def activate_scope(trace, service_entry_span, processor) - raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_scope + def activate_context(trace, service_entry_span, processor) + raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_context context = processor.new_context - self.active_scope = new(trace, service_entry_span, context) + self.active_context = new(trace, service_entry_span, context) end - def deactivate_scope - raise InactiveScopeError, 'no scope is active, nested scopes are not supported' unless active_scope + def deactivate_context + raise InactiveScopeError, 'no context is active, nested contexts are not supported' unless active_context - scope = active_scope + context = active_context - reset_active_scope + reset_active_context - scope.finalize + context.finalize end - def active_scope - Thread.current[:datadog_appsec_active_scope] + def active_context + Thread.current[Ext::ACTIVE_CONTEXT_KEY] end private - def active_scope=(scope) - raise ArgumentError, 'not a Datadog::AppSec::Scope' unless scope.instance_of?(Context) + def active_context=(context) + raise ArgumentError, 'not a Datadog::AppSec::Context' unless context.instance_of?(Context) - Thread.current[:datadog_appsec_active_scope] = scope + Thread.current[Ext::ACTIVE_CONTEXT_KEY] = context end - def reset_active_scope - Thread.current[:datadog_appsec_active_scope] = nil + def reset_active_context + Thread.current[Ext::ACTIVE_CONTEXT_KEY] = nil end end - - class InactiveScopeError < StandardError; end - class ActiveScopeError < StandardError; end end end end diff --git a/lib/datadog/appsec/contrib/active_record/instrumentation.rb b/lib/datadog/appsec/contrib/active_record/instrumentation.rb index 1969e5df365..f8c261bc354 100644 --- a/lib/datadog/appsec/contrib/active_record/instrumentation.rb +++ b/lib/datadog/appsec/contrib/active_record/instrumentation.rb @@ -9,7 +9,7 @@ module Instrumentation module_function def detect_sql_injection(sql, adapter_name) - context = AppSec.active_scope + context = AppSec.active_context return unless context # libddwaf expects db system to be lowercase, diff --git a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb index 401fa44e66d..b01a59c6e10 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb @@ -23,7 +23,7 @@ def validate(resource, &block) automated_track_user_events_mode = track_user_events_configuration.mode - appsec_context = Datadog::AppSec.active_scope + appsec_context = Datadog::AppSec.active_context return result unless appsec_context diff --git a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb index 409a7606f71..35803d3438d 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb @@ -20,7 +20,7 @@ def create automated_track_user_events_mode = track_user_events_configuration.mode - appsec_context = Datadog::AppSec.active_scope + appsec_context = Datadog::AppSec.active_context return super unless appsec_context super do |resource| diff --git a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb index b98d3de9581..aeefe9df4d5 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -24,7 +24,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) gateway.watch('graphql.multiplex', :appsec) do |stack, gateway_multiplex| block = false event = nil - context = AppSec::Context.active_scope + context = AppSec::Context.active_context engine = AppSec::Reactive::Engine.new if context diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index 15fc50c28e8..f1c11bb2d5f 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -50,13 +50,13 @@ def call(env) # For a given request, keep using the first Rack stack scope for # nested apps. Don't set `context` local variable so that on popping # out of this nested stack we don't finalize the parent's context - return @app.call(env) if active_scope(env) + return @app.call(env) if active_context(env) Datadog::AppSec.reconfigure_lock do processor = Datadog::AppSec.processor if !processor.nil? && processor.ready? - ctx = Datadog::AppSec::Context.activate_scope(active_trace, active_span, processor) + ctx = Datadog::AppSec::Context.activate_context(active_trace, active_span, processor) env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx ready = true end @@ -117,14 +117,14 @@ def call(env) ensure if ctx add_waf_runtime_tags(ctx) - Datadog::AppSec::Context.deactivate_scope + Datadog::AppSec::Context.deactivate_context end end # rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength private - def active_scope(env) + def active_context(env) env[Datadog::AppSec::Ext::CONTEXT_KEY] end diff --git a/lib/datadog/appsec/ext.rb b/lib/datadog/appsec/ext.rb index 30e83d3fe4b..a801a394546 100644 --- a/lib/datadog/appsec/ext.rb +++ b/lib/datadog/appsec/ext.rb @@ -5,6 +5,7 @@ module AppSec module Ext INTERRUPT = :datadog_appsec_interrupt CONTEXT_KEY = 'datadog.appsec.context' + ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context TAG_APPSEC_ENABLED = '_dd.appsec.enabled' TAG_APM_ENABLED = '_dd.apm.enabled' diff --git a/lib/datadog/appsec/monitor/gateway/watcher.rb b/lib/datadog/appsec/monitor/gateway/watcher.rb index 7f31052e1cb..014abcfffb7 100644 --- a/lib/datadog/appsec/monitor/gateway/watcher.rb +++ b/lib/datadog/appsec/monitor/gateway/watcher.rb @@ -20,7 +20,7 @@ def watch def watch_user_id(gateway = Instrumentation.gateway) gateway.watch('identity.set_user', :appsec) do |stack, user| event = nil - context = Datadog::AppSec.active_scope + context = Datadog::AppSec.active_context engine = AppSec::Reactive::Engine.new Monitor::Reactive::SetUser.subscribe(engine, context.processor_context) do |result| diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index 637f63ad2eb..dcf3508cd4d 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -12,80 +12,80 @@ let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } after do - described_class.send(:reset_active_scope) + described_class.send(:reset_active_context) processor.finalize end - describe '.activate_scope' do + describe '.activate_context' do context 'with no active scope' do - subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } + subject(:activate_context) { described_class.activate_context(trace, span, processor) } it 'returns a new scope' do - expect(activate_scope).to be_a described_class + expect(activate_context).to be_a described_class end it 'sets the active scope' do - expect { activate_scope }.to change { described_class.active_scope }.from(nil).to be_a described_class + expect { activate_context }.to change { described_class.active_context }.from(nil).to be_a described_class end end context 'with an active scope' do before do - described_class.activate_scope(trace, span, processor) + described_class.activate_context(trace, span, processor) end - subject(:activate_scope) { described_class.activate_scope(trace, span, processor) } + subject(:activate_context) { described_class.activate_context(trace, span, processor) } it 'raises ActiveScopeError' do - expect { activate_scope }.to raise_error Datadog::AppSec::Context::ActiveScopeError + expect { activate_context }.to raise_error Datadog::AppSec::Context::ActiveScopeError end it 'does not change the active scope' do - expect { activate_scope rescue nil }.to_not(change { described_class.active_scope }) + expect { activate_context rescue nil }.to_not(change { described_class.active_context }) end end end - describe '.deactivate_scope' do + describe '.deactivate_context' do context 'with no active scope' do - subject(:deactivate_scope) { described_class.deactivate_scope } + subject(:deactivate_context) { described_class.deactivate_context } it 'raises ActiveContextError' do - expect { deactivate_scope }.to raise_error Datadog::AppSec::Context::InactiveScopeError + expect { deactivate_context }.to raise_error Datadog::AppSec::Context::InactiveScopeError end it 'does not change the active scope' do - expect { deactivate_scope rescue nil }.to_not(change { described_class.active_scope }) + expect { deactivate_context rescue nil }.to_not(change { described_class.active_context }) end end context 'with an active scope' do - let(:active_scope) { described_class.active_scope } - subject(:deactivate_scope) { described_class.deactivate_scope } + let(:active_context) { described_class.active_context } + subject(:deactivate_context) { described_class.deactivate_context } before do allow(described_class).to receive(:new).and_call_original - described_class.activate_scope(trace, span, processor) + described_class.activate_context(trace, span, processor) - expect(active_scope).to receive(:finalize).and_call_original + expect(active_context).to receive(:finalize).and_call_original end it 'unsets the active scope' do - expect { deactivate_scope }.to change { described_class.active_scope }.from(active_scope).to nil + expect { deactivate_context }.to change { described_class.active_context }.from(active_context).to nil end end end - describe '.active_scope' do - subject(:active_scope) { described_class.active_scope } + describe '.active_context' do + subject(:active_context) { described_class.active_context } context 'with no active context' do it { is_expected.to be_nil } end context 'with an active context' do - before { described_class.activate_scope(trace, span, processor) } + before { described_class.activate_context(trace, span, processor) } it { is_expected.to be_a described_class } end 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 60e9138d885..b43f7b15dc0 100644 --- a/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb @@ -52,7 +52,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_context(trace, span, processor) raise_on_rails_deprecation! end @@ -60,12 +60,12 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_scope + Datadog::AppSec::Context.deactivate_context processor.finalize end it 'calls waf with correct arguments when querying using .where' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -80,7 +80,7 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -95,11 +95,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_scope.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.processor_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 ee8249c72c6..88bf4ed57fa 100644 --- a/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb @@ -53,7 +53,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_context(trace, span, processor) raise_on_rails_deprecation! end @@ -61,7 +61,7 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_scope + Datadog::AppSec::Context.deactivate_context processor.finalize end @@ -72,7 +72,7 @@ 'SELECT "users".* FROM "users" WHERE "users"."name" = $1' end - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -87,7 +87,7 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -102,11 +102,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_scope.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.processor_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 346d18e1e3b..9be5d7ebfad 100644 --- a/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb @@ -49,7 +49,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_scope(trace, span, processor) + Datadog::AppSec::Context.activate_context(trace, span, processor) raise_on_rails_deprecation! end @@ -57,12 +57,12 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_scope + Datadog::AppSec::Context.deactivate_context processor.finalize end it 'calls waf with correct arguments when querying using .where' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -77,7 +77,7 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).with( {}, { @@ -92,11 +92,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_scope.processor_context).to( + expect(Datadog::AppSec.active_context.processor_context).to( receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_scope.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.processor_context.events).to receive(:<<).and_call_original User.where(name: 'Bob').to_a end diff --git a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb index e0efba2c2d8..113c7570570 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb @@ -43,7 +43,7 @@ def initialize(id, email, username) if appsec_enabled allow(Datadog.configuration.appsec).to receive(:track_user_events).and_return(automated_track_user_events) - allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_context) if track_user_events_enabled + allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_context) if track_user_events_enabled end end diff --git a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb index b404fe264c0..a0bf30aaf17 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb @@ -54,7 +54,7 @@ def try(value) if appsec_enabled expect(Datadog.configuration.appsec).to receive(:track_user_events).and_return(automated_track_user_events) - expect(Datadog::AppSec).to receive(:active_scope).and_return(appsec_context) if track_user_events_enabled + expect(Datadog::AppSec).to receive(:active_context).and_return(appsec_context) if track_user_events_enabled end end From 2fba794bc5de949dab664a2bce1d5762e3eadbf6 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Thu, 9 Jan 2025 15:46:23 +0100 Subject: [PATCH 06/11] Rename use of AppSec::Context scope into context --- lib/datadog/appsec.rb | 4 ++-- lib/datadog/appsec/context.rb | 2 +- .../appsec/contrib/rack/gateway/response.rb | 6 +++--- .../appsec/contrib/rack/gateway/watcher.rb | 2 +- .../appsec/contrib/rack/request_middleware.rb | 2 +- lib/datadog/kit/appsec/events.rb | 2 +- lib/datadog/kit/identity.rb | 4 ++-- spec/datadog/appsec/context_spec.rb | 18 +++++++++--------- .../patcher/authenticatable_patch_spec.rb | 2 +- .../registration_controller_patch_spec.rb | 2 +- .../contrib/rack/gateway/response_spec.rb | 2 +- .../contrib/rack/reactive/response_spec.rb | 2 +- spec/datadog/kit/appsec/events_spec.rb | 4 ++-- spec/datadog/kit/identity_spec.rb | 2 +- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/datadog/appsec.rb b/lib/datadog/appsec.rb index 3faed0980d0..a95e8e30253 100644 --- a/lib/datadog/appsec.rb +++ b/lib/datadog/appsec.rb @@ -14,8 +14,8 @@ def enabled? Datadog.configuration.appsec.enabled end - def active_scope - Datadog::AppSec::Context.active_scope + def active_context + Datadog::AppSec::Context.active_context end def processor diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index 4f23cb8326b..881bc5f6a99 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -21,7 +21,7 @@ def finalize class << self def activate_context(trace, service_entry_span, processor) - raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_context + raise ActiveScopeError, 'another context is active, nested contexts are not supported' if active_context context = processor.new_context self.active_context = new(trace, service_entry_span, context) diff --git a/lib/datadog/appsec/contrib/rack/gateway/response.rb b/lib/datadog/appsec/contrib/rack/gateway/response.rb index 32b311bd919..a1969aa7e01 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/response.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/response.rb @@ -9,14 +9,14 @@ module Rack module Gateway # Gateway Response argument. class Response < Instrumentation::Gateway::Argument - attr_reader :body, :status, :headers, :scope + attr_reader :body, :status, :headers, :context - def initialize(body, status, headers, scope:) + def initialize(body, status, headers, context:) super() @body = body @status = status @headers = headers.each_with_object({}) { |(k, v), h| h[k.downcase] = v } - @scope = scope + @context = context end def response diff --git a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb index d9c3ad49b20..d32b13a4fc0 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -57,7 +57,7 @@ def watch_request(gateway = Instrumentation.gateway) def watch_response(gateway = Instrumentation.gateway) gateway.watch('rack.response', :appsec) do |stack, gateway_response| event = nil - context = gateway_response.scope + context = gateway_response.context engine = AppSec::Reactive::Engine.new Rack::Reactive::Response.subscribe(engine, context.processor_context) do |result| diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index f1c11bb2d5f..f5763190a92 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -86,7 +86,7 @@ def call(env) request_return[2], request_return[0], request_return[1], - scope: ctx, + context: ctx, ) _response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response) diff --git a/lib/datadog/kit/appsec/events.rb b/lib/datadog/kit/appsec/events.rb index 1e7ed0406a9..3b5c9717110 100644 --- a/lib/datadog/kit/appsec/events.rb +++ b/lib/datadog/kit/appsec/events.rb @@ -136,7 +136,7 @@ def track(event, trace = nil, span = nil, **others) private def set_trace_and_span_context(method, trace = nil, span = nil) - if (appsec_context = Datadog::AppSec.active_scope) + if (appsec_context = Datadog::AppSec.active_context) trace = appsec_context.trace span = appsec_context.service_entry_span end diff --git a/lib/datadog/kit/identity.rb b/lib/datadog/kit/identity.rb index 8a9711fe703..09de6392ead 100644 --- a/lib/datadog/kit/identity.rb +++ b/lib/datadog/kit/identity.rb @@ -66,7 +66,7 @@ def set_user( active_span.set_tag("usr.#{k}", v) unless v.nil? end - if Datadog::AppSec.active_scope + if Datadog::AppSec.active_context user = ::Datadog::AppSec::Instrumentation::Gateway::User.new(id) ::Datadog::AppSec::Instrumentation.gateway.push('identity.set_user', user) end @@ -78,7 +78,7 @@ def set_user( private def set_trace_and_span_context(method, trace = nil, span = nil) - if (appsec_context = Datadog::AppSec.active_scope) + if (appsec_context = Datadog::AppSec.active_context) trace = appsec_context.trace span = appsec_context.service_entry_span end diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index dcf3508cd4d..2634d6a69dc 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -17,19 +17,19 @@ end describe '.activate_context' do - context 'with no active scope' do + context 'with no active context' do subject(:activate_context) { described_class.activate_context(trace, span, processor) } - it 'returns a new scope' do + it 'returns a new context' do expect(activate_context).to be_a described_class end - it 'sets the active scope' do + it 'sets the active context' do expect { activate_context }.to change { described_class.active_context }.from(nil).to be_a described_class end end - context 'with an active scope' do + context 'with an active context' do before do described_class.activate_context(trace, span, processor) end @@ -40,26 +40,26 @@ expect { activate_context }.to raise_error Datadog::AppSec::Context::ActiveScopeError end - it 'does not change the active scope' do + it 'does not change the active context' do expect { activate_context rescue nil }.to_not(change { described_class.active_context }) end end end describe '.deactivate_context' do - context 'with no active scope' do + context 'with no active context' do subject(:deactivate_context) { described_class.deactivate_context } it 'raises ActiveContextError' do expect { deactivate_context }.to raise_error Datadog::AppSec::Context::InactiveScopeError end - it 'does not change the active scope' do + it 'does not change the active context' do expect { deactivate_context rescue nil }.to_not(change { described_class.active_context }) end end - context 'with an active scope' do + context 'with an active context' do let(:active_context) { described_class.active_context } subject(:deactivate_context) { described_class.deactivate_context } @@ -71,7 +71,7 @@ expect(active_context).to receive(:finalize).and_call_original end - it 'unsets the active scope' do + it 'unsets the active context' do expect { deactivate_context }.to change { described_class.active_context }.from(active_context).to nil end end diff --git a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb index 113c7570570..2f763049475 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb @@ -67,7 +67,7 @@ def initialize(id, email, username) end end - context 'AppSec scope is nil' do + context 'AppSec context is nil' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } let(:mode) { 'safe' } diff --git a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb index a0bf30aaf17..3660923d1b4 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb @@ -101,7 +101,7 @@ def try(value) end end - context 'AppSec scope is nil ' do + context 'AppSec context is nil ' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } let(:mode) { 'safe' } diff --git a/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb b/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb index 52455ff8afd..65a9cbf2855 100644 --- a/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb +++ b/spec/datadog/appsec/contrib/rack/gateway/response_spec.rb @@ -15,7 +15,7 @@ body, 200, headers, - scope: instance_double(Datadog::AppSec::Context) + context: instance_double(Datadog::AppSec::Context) ) end diff --git a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb index 84ecc4cf518..0d53e61464f 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb @@ -19,7 +19,7 @@ body, 200, headers, - scope: context, + context: context, ) end diff --git a/spec/datadog/kit/appsec/events_spec.rb b/spec/datadog/kit/appsec/events_spec.rb index c95276b9d43..7f2ff40ab04 100644 --- a/spec/datadog/kit/appsec/events_spec.rb +++ b/spec/datadog/kit/appsec/events_spec.rb @@ -9,7 +9,7 @@ let(:trace_op) { Datadog::Tracing::TraceOperation.new } shared_context 'uses AppSec context' do - before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_context) } + before { allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) } let(:appsec_span) { trace_op.build_span('root') } context 'when is present' do @@ -19,7 +19,7 @@ Datadog::AppSec::Context.new(trace_op, appsec_span, processor) end - it 'sets tags on AppSec scope' do + it 'sets tags on AppSec span' do event expect(appsec_span.has_tag?(event_tag)).to eq true end diff --git a/spec/datadog/kit/identity_spec.rb b/spec/datadog/kit/identity_spec.rb index c3d9fb15858..d888eb437bf 100644 --- a/spec/datadog/kit/identity_spec.rb +++ b/spec/datadog/kit/identity_spec.rb @@ -213,7 +213,7 @@ context 'appsec' do let(:appsec_active_context) { nil } - before { allow(Datadog::AppSec).to receive(:active_scope).and_return(appsec_active_context) } + before { allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) } context 'when is enabled' do let(:appsec_active_context) do From 7ce4b9e47e2afab6a52a288c108cb9130ea0d9bd Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 10 Jan 2025 10:14:01 +0100 Subject: [PATCH 07/11] Change AppSec::Context interface --- lib/datadog/appsec.rb | 2 +- lib/datadog/appsec/context.rb | 58 +++++-------- .../appsec/contrib/graphql/gateway/watcher.rb | 2 +- .../appsec/contrib/rack/request_middleware.rb | 7 +- spec/datadog/appsec/context_spec.rb | 84 +++++++++---------- 5 files changed, 69 insertions(+), 84 deletions(-) diff --git a/lib/datadog/appsec.rb b/lib/datadog/appsec.rb index a95e8e30253..968b9c6a1fb 100644 --- a/lib/datadog/appsec.rb +++ b/lib/datadog/appsec.rb @@ -15,7 +15,7 @@ def enabled? end def active_context - Datadog::AppSec::Context.active_context + Datadog::AppSec::Context.active end def processor diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index 881bc5f6a99..de506ec74f7 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -2,56 +2,44 @@ module Datadog module AppSec - # Write desciption TODO + # This class accumulates the context over the request life-cycle and exposes + # interface sufficient for instrumentation to perform threat detection. class Context - InactiveScopeError = Class.new(StandardError) - ActiveScopeError = Class.new(StandardError) + ActiveContextError = Class.new(StandardError) attr_reader :trace, :service_entry_span, :processor_context - def initialize(trace, service_entry_span, processor_context) - @trace = trace - @service_entry_span = service_entry_span - @processor_context = processor_context - end - - def finalize - @processor_context.finalize - end - class << self - def activate_context(trace, service_entry_span, processor) - raise ActiveScopeError, 'another context is active, nested contexts are not supported' if active_context + def activate(context) + raise ArgumentError, 'not a Datadog::AppSec::Context' unless context.instance_of?(Context) + raise ActiveContextError, 'another context is active, nested contexts are not supported' if active - context = processor.new_context - self.active_context = new(trace, service_entry_span, context) + Thread.current[Ext::ACTIVE_CONTEXT_KEY] = context end - def deactivate_context - raise InactiveScopeError, 'no context is active, nested contexts are not supported' unless active_context - - context = active_context - - reset_active_context - - context.finalize + def deactivate + active&.finalize + ensure + Thread.current[Ext::ACTIVE_CONTEXT_KEY] = nil end - def active_context + def active Thread.current[Ext::ACTIVE_CONTEXT_KEY] end + end - private - - def active_context=(context) - raise ArgumentError, 'not a Datadog::AppSec::Context' unless context.instance_of?(Context) + def initialize(trace, span, security_engine) + @trace = trace + @span = span + @security_engine = security_engine - Thread.current[Ext::ACTIVE_CONTEXT_KEY] = context - end + # TODO: Rename + @service_entry_span = span + @processor_context = security_engine.new_context + end - def reset_active_context - Thread.current[Ext::ACTIVE_CONTEXT_KEY] = nil - end + def finalize + @processor_context.finalize end end end diff --git a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb index aeefe9df4d5..64e0de6fabe 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -24,7 +24,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) gateway.watch('graphql.multiplex', :appsec) do |stack, gateway_multiplex| block = false event = nil - context = AppSec::Context.active_context + context = AppSec::Context.active engine = AppSec::Reactive::Engine.new if context diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index f5763190a92..29f8fd45e4a 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -56,7 +56,10 @@ def call(env) processor = Datadog::AppSec.processor if !processor.nil? && processor.ready? - ctx = Datadog::AppSec::Context.activate_context(active_trace, active_span, processor) + ctx = Datadog::AppSec::Context.activate( + Datadog::AppSec::Context.new(active_trace, active_span, processor) + ) + env[Datadog::AppSec::Ext::CONTEXT_KEY] = ctx ready = true end @@ -117,7 +120,7 @@ def call(env) ensure if ctx add_waf_runtime_tags(ctx) - Datadog::AppSec::Context.deactivate_context + Datadog::AppSec::Context.deactivate end end # rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity,Metrics/MethodLength diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index 2634d6a69dc..a1f44b070a7 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -4,90 +4,84 @@ require 'datadog/appsec/context' RSpec.describe Datadog::AppSec::Context do - let(:trace) { double } - let(:span) { double } + let(:span) { instance_double(Datadog::Tracing::SpanOperation) } + let(:trace) { instance_double(Datadog::Tracing::TraceOperation) } let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } + let(:context) { described_class.new(trace, span, processor) } after do - described_class.send(:reset_active_context) + described_class.deactivate processor.finalize end - describe '.activate_context' do + describe '.active' do context 'with no active context' do - subject(:activate_context) { described_class.activate_context(trace, span, processor) } + it { expect(described_class.active).to be_nil } + end - it 'returns a new context' do - expect(activate_context).to be_a described_class - end + context 'with an active context' do + before { described_class.activate(context) } - it 'sets the active context' do - expect { activate_context }.to change { described_class.active_context }.from(nil).to be_a described_class - end + it { expect(described_class.active).to eq(context) } + end + end + + describe '.activate' do + it { expect { described_class.activate(double) }.to raise_error(ArgumentError) } + + context 'with no active context' do + it { expect { described_class.activate(context) }.to change { described_class.active }.from(nil).to(context) } end context 'with an active context' do - before do - described_class.activate_context(trace, span, processor) - end + before { described_class.activate(context) } - subject(:activate_context) { described_class.activate_context(trace, span, processor) } + subject(:activate_context) { described_class.activate(described_class.new(trace, span, processor)) } - it 'raises ActiveScopeError' do - expect { activate_context }.to raise_error Datadog::AppSec::Context::ActiveScopeError + it 'raises ActiveContextError' do + expect { activate_context }.to raise_error(Datadog::AppSec::Context::ActiveContextError) end it 'does not change the active context' do - expect { activate_context rescue nil }.to_not(change { described_class.active_context }) + expect { activate_context rescue nil }.to_not(change { described_class.active }) end end end - describe '.deactivate_context' do + describe '.deactivate' do context 'with no active context' do - subject(:deactivate_context) { described_class.deactivate_context } - - it 'raises ActiveContextError' do - expect { deactivate_context }.to raise_error Datadog::AppSec::Context::InactiveScopeError - end - it 'does not change the active context' do - expect { deactivate_context rescue nil }.to_not(change { described_class.active_context }) + expect { described_class.deactivate }.to_not(change { described_class.active }) end end context 'with an active context' do - let(:active_context) { described_class.active_context } - subject(:deactivate_context) { described_class.deactivate_context } - before do - allow(described_class).to receive(:new).and_call_original - - described_class.activate_context(trace, span, processor) - - expect(active_context).to receive(:finalize).and_call_original + described_class.activate(context) + expect(context).to receive(:finalize).and_call_original end it 'unsets the active context' do - expect { deactivate_context }.to change { described_class.active_context }.from(active_context).to nil + expect { described_class.deactivate }.to change { described_class.active }.from(context).to(nil) end end - end - - describe '.active_context' do - subject(:active_context) { described_class.active_context } - context 'with no active context' do - it { is_expected.to be_nil } - end + context 'with error during deactivation' do + before do + described_class.activate(context) + expect(context).to receive(:finalize).and_raise(RuntimeError.new('Ooops')) + end - context 'with an active context' do - before { described_class.activate_context(trace, span, processor) } + it 'raises underlying exception' do + expect { described_class.deactivate }.to raise_error(RuntimeError) + end - it { is_expected.to be_a described_class } + it 'unsets the active context' do + expect { described_class.deactivate rescue nil }.to change { described_class.active }.from(context).to(nil) + end end end end From ff493bf487426d0034d5797698c4e203cc84de60 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 10 Jan 2025 13:01:44 +0100 Subject: [PATCH 08/11] Change AppSec::Context exposed interface --- lib/datadog/appsec/context.rb | 21 ++++++++++++---- .../contrib/active_record/instrumentation.rb | 2 +- .../devise/patcher/authenticatable_patch.rb | 4 ++-- .../patcher/registration_controller_patch.rb | 2 +- .../appsec/contrib/graphql/gateway/watcher.rb | 2 +- .../appsec/contrib/rack/gateway/watcher.rb | 6 ++--- .../appsec/contrib/rack/request_middleware.rb | 10 ++++---- .../appsec/contrib/rails/gateway/watcher.rb | 2 +- .../appsec/contrib/sinatra/gateway/watcher.rb | 4 ++-- lib/datadog/appsec/event.rb | 6 ++--- lib/datadog/appsec/monitor/gateway/watcher.rb | 2 +- lib/datadog/kit/appsec/events.rb | 2 +- lib/datadog/kit/identity.rb | 2 +- .../patcher/authenticatable_patch_spec.rb | 22 ++++++++--------- .../registration_controller_patch_spec.rb | 20 ++++++++-------- spec/datadog/appsec/event_spec.rb | 24 +++++++++---------- 16 files changed, 71 insertions(+), 60 deletions(-) diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index de506ec74f7..cf63ab4a57a 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -7,7 +7,10 @@ module AppSec class Context ActiveContextError = Class.new(StandardError) - attr_reader :trace, :service_entry_span, :processor_context + # XXX: Continue from here: + # 1. Replace naming of processor_context into waf_runner + # 2. Replace calls of waf run + attr_reader :trace, :span, :processor_context class << self def activate(context) @@ -32,14 +35,22 @@ def initialize(trace, span, security_engine) @trace = trace @span = span @security_engine = security_engine + @waf_runner = security_engine.new_context - # TODO: Rename - @service_entry_span = span - @processor_context = security_engine.new_context + # FIXME: Left for compatibility now + @processor_context = @waf_runner + end + + def run_waf(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT) + @waf_runner.run(persistent_data, ephemeral_data, timeout) + end + + def run_rasp(_type, persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT) + @waf_runner.run(persistent_data, ephemeral_data, timeout) end def finalize - @processor_context.finalize + @waf_runner.finalize end end end diff --git a/lib/datadog/appsec/contrib/active_record/instrumentation.rb b/lib/datadog/appsec/contrib/active_record/instrumentation.rb index f8c261bc354..57334c93896 100644 --- a/lib/datadog/appsec/contrib/active_record/instrumentation.rb +++ b/lib/datadog/appsec/contrib/active_record/instrumentation.rb @@ -31,7 +31,7 @@ def detect_sql_injection(sql, adapter_name) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, sql: sql, actions: result.actions } diff --git a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb index b01a59c6e10..51d0b06619d 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb @@ -40,7 +40,7 @@ def validate(resource, &block) Tracking.track_login_success( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: event_information.user_id, **event_information.to_h ) @@ -60,7 +60,7 @@ def validate(resource, &block) Tracking.track_login_failure( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: event_information.user_id, user_exists: user_exists, **event_information.to_h diff --git a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb index 35803d3438d..8db73f60f32 100644 --- a/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +++ b/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb @@ -37,7 +37,7 @@ def create Tracking.track_signup( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: event_information.user_id, **event_information.to_h ) diff --git a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb index 64e0de6fabe..4855a81ce68 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -32,7 +32,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, multiplex: gateway_multiplex, actions: result.actions } diff --git a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb index d32b13a4fc0..c006fa1e400 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -35,7 +35,7 @@ def watch_request(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, request: gateway_request, actions: result.actions } @@ -66,7 +66,7 @@ def watch_response(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, response: gateway_response, actions: result.actions } @@ -97,7 +97,7 @@ def watch_request_body(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, request: gateway_request, actions: result.actions } diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index 29f8fd45e4a..33e1e121bca 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -99,7 +99,7 @@ def call(env) if result ctx.processor_context.events << { trace: ctx.trace, - span: ctx.service_entry_span, + span: ctx.span, waf_result: result, } end @@ -109,7 +109,7 @@ def call(env) e[:request] ||= gateway_request end - AppSec::Event.record(ctx.service_entry_span, *ctx.processor_context.events) + AppSec::Event.record(ctx.span, *ctx.processor_context.events) if response_response blocked_event = response_response.find { |action, _options| action == :block } @@ -148,7 +148,7 @@ def active_span end def add_appsec_tags(processor, context) - span = context.service_entry_span + span = context.span trace = context.trace return unless trace && span @@ -185,7 +185,7 @@ def add_appsec_tags(processor, context) end def add_request_tags(context, env) - span = context.service_entry_span + span = context.span return unless span @@ -208,7 +208,7 @@ def add_request_tags(context, env) end def add_waf_runtime_tags(context) - span = context.service_entry_span + span = context.span context = context.processor_context return unless span && context diff --git a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb index 87adb30a555..84be36bae4f 100644 --- a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb @@ -31,7 +31,7 @@ def watch_request_action(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, request: gateway_request, actions: result.actions } diff --git a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb index 3bf5837e2a2..8c20ca4b3a2 100644 --- a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb @@ -33,7 +33,7 @@ def watch_request_dispatch(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, request: gateway_request, actions: result.actions } @@ -64,7 +64,7 @@ def watch_request_routed(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, request: gateway_request, actions: result.actions } diff --git a/lib/datadog/appsec/event.rb b/lib/datadog/appsec/event.rb index 37ab9da4e8a..ad43bc354cb 100644 --- a/lib/datadog/appsec/event.rb +++ b/lib/datadog/appsec/event.rb @@ -141,9 +141,9 @@ def tag_and_keep!(context, waf_result) # We want to keep the trace in case of security event context.trace.keep! if context.trace - if context.service_entry_span - context.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request') - context.service_entry_span.set_tag('appsec.event', 'true') + if context.span + context.span.set_tag('appsec.blocked', 'true') if waf_result.actions.key?('block_request') + context.span.set_tag('appsec.event', 'true') end add_distributed_tags(context.trace) diff --git a/lib/datadog/appsec/monitor/gateway/watcher.rb b/lib/datadog/appsec/monitor/gateway/watcher.rb index 014abcfffb7..69ebfb0420b 100644 --- a/lib/datadog/appsec/monitor/gateway/watcher.rb +++ b/lib/datadog/appsec/monitor/gateway/watcher.rb @@ -29,7 +29,7 @@ def watch_user_id(gateway = Instrumentation.gateway) event = { waf_result: result, trace: context.trace, - span: context.service_entry_span, + span: context.span, user: user, actions: result.actions } diff --git a/lib/datadog/kit/appsec/events.rb b/lib/datadog/kit/appsec/events.rb index 3b5c9717110..61b6b6bf934 100644 --- a/lib/datadog/kit/appsec/events.rb +++ b/lib/datadog/kit/appsec/events.rb @@ -138,7 +138,7 @@ def track(event, trace = nil, span = nil, **others) def set_trace_and_span_context(method, trace = nil, span = nil) if (appsec_context = Datadog::AppSec.active_context) trace = appsec_context.trace - span = appsec_context.service_entry_span + span = appsec_context.span end trace ||= Datadog::Tracing.active_trace diff --git a/lib/datadog/kit/identity.rb b/lib/datadog/kit/identity.rb index 09de6392ead..a782f1364ae 100644 --- a/lib/datadog/kit/identity.rb +++ b/lib/datadog/kit/identity.rb @@ -80,7 +80,7 @@ def set_user( def set_trace_and_span_context(method, trace = nil, span = nil) if (appsec_context = Datadog::AppSec.active_context) trace = appsec_context.trace - span = appsec_context.service_entry_span + span = appsec_context.span end trace ||= Datadog::Tracing.active_trace diff --git a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb index 2f763049475..e2741ddb90e 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/authenticatable_patch_spec.rb @@ -82,7 +82,7 @@ def initialize(id, email, username) context 'when logging in from Rememberable devise strategy' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, span: double) } let(:mock_klass) do Class.new do @@ -109,7 +109,7 @@ def initialize(result) context 'successful login' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, span: double) } context 'with resource ID' do context 'safe mode' do @@ -118,7 +118,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{} ) @@ -132,7 +132,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{ username: 'John', email: 'hello@gmail.com' } ) @@ -150,7 +150,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{} ) @@ -164,7 +164,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_success).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{ username: 'John', email: 'hello@gmail.com' } ) @@ -177,7 +177,7 @@ def initialize(result) context 'unsuccessful login' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, span: double) } context 'with resource' do context 'safe mode' do @@ -186,7 +186,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, user_exists: true, **{} @@ -201,7 +201,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, user_exists: true, **{ username: 'John', email: 'hello@gmail.com' } @@ -218,7 +218,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, user_exists: false, **{} @@ -233,7 +233,7 @@ def initialize(result) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_login_failure).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, user_exists: false, **{} diff --git a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb index 3660923d1b4..d2fb4e3c338 100644 --- a/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb +++ b/spec/datadog/appsec/contrib/devise/patcher/registration_controller_patch_spec.rb @@ -127,7 +127,7 @@ def try(value) context 'with persisted resource' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, span: double) } context 'with resource ID' do let(:resource) { persited_resource } @@ -142,7 +142,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{} ) @@ -157,7 +157,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -173,7 +173,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{} ) @@ -187,7 +187,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: resource.id, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -209,7 +209,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{} ) @@ -224,7 +224,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -240,7 +240,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{} ) @@ -254,7 +254,7 @@ def try(value) it 'tracks event' do expect(Datadog::AppSec::Contrib::Devise::Tracking).to receive(:track_signup).with( appsec_context.trace, - appsec_context.service_entry_span, + appsec_context.span, user_id: nil, **{ email: 'hello@gmail.com', username: 'John' } ) @@ -267,7 +267,7 @@ def try(value) context 'with non persisted resource' do let(:appsec_enabled) { true } let(:track_user_events_enabled) { true } - let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, service_entry_span: double) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context, trace: double, span: double) } let(:resource) { non_persisted_resource } context 'safe mode' do diff --git a/spec/datadog/appsec/event_spec.rb b/spec/datadog/appsec/event_spec.rb index 194381ea4e1..f3a0df8195b 100644 --- a/spec/datadog/appsec/event_spec.rb +++ b/spec/datadog/appsec/event_spec.rb @@ -385,10 +385,10 @@ context_span = span if with_span end - dbl = double + dbl = instance_double(Datadog::AppSec::Context) allow(dbl).to receive(:trace).and_return(context_trace) - allow(dbl).to receive(:service_entry_span).and_return(context_span) + allow(dbl).to receive(:span).and_return(context_span) dbl end @@ -402,8 +402,8 @@ context 'with no actions' do it 'does not add appsec.blocked tag to span' do - expect(context.service_entry_span.send(:meta)).to_not include('appsec.blocked') - expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.span.send(:meta)).to_not include('appsec.blocked') + expect(context.span.send(:meta)['appsec.event']).to eq('true') expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end @@ -415,18 +415,18 @@ end it 'adds appsec.blocked tag to span' do - expect(context.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') - expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.span.send(:meta)['appsec.blocked']).to eq('true') + expect(context.span.send(:meta)['appsec.event']).to eq('true') expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end end - context 'without service_entry_span' do + context 'without span' do let(:with_span) { false } it 'does not add appsec span tags but still add distributed tags' do - expect(context.service_entry_span).to be nil + expect(context.span).to be nil expect(context.trace.send(:meta)['_dd.p.dm']).to eq('-5') expect(context.trace.send(:meta)['_dd.p.appsec']).to eq('1') end @@ -438,8 +438,8 @@ context 'with no actions' do it 'does not add distributed tags but still add appsec span tags' do expect(context.trace).to be nil - expect(context.service_entry_span.send(:meta)['appsec.blocked']).to be nil - expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.span.send(:meta)['appsec.blocked']).to be nil + expect(context.span.send(:meta)['appsec.event']).to eq('true') end end @@ -450,8 +450,8 @@ it 'does not add distributed tags but still add appsec span tags' do expect(context.trace).to be nil - expect(context.service_entry_span.send(:meta)['appsec.blocked']).to eq('true') - expect(context.service_entry_span.send(:meta)['appsec.event']).to eq('true') + expect(context.span.send(:meta)['appsec.blocked']).to eq('true') + expect(context.span.send(:meta)['appsec.event']).to eq('true') end end end From c709dcab24f66fd1467f707463a660eae28fac22 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 10 Jan 2025 14:20:25 +0100 Subject: [PATCH 09/11] Replace direct AppSec::Processor::Context calls --- lib/datadog/appsec/context.rb | 11 +++---- .../contrib/active_record/instrumentation.rb | 4 +-- .../appsec/contrib/graphql/gateway/watcher.rb | 4 +-- .../contrib/graphql/reactive/multiplex.rb | 4 +-- .../appsec/contrib/rack/gateway/watcher.rb | 12 +++---- .../appsec/contrib/rack/reactive/request.rb | 4 +-- .../contrib/rack/reactive/request_body.rb | 4 +-- .../appsec/contrib/rack/reactive/response.rb | 4 +-- .../appsec/contrib/rack/request_middleware.rb | 10 +++--- .../appsec/contrib/rails/gateway/watcher.rb | 4 +-- .../appsec/contrib/rails/reactive/action.rb | 4 +-- .../appsec/contrib/sinatra/gateway/watcher.rb | 8 ++--- .../appsec/contrib/sinatra/reactive/routed.rb | 4 +-- lib/datadog/appsec/ext.rb | 1 + lib/datadog/appsec/monitor/gateway/watcher.rb | 4 +-- .../appsec/monitor/reactive/set_user.rb | 4 +-- spec/datadog/appsec/context_spec.rb | 14 +++----- .../active_record/mysql2_adapter_spec.rb | 22 +++++++------ .../active_record/postgresql_adapter_spec.rb | 22 +++++++------ .../active_record/sqlite3_adapter_spec.rb | 27 ++++++++-------- .../graphql/reactive/multiplex_spec.rb | 10 +++--- .../rack/reactive/request_body_spec.rb | 10 +++--- .../contrib/rack/reactive/request_spec.rb | 10 +++--- .../contrib/rack/reactive/response_spec.rb | 20 ++++++------ .../contrib/rails/reactive/action_spec.rb | 10 +++--- .../contrib/sinatra/reactive/routed_spec.rb | 10 +++--- .../appsec/monitor/reactive/set_user_spec.rb | 10 +++--- .../appsec/reactive/shared_examples.rb | 32 +++++++++---------- spec/datadog/kit/appsec/events_spec.rb | 13 ++++---- spec/datadog/kit/identity_spec.rb | 8 +++-- 30 files changed, 151 insertions(+), 153 deletions(-) diff --git a/lib/datadog/appsec/context.rb b/lib/datadog/appsec/context.rb index cf63ab4a57a..393cad27069 100644 --- a/lib/datadog/appsec/context.rb +++ b/lib/datadog/appsec/context.rb @@ -7,10 +7,10 @@ module AppSec class Context ActiveContextError = Class.new(StandardError) - # XXX: Continue from here: - # 1. Replace naming of processor_context into waf_runner - # 2. Replace calls of waf run - attr_reader :trace, :span, :processor_context + attr_reader :trace, :span + + # NOTE: This is an intermediate state and will be changed + attr_reader :waf_runner class << self def activate(context) @@ -36,9 +36,6 @@ def initialize(trace, span, security_engine) @span = span @security_engine = security_engine @waf_runner = security_engine.new_context - - # FIXME: Left for compatibility now - @processor_context = @waf_runner end def run_waf(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT) diff --git a/lib/datadog/appsec/contrib/active_record/instrumentation.rb b/lib/datadog/appsec/contrib/active_record/instrumentation.rb index 57334c93896..41a8e80523c 100644 --- a/lib/datadog/appsec/contrib/active_record/instrumentation.rb +++ b/lib/datadog/appsec/contrib/active_record/instrumentation.rb @@ -23,7 +23,7 @@ def detect_sql_injection(sql, adapter_name) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = context.processor_context.run({}, ephemeral_data, waf_timeout) + result = context.run_rasp(Ext::RASP_SQLI, {}, ephemeral_data, waf_timeout) if result.status == :match Datadog::AppSec::Event.tag_and_keep!(context, result) @@ -35,7 +35,7 @@ def detect_sql_injection(sql, adapter_name) sql: sql, actions: result.actions } - context.processor_context.events << event + context.waf_runner.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 4855a81ce68..025b6e10359 100644 --- a/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb @@ -28,7 +28,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) engine = AppSec::Reactive::Engine.new if context - GraphQL::Reactive::Multiplex.subscribe(engine, context.processor_context) do |result| + GraphQL::Reactive::Multiplex.subscribe(engine, context) do |result| event = { waf_result: result, trace: context.trace, @@ -38,7 +38,7 @@ def watch_multiplex(gateway = Instrumentation.gateway) } Datadog::AppSec::Event.tag_and_keep!(context, result) - context.processor_context.events << event + context.waf_runner.events << event end block = GraphQL::Reactive::Multiplex.publish(engine, gateway_multiplex) diff --git a/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb b/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb index cfbf31dc1b8..ec6380cff52 100644 --- a/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +++ b/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb @@ -20,7 +20,7 @@ def self.publish(engine, gateway_multiplex) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } arguments = values[0] @@ -30,7 +30,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb index c006fa1e400..a655b3fe1d5 100644 --- a/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rack/gateway/watcher.rb @@ -29,7 +29,7 @@ def watch_request(gateway = Instrumentation.gateway) context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::Request.subscribe(engine, context.processor_context) do |result| + Rack::Reactive::Request.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end @@ -60,7 +60,7 @@ def watch_response(gateway = Instrumentation.gateway) context = gateway_response.context engine = AppSec::Reactive::Engine.new - Rack::Reactive::Response.subscribe(engine, context.processor_context) do |result| + Rack::Reactive::Response.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end @@ -91,7 +91,7 @@ def watch_request_body(gateway = Instrumentation.gateway) context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| + Rack::Reactive::RequestBody.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end diff --git a/lib/datadog/appsec/contrib/rack/reactive/request.rb b/lib/datadog/appsec/contrib/rack/reactive/request.rb index 78074268af6..31333851412 100644 --- a/lib/datadog/appsec/contrib/rack/reactive/request.rb +++ b/lib/datadog/appsec/contrib/rack/reactive/request.rb @@ -30,7 +30,7 @@ def self.publish(engine, gateway_request) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } @@ -53,7 +53,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/contrib/rack/reactive/request_body.rb b/lib/datadog/appsec/contrib/rack/reactive/request_body.rb index 57395ac83b8..0cf74aef33f 100644 --- a/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +++ b/lib/datadog/appsec/contrib/rack/reactive/request_body.rb @@ -21,7 +21,7 @@ def self.publish(engine, gateway_request) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } body = values[0] @@ -31,7 +31,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/contrib/rack/reactive/response.rb b/lib/datadog/appsec/contrib/rack/reactive/response.rb index 8c0cd706d26..9eca3e0157b 100644 --- a/lib/datadog/appsec/contrib/rack/reactive/response.rb +++ b/lib/datadog/appsec/contrib/rack/reactive/response.rb @@ -22,7 +22,7 @@ def self.publish(engine, gateway_response) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } @@ -37,7 +37,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index 33e1e121bca..6aa14798a19 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -94,22 +94,22 @@ def call(env) _response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response) - result = ctx.processor_context.extract_schema + result = ctx.waf_runner.extract_schema if result - ctx.processor_context.events << { + ctx.waf_runner.events << { trace: ctx.trace, span: ctx.span, waf_result: result, } end - ctx.processor_context.events.each do |e| + ctx.waf_runner.events.each do |e| e[:response] ||= gateway_response e[:request] ||= gateway_request end - AppSec::Event.record(ctx.span, *ctx.processor_context.events) + AppSec::Event.record(ctx.span, *ctx.waf_runner.events) if response_response blocked_event = response_response.find { |action, _options| action == :block } @@ -209,7 +209,7 @@ def add_request_tags(context, env) def add_waf_runtime_tags(context) span = context.span - context = context.processor_context + context = context.waf_runner return unless span && context diff --git a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb index 84be36bae4f..4ae52c73333 100644 --- a/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/rails/gateway/watcher.rb @@ -25,7 +25,7 @@ def watch_request_action(gateway = Instrumentation.gateway) context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new - Rails::Reactive::Action.subscribe(engine, context.processor_context) do |result| + Rails::Reactive::Action.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end diff --git a/lib/datadog/appsec/contrib/rails/reactive/action.rb b/lib/datadog/appsec/contrib/rails/reactive/action.rb index 9dbe8697e51..b1589b3131e 100644 --- a/lib/datadog/appsec/contrib/rails/reactive/action.rb +++ b/lib/datadog/appsec/contrib/rails/reactive/action.rb @@ -25,7 +25,7 @@ def self.publish(engine, gateway_request) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } body = values[0] @@ -37,7 +37,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb index 8c20ca4b3a2..a9ca382b904 100644 --- a/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +++ b/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb @@ -27,7 +27,7 @@ def watch_request_dispatch(gateway = Instrumentation.gateway) context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new - Rack::Reactive::RequestBody.subscribe(engine, context.processor_context) do |result| + Rack::Reactive::RequestBody.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end @@ -58,7 +58,7 @@ def watch_request_routed(gateway = Instrumentation.gateway) context = gateway_request.env[Datadog::AppSec::Ext::CONTEXT_KEY] engine = AppSec::Reactive::Engine.new - Sinatra::Reactive::Routed.subscribe(engine, context.processor_context) do |result| + Sinatra::Reactive::Routed.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end diff --git a/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb b/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb index e34dfb4ccb3..7227d0539d6 100644 --- a/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +++ b/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb @@ -22,7 +22,7 @@ def self.publish(engine, data) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } path_params = values[0] @@ -32,7 +32,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/lib/datadog/appsec/ext.rb b/lib/datadog/appsec/ext.rb index a801a394546..2c6e6f5fae3 100644 --- a/lib/datadog/appsec/ext.rb +++ b/lib/datadog/appsec/ext.rb @@ -3,6 +3,7 @@ module Datadog module AppSec module Ext + RASP_SQLI = :sql_injection INTERRUPT = :datadog_appsec_interrupt CONTEXT_KEY = 'datadog.appsec.context' ACTIVE_CONTEXT_KEY = :datadog_appsec_active_context diff --git a/lib/datadog/appsec/monitor/gateway/watcher.rb b/lib/datadog/appsec/monitor/gateway/watcher.rb index 69ebfb0420b..4d0194f9c7a 100644 --- a/lib/datadog/appsec/monitor/gateway/watcher.rb +++ b/lib/datadog/appsec/monitor/gateway/watcher.rb @@ -23,7 +23,7 @@ def watch_user_id(gateway = Instrumentation.gateway) context = Datadog::AppSec.active_context engine = AppSec::Reactive::Engine.new - Monitor::Reactive::SetUser.subscribe(engine, context.processor_context) do |result| + Monitor::Reactive::SetUser.subscribe(engine, context) do |result| if result.status == :match # TODO: should this hash be an Event instance instead? event = { @@ -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.processor_context.events << event + context.waf_runner.events << event end end diff --git a/lib/datadog/appsec/monitor/reactive/set_user.rb b/lib/datadog/appsec/monitor/reactive/set_user.rb index ea3128c6031..64df8931f30 100644 --- a/lib/datadog/appsec/monitor/reactive/set_user.rb +++ b/lib/datadog/appsec/monitor/reactive/set_user.rb @@ -19,7 +19,7 @@ def self.publish(engine, user) end end - def self.subscribe(engine, waf_context) + def self.subscribe(engine, context) engine.subscribe(*ADDRESSES) do |*values| Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" } @@ -30,7 +30,7 @@ def self.subscribe(engine, waf_context) } waf_timeout = Datadog.configuration.appsec.waf_timeout - result = waf_context.run(persistent_data, {}, waf_timeout) + result = context.run_waf(persistent_data, {}, waf_timeout) next if result.status != :match diff --git a/spec/datadog/appsec/context_spec.rb b/spec/datadog/appsec/context_spec.rb index a1f44b070a7..e490cd6aaf3 100644 --- a/spec/datadog/appsec/context_spec.rb +++ b/spec/datadog/appsec/context_spec.rb @@ -41,12 +41,9 @@ subject(:activate_context) { described_class.activate(described_class.new(trace, span, processor)) } - it 'raises ActiveContextError' do + it 'raises ActiveContextError and does not change the active context' do expect { activate_context }.to raise_error(Datadog::AppSec::Context::ActiveContextError) - end - - it 'does not change the active context' do - expect { activate_context rescue nil }.to_not(change { described_class.active }) + .and(not_change { described_class.active }) end end end @@ -75,12 +72,9 @@ expect(context).to receive(:finalize).and_raise(RuntimeError.new('Ooops')) end - it 'raises underlying exception' do + it 'raises underlying exception and unsets the active context' do expect { described_class.deactivate }.to raise_error(RuntimeError) - end - - it 'unsets the active context' do - expect { described_class.deactivate rescue nil }.to change { described_class.active }.from(context).to(nil) + .and(change { described_class.active }.from(context).to(nil)) end end end 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 b43f7b15dc0..59306b5a7ba 100644 --- a/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb @@ -15,7 +15,7 @@ let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } - let(:context) { processor.new_context } + let(:context) { Datadog::AppSec::Context.new(trace, span, processor) } let(:span) { Datadog::Tracing::SpanOperation.new('root') } let(:trace) { Datadog::Tracing::TraceOperation.new } @@ -52,7 +52,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_context(trace, span, processor) + Datadog::AppSec::Context.activate(context) raise_on_rails_deprecation! end @@ -60,13 +60,14 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_context + Datadog::AppSec::Context.deactivate processor.finalize end it 'calls waf with correct arguments when querying using .where' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => "SELECT `users`.* FROM `users` WHERE `users`.`name` = 'Bob'", @@ -80,8 +81,9 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'", @@ -95,11 +97,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_context.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.waf_runner.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 88bf4ed57fa..1a718855f00 100644 --- a/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb @@ -15,7 +15,7 @@ let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } - let(:context) { processor.new_context } + let(:context) { Datadog::AppSec::Context.new(trace, span, processor) } let(:span) { Datadog::Tracing::SpanOperation.new('root') } let(:trace) { Datadog::Tracing::TraceOperation.new } @@ -53,7 +53,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_context(trace, span, processor) + Datadog::AppSec::Context.activate(context) raise_on_rails_deprecation! end @@ -61,7 +61,7 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_context + Datadog::AppSec::Context.deactivate processor.finalize end @@ -72,8 +72,9 @@ 'SELECT "users".* FROM "users" WHERE "users"."name" = $1' end - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => expected_db_statement, @@ -87,8 +88,9 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'", @@ -102,11 +104,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_context.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.waf_runner.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 9be5d7ebfad..c15246f9017 100644 --- a/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb +++ b/spec/datadog/appsec/contrib/active_record/sqlite3_adapter_spec.rb @@ -15,7 +15,7 @@ let(:telemetry) { instance_double(Datadog::Core::Telemetry::Component) } let(:ruleset) { Datadog::AppSec::Processor::RuleLoader.load_rules(ruleset: :recommended, telemetry: telemetry) } let(:processor) { Datadog::AppSec::Processor.new(ruleset: ruleset, telemetry: telemetry) } - let(:context) { processor.new_context } + let(:context) { Datadog::AppSec::Context.new(trace, span, processor) } let(:span) { Datadog::Tracing::SpanOperation.new('root') } let(:trace) { Datadog::Tracing::TraceOperation.new } @@ -37,10 +37,7 @@ end let(:db_config) do - { - adapter: 'sqlite3', - database: ':memory:' - } + { adapter: 'sqlite3', database: ':memory:' } end before do @@ -49,7 +46,7 @@ c.appsec.instrument :active_record end - Datadog::AppSec::Context.activate_context(trace, span, processor) + Datadog::AppSec::Context.activate(context) raise_on_rails_deprecation! end @@ -57,13 +54,14 @@ after do Datadog.configuration.reset! - Datadog::AppSec::Context.deactivate_context + Datadog::AppSec::Context.deactivate processor.finalize end it 'calls waf with correct arguments when querying using .where' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => 'SELECT "users".* FROM "users" WHERE "users"."name" = ?', @@ -77,8 +75,9 @@ end it 'calls waf with correct arguments when querying using .find_by_sql' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).with( + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).with( + Datadog::AppSec::Ext::RASP_SQLI, {}, { 'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'", @@ -92,11 +91,11 @@ end it 'adds an event to processor context if waf status is :match' do - expect(Datadog::AppSec.active_context.processor_context).to( - receive(:run).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) + expect(Datadog::AppSec.active_context).to( + receive(:run_rasp).and_return(instance_double(Datadog::AppSec::WAF::Result, status: :match, actions: {})) ) - expect(Datadog::AppSec.active_context.processor_context.events).to receive(:<<).and_call_original + expect(Datadog::AppSec.active_context.waf_runner.events).to receive(:<<).and_call_original User.where(name: 'Bob').to_a end diff --git a/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb b/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb index 21df7b7b6d5..b1354a738cb 100644 --- a/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb +++ b/spec/datadog/appsec/contrib/graphql/reactive/multiplex_spec.rb @@ -29,15 +29,15 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do expect(engine).to receive(:subscribe).with( 'graphql.server.all_resolvers' ).and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -46,12 +46,12 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( { 'graphql.server.all_resolvers' => expected_arguments }, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) gateway_multiplex = Datadog::AppSec::Contrib::GraphQL::Gateway::Multiplex.new(multiplex) result = described_class.publish(engine, gateway_multiplex) expect(result).to be_nil diff --git a/spec/datadog/appsec/contrib/rack/reactive/request_body_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/request_body_spec.rb index 75cf9aae480..e4363628dd7 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/request_body_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/request_body_spec.rb @@ -28,13 +28,13 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do expect(engine).to receive(:subscribe).with('request.body').and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -45,12 +45,12 @@ expected_waf_arguments = { 'server.request.body' => { 'foo' => 'bar' } } waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_arguments, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, request) expect(result).to be_nil end diff --git a/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb index f22a3964b1d..b0327350d70 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/request_spec.rb @@ -47,7 +47,7 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do @@ -59,8 +59,8 @@ 'request.client_ip', 'server.request.method', ).and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -79,12 +79,12 @@ } waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_arguments, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, request) expect(result).to be_nil end diff --git a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb index 0d53e61464f..fb15acf8f4e 100644 --- a/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb +++ b/spec/datadog/appsec/contrib/rack/reactive/response_spec.rb @@ -9,8 +9,7 @@ RSpec.describe Datadog::AppSec::Contrib::Rack::Reactive::Response do let(:engine) { Datadog::AppSec::Reactive::Engine.new } - let(:processor_context) { instance_double(Datadog::AppSec::Processor::Context) } - let(:context) { instance_double(Datadog::AppSec::Context, processor_context: processor_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } let(:body) { ['Ok'] } let(:headers) { { 'content-type' => 'text/html', 'set-cookie' => 'foo' } } @@ -19,7 +18,7 @@ body, 200, headers, - context: context, + context: appsec_context, ) end @@ -41,15 +40,13 @@ 'response.status', 'response.headers', ).and_call_original - expect(processor_context).to_not receive(:run) - described_class.subscribe(engine, processor_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end context 'waf arguments' do - before do - expect(engine).to receive(:subscribe).and_call_original - end + before { expect(engine).to receive(:subscribe).and_call_original } let(:waf_result) { double(:waf_result, status: :ok, timeout: false) } @@ -68,13 +65,15 @@ end it 'does call the waf context with the right arguments' do - expect(processor_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_arguments, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, processor_context) + + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, response) + expect(result).to be_nil end end @@ -82,7 +81,6 @@ it_behaves_like 'waf result' do let(:gateway) { response } - let(:waf_context) { processor_context } end end end diff --git a/spec/datadog/appsec/contrib/rails/reactive/action_spec.rb b/spec/datadog/appsec/contrib/rails/reactive/action_spec.rb index fad066ef7cf..6ba2e54e988 100644 --- a/spec/datadog/appsec/contrib/rails/reactive/action_spec.rb +++ b/spec/datadog/appsec/contrib/rails/reactive/action_spec.rb @@ -35,13 +35,13 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do expect(engine).to receive(:subscribe).with('rails.request.body', 'rails.request.route_params').and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -55,12 +55,12 @@ } waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_arguments, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, request) expect(result).to be_nil end diff --git a/spec/datadog/appsec/contrib/sinatra/reactive/routed_spec.rb b/spec/datadog/appsec/contrib/sinatra/reactive/routed_spec.rb index 690d1609ecb..5183002b0cd 100644 --- a/spec/datadog/appsec/contrib/sinatra/reactive/routed_spec.rb +++ b/spec/datadog/appsec/contrib/sinatra/reactive/routed_spec.rb @@ -30,13 +30,13 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do expect(engine).to receive(:subscribe).with('sinatra.request.route_params').and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -49,12 +49,12 @@ } waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_arguments, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, [request, routed_params]) expect(result).to be_nil end diff --git a/spec/datadog/appsec/monitor/reactive/set_user_spec.rb b/spec/datadog/appsec/monitor/reactive/set_user_spec.rb index 5e5472f6b2a..757fc5f9ed8 100644 --- a/spec/datadog/appsec/monitor/reactive/set_user_spec.rb +++ b/spec/datadog/appsec/monitor/reactive/set_user_spec.rb @@ -18,13 +18,13 @@ end describe '.subscribe' do - let(:waf_context) { double(:waf_context) } + let(:appsec_context) { instance_double(Datadog::AppSec::Context) } context 'not all addresses have been published' do it 'does not call the waf context' do expect(engine).to receive(:subscribe).with('usr.id').and_call_original - expect(waf_context).to_not receive(:run) - described_class.subscribe(engine, waf_context) + expect(appsec_context).to_not receive(:run_waf) + described_class.subscribe(engine, appsec_context) end end @@ -35,12 +35,12 @@ expected_waf_persisted_data = { 'usr.id' => 1 } waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).with( + expect(appsec_context).to receive(:run_waf).with( expected_waf_persisted_data, {}, Datadog.configuration.appsec.waf_timeout ).and_return(waf_result) - described_class.subscribe(engine, waf_context) + described_class.subscribe(engine, appsec_context) result = described_class.publish(engine, user) expect(result).to be_nil end diff --git a/spec/datadog/appsec/reactive/shared_examples.rb b/spec/datadog/appsec/reactive/shared_examples.rb index 352ae336781..4d1ebe37adc 100644 --- a/spec/datadog/appsec/reactive/shared_examples.rb +++ b/spec/datadog/appsec/reactive/shared_examples.rb @@ -6,8 +6,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :match, timeout: false, actions: []) - expect(waf_context).to receive(:run).and_return(waf_result) - described_class.subscribe(engine, waf_context) do |result| + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + described_class.subscribe(engine, appsec_context) do |result| expect(result).to eq(waf_result) end result = described_class.publish(engine, gateway) @@ -18,8 +18,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :match, timeout: false, actions: ['block']) - expect(waf_context).to receive(:run).and_return(waf_result) - described_class.subscribe(engine, waf_context) do |result| + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + described_class.subscribe(engine, appsec_context) do |result| expect(result).to eq(waf_result) end block = described_class.publish(engine, gateway) @@ -32,8 +32,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :ok, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end @@ -44,8 +44,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :invalid_call, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end @@ -56,8 +56,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :invalid_rule, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end @@ -68,8 +68,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :invalid_flow, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end @@ -80,8 +80,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :no_rule, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end @@ -92,8 +92,8 @@ expect(engine).to receive(:subscribe).and_call_original waf_result = double(:waf_result, status: :foo, timeout: false) - expect(waf_context).to receive(:run).and_return(waf_result) - expect { |b| described_class.subscribe(engine, waf_context, &b) }.not_to yield_control + expect(appsec_context).to receive(:run_waf).and_return(waf_result) + expect { |b| described_class.subscribe(engine, appsec_context, &b) }.not_to yield_control result = described_class.publish(engine, gateway) expect(result).to be_nil end diff --git a/spec/datadog/kit/appsec/events_spec.rb b/spec/datadog/kit/appsec/events_spec.rb index 7f2ff40ab04..200ea4812d0 100644 --- a/spec/datadog/kit/appsec/events_spec.rb +++ b/spec/datadog/kit/appsec/events_spec.rb @@ -9,15 +9,16 @@ let(:trace_op) { Datadog::Tracing::TraceOperation.new } shared_context 'uses AppSec context' do - before { allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) } + before do + allow(processor).to receive(:new_context).and_return(instance_double(Datadog::AppSec::Processor::Context)) + allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) + end + + let(:processor) { instance_double(Datadog::AppSec::Processor) } let(:appsec_span) { trace_op.build_span('root') } context 'when is present' do - let(:appsec_active_context) do - processor = instance_double('Datadog::Appsec::Processor') - - Datadog::AppSec::Context.new(trace_op, appsec_span, processor) - end + let(:appsec_active_context) { Datadog::AppSec::Context.new(trace_op, appsec_span, processor) } it 'sets tags on AppSec span' do event diff --git a/spec/datadog/kit/identity_spec.rb b/spec/datadog/kit/identity_spec.rb index d888eb437bf..1531faffd8d 100644 --- a/spec/datadog/kit/identity_spec.rb +++ b/spec/datadog/kit/identity_spec.rb @@ -212,12 +212,16 @@ end context 'appsec' do + before do + allow(processor).to receive(:new_context).and_return(instance_double(Datadog::AppSec::Processor::Context)) + allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) + end + + let(:processor) { instance_double(Datadog::AppSec::Processor) } let(:appsec_active_context) { nil } - before { allow(Datadog::AppSec).to receive(:active_context).and_return(appsec_active_context) } context 'when is enabled' do let(:appsec_active_context) do - processor = instance_double('Datadog::Appsec::Processor') trace = trace_op span = trace.build_span('root') From f8fe6ee19b0eef923ef99cbf78099b8e3e68ac1c Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 10 Jan 2025 16:49:24 +0100 Subject: [PATCH 10/11] Add new RSpec negate matcher not_change --- spec/spec_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 19f85ae593d..c493bbc86ff 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -295,6 +295,7 @@ def initialize(*args, &block) # Helper matchers RSpec::Matchers.define_negated_matcher :not_be, :be +RSpec::Matchers.define_negated_matcher :not_change, :change # The Ruby Timeout class uses a long-lived class-level thread that is never terminated. # Creating it early here ensures tests that tests that check for leaking threads are not From 92b64430a0a49524f977819a087b582edf559415 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 13 Jan 2025 10:27:29 +0100 Subject: [PATCH 11/11] Update RBS signatures --- sig/datadog/appsec/context.rbs | 37 ++++++++++++++++++++++++++++++++++ sig/datadog/appsec/event.rbs | 14 ++++++------- sig/datadog/appsec/ext.rbs | 12 ++++++----- sig/datadog/appsec/scope.rbs | 35 -------------------------------- 4 files changed, 51 insertions(+), 47 deletions(-) create mode 100644 sig/datadog/appsec/context.rbs delete mode 100644 sig/datadog/appsec/scope.rbs diff --git a/sig/datadog/appsec/context.rbs b/sig/datadog/appsec/context.rbs new file mode 100644 index 00000000000..522072741b2 --- /dev/null +++ b/sig/datadog/appsec/context.rbs @@ -0,0 +1,37 @@ +module Datadog + module AppSec + class Context + type waf_data = ::Hash[::String, untyped] + + @trace: Tracing::TraceOperation + + @span: Tracing::SpanOperation + + @security_engine: Processor + + @waf_runner: Processor::Context + + ActiveContextError: ::StandardError + + attr_reader trace: Tracing::TraceOperation + + attr_reader span: Tracing::SpanOperation + + attr_reader waf_runner: Processor::Context + + def self.activate: (Context context) -> Context + + def self.deactivate: () -> void + + def self.active: () -> Context + + def initialize: (Tracing::TraceOperation trace, Tracing::SpanOperation span, AppSec::Processor security_engine) -> void + + def run_waf: (waf_data persistent_data, waf_data ephemeral_data, ?Integer timeout) -> WAF::Result + + def run_rasp: (::Symbol _type, waf_data persistent_data, waf_data ephemeral_data, ?Integer timeout) -> WAF::Result + + def finalize: () -> void + end + end +end diff --git a/sig/datadog/appsec/event.rbs b/sig/datadog/appsec/event.rbs index b4b0e584513..713f73a2129 100644 --- a/sig/datadog/appsec/event.rbs +++ b/sig/datadog/appsec/event.rbs @@ -8,14 +8,14 @@ module Datadog MAX_ENCODED_SCHEMA_SIZE: Numeric MIN_SCHEMA_SIZE_FOR_COMPRESSION: Numeric - def self.record: (Datadog::Tracing::SpanOperation, *untyped events) -> (nil | untyped) + def self.record: (Tracing::SpanOperation, *untyped events) -> (nil | untyped) - def self.record_via_span: (Datadog::Tracing::SpanOperation, *untyped events) -> untyped + def self.record_via_span: (Tracing::SpanOperation, *untyped events) -> untyped def self.build_service_entry_tags: (Array[Hash[::Symbol, untyped]] event_group) -> Hash[::String, untyped] - - def self.tag_and_keep!: (Datadog::AppSec::Scope scope, Datadog::AppSec::WAF::Result waf_result) -> void - + + def self.tag_and_keep!: (Context scope, WAF::Result waf_result) -> void + private def self.compressed_and_base64_encoded: (untyped value) -> untyped @@ -23,8 +23,8 @@ module Datadog def self.json_parse: (untyped value) -> untyped def self.gzip: (untyped value) -> untyped - - def self.add_distributed_tags: (Datadog::Tracing::TraceOperation trace) -> void + + def self.add_distributed_tags: (Tracing::TraceOperation trace) -> void end end end diff --git a/sig/datadog/appsec/ext.rbs b/sig/datadog/appsec/ext.rbs index 2ac545ba1d3..8c4b59fb575 100644 --- a/sig/datadog/appsec/ext.rbs +++ b/sig/datadog/appsec/ext.rbs @@ -1,12 +1,14 @@ module Datadog module AppSec module Ext - INTERRUPT: Symbol - SCOPE_KEY: String + RASP_SQLI: ::Symbol + INTERRUPT: ::Symbol + CONTEXT_KEY: ::String + ACTIVE_CONTEXT_KEY: ::Symbol - TAG_APPSEC_ENABLED: String - TAG_APM_ENABLED: String - TAG_DISTRIBUTED_APPSEC_EVENT: String + TAG_APPSEC_ENABLED: ::String + TAG_APM_ENABLED: ::String + TAG_DISTRIBUTED_APPSEC_EVENT: ::String end end end diff --git a/sig/datadog/appsec/scope.rbs b/sig/datadog/appsec/scope.rbs deleted file mode 100644 index bde7a39b332..00000000000 --- a/sig/datadog/appsec/scope.rbs +++ /dev/null @@ -1,35 +0,0 @@ -module Datadog - module AppSec - class Scope - attr_reader trace: Datadog::Tracing::TraceOperation - - attr_reader service_entry_span: Datadog::Tracing::SpanOperation - - attr_reader processor_context: Datadog::AppSec::Processor::Context - - def initialize: (Datadog::Tracing::TraceOperation trace, Datadog::Tracing::SpanOperation service_entry_span, Datadog::AppSec::Processor::Context processor_context) -> void - - def finalize: () -> void - - def self.activate_scope: (Datadog::Tracing::TraceOperation trace, Datadog::Tracing::SpanOperation service_entry_span, Datadog::AppSec::Processor processor) -> Scope - - def self.deactivate_scope: () -> void - - def self.active_scope: () -> Scope - - private - - def self.active_scope=: (Scope scope) -> Scope - - def self.reset_active_scope: () -> void - - public - - class InactiveScopeError < StandardError - end - - class ActiveScopeError < StandardError - end - end - end -end