Skip to content

Commit

Permalink
Merge branch 'master' into appsec-56456-add-telemetry-metrics-to-rasp…
Browse files Browse the repository at this point in the history
…-calls
  • Loading branch information
Strech authored Jan 24, 2025
2 parents 9e07af4 + a72b341 commit a214cff
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 144 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ orbs:
name: Upload JUnit reports to Datadog
when: always
command: |
sed -i 's/file="\.\//file="/g' tmp/rspec/*.xml
ls -l tmp/rspec/*.xml
curl -L --fail --retry 3 "https://github.com/DataDog/datadog-ci/releases/latest/download/datadog-ci_linux-x64" --output "/usr/local/bin/datadog-ci" && chmod +x /usr/local/bin/datadog-ci
Expand Down
60 changes: 30 additions & 30 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
* @DataDog/ruby-guild

# Public Documentation
/docs/Compatibility.md @DataDog/documentation
/docs/GettingStarted.md @DataDog/documentation
docs/Compatibility.md @DataDog/documentation
docs/GettingStarted.md @DataDog/documentation

# Library
/lib/datadog/appsec/ @DataDog/asm-ruby
/lib/datadog/appsec.rb @DataDog/asm-ruby
/lib/datadog/tracing/ @DataDog/tracing-ruby
/lib/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
/lib/datadog/tracing.rb @DataDog/tracing-ruby
/lib/datadog/opentelemetry/ @DataDog/tracing-ruby
/lib/datadog/opentelemetry.rb @DataDog/tracing-ruby
/lib-injection/ @DataDog/tracing-ruby
/lib/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
/lib/datadog/profiling.rb @DataDog/profiling-rb @DataDog/ruby-guild
/ext/ @DataDog/profiling-rb @DataDog/ruby-guild
lib/datadog/appsec/ @DataDog/asm-ruby
lib/datadog/appsec.rb @DataDog/asm-ruby
lib/datadog/tracing/ @DataDog/tracing-ruby
lib/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
lib/datadog/tracing.rb @DataDog/tracing-ruby
lib/datadog/opentelemetry/ @DataDog/tracing-ruby
lib/datadog/opentelemetry.rb @DataDog/tracing-ruby
lib-injection/ @DataDog/tracing-ruby
lib/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
lib/datadog/profiling.rb @DataDog/profiling-rb @DataDog/ruby-guild
ext/ @DataDog/profiling-rb @DataDog/ruby-guild

# RBS signatures
/sig/datadog/appsec/ @DataDog/asm-ruby
/sig/datadog/appsec.rbs @DataDog/asm-ruby
/sig/datadog/tracing/ @DataDog/tracing-ruby
/sig/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
/sig/datadog/tracing.rbs @DataDog/tracing-ruby
/sig/datadog/opentelemetry/ @DataDog/tracing-ruby
/sig/datadog/opentelemetry.rbs @DataDog/tracing-ruby
/sig/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
/sig/datadog/profiling.rbs @DataDog/profiling-rb @DataDog/ruby-guild
sig/datadog/appsec/ @DataDog/asm-ruby
sig/datadog/appsec.rbs @DataDog/asm-ruby
sig/datadog/tracing/ @DataDog/tracing-ruby
sig/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
sig/datadog/tracing.rbs @DataDog/tracing-ruby
sig/datadog/opentelemetry/ @DataDog/tracing-ruby
sig/datadog/opentelemetry.rbs @DataDog/tracing-ruby
sig/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
sig/datadog/profiling.rbs @DataDog/profiling-rb @DataDog/ruby-guild

# Specs
/spec/datadog/appsec/ @DataDog/asm-ruby
/spec/datadog/tracing/ @DataDog/tracing-ruby
/spec/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
/spec/datadog/tracing_spec.rb @DataDog/tracing-ruby
/spec/datadog/opentelemetry/ @DataDog/tracing-ruby
/spec/datadog/opentelemetry_spec.rb @DataDog/tracing-ruby
/spec/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
/spec/datadog/profiling_spec.rb @DataDog/profiling-rb @DataDog/ruby-guild
spec/datadog/appsec/ @DataDog/asm-ruby
spec/datadog/tracing/ @DataDog/tracing-ruby
spec/datadog/tracing/contrib/ @DataDog/apm-idm-ruby
spec/datadog/tracing_spec.rb @DataDog/tracing-ruby
spec/datadog/opentelemetry/ @DataDog/tracing-ruby
spec/datadog/opentelemetry_spec.rb @DataDog/tracing-ruby
spec/datadog/profiling/ @DataDog/profiling-rb @DataDog/ruby-guild
spec/datadog/profiling_spec.rb @DataDog/profiling-rb @DataDog/ruby-guild
4 changes: 4 additions & 0 deletions lib/datadog/appsec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ def enabled?
Datadog.configuration.appsec.enabled
end

def rasp_enabled?
Datadog.configuration.appsec.rasp_enabled
end

def active_context
Datadog::AppSec::Context.active
end
Expand Down
9 changes: 9 additions & 0 deletions lib/datadog/appsec/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ def self.add_settings!(base)
end
end

# RASP or Runtime Application Self-Protection
# is a collection of techniques and heuristics aimed at detecting malicious inputs and preventing
# any potential side-effects on the application resulting from the use of said malicious inputs.
option :rasp_enabled do |o|
o.type :bool, nilable: true
o.env 'DD_APPSEC_RASP_ENABLED'
o.default true
end

option :ruleset do |o|
o.env 'DD_APPSEC_RULES'
o.default :recommended
Expand Down
2 changes: 2 additions & 0 deletions lib/datadog/appsec/contrib/active_record/instrumentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ module Instrumentation
module_function

def detect_sql_injection(sql, adapter_name)
return unless AppSec.rasp_enabled?

context = AppSec.active_context
return unless context

Expand Down
22 changes: 22 additions & 0 deletions spec/datadog/appsec/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ def patcher
end
end

describe '#rasp_enabled' do
context 'when DD_APPSEC_RASP_ENABLED' do
around do |example|
ClimateControl.modify('DD_APPSEC_RASP_ENABLED' => rasp_enabled_env_var) do
example.run
end
end

context 'is not defined' do
let(:rasp_enabled_env_var) { nil }

it { expect(settings.appsec.rasp_enabled).to eq(true) }
end

context 'is defined' do
let(:rasp_enabled_env_var) { 'false' }

it { expect(settings.appsec.rasp_enabled).to eq(false) }
end
end
end

describe '#instrument' do
let(:registry) { {} }
let(:integration_name) { :fake }
Expand Down
96 changes: 60 additions & 36 deletions spec/datadog/appsec/contrib/active_record/mysql2_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,46 +64,70 @@
processor.finalize
end

it 'calls waf with correct arguments when querying using .where' do
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'",
'server.db.system' => 'mysql2'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.where(name: 'Bob').to_a
end
context 'when RASP is disabled' do
before do
allow(Datadog::AppSec).to receive(:rasp_enabled?).and_return(false)
end

it 'calls waf with correct arguments when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'",
'server.db.system' => 'mysql2'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
it 'does not call waf when querying using .where' do
expect(Datadog::AppSec.active_context).not_to receive(:run_rasp)

User.where(name: 'Bob').to_a
end

it 'does not call waf when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).not_to receive(:run_rasp)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
end
end

it 'adds an event to processor context if waf result is a match' do
result = Datadog::AppSec::SecurityEngine::Result::Match.new(
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
)
context 'when RASP is enabled' do
before do
allow(Datadog::AppSec).to receive(:rasp_enabled?).and_return(true)
end

it 'calls waf with correct arguments when querying using .where' do
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'",
'server.db.system' => 'mysql2'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.where(name: 'Bob').to_a
end

expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result)
expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original
it 'calls waf with correct arguments when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'",
'server.db.system' => 'mysql2'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
end

User.where(name: 'Bob').to_a
it 'adds an event to processor context if waf result is a match' do
result = Datadog::AppSec::SecurityEngine::Result::Match.new(
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
)

expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result)
expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original

User.where(name: 'Bob').to_a
end
end
end
108 changes: 66 additions & 42 deletions spec/datadog/appsec/contrib/active_record/postgresql_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,52 +65,76 @@
processor.finalize
end

it 'calls waf with correct arguments when querying using .where' do
expected_db_statement = if PlatformHelpers.jruby?
'SELECT "users".* FROM "users" WHERE "users"."name" = ?'
else
'SELECT "users".* FROM "users" WHERE "users"."name" = $1'
end

expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => expected_db_statement,
'server.db.system' => 'postgresql'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.where(name: 'Bob').to_a
end
context 'when RASP is disabled' do
before do
allow(Datadog::AppSec).to receive(:rasp_enabled?).and_return(false)
end

it 'calls waf with correct arguments when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'",
'server.db.system' => 'postgresql'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
it 'does not call waf when querying using .where' do
expect(Datadog::AppSec.active_context).not_to receive(:run_rasp)

User.where(name: 'Bob').to_a
end

it 'does not call waf when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).not_to receive(:run_rasp)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
end
end

it 'adds an event to processor context if waf result is a match' do
result = Datadog::AppSec::SecurityEngine::Result::Match.new(
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
)
context 'when RASP is enabled' do
before do
allow(Datadog::AppSec).to receive(:rasp_enabled?).and_return(true)
end

it 'calls waf with correct arguments when querying using .where' do
expected_db_statement = if PlatformHelpers.jruby?
'SELECT "users".* FROM "users" WHERE "users"."name" = ?'
else
'SELECT "users".* FROM "users" WHERE "users"."name" = $1'
end

expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => expected_db_statement,
'server.db.system' => 'postgresql'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.where(name: 'Bob').to_a
end

expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result)
expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original
it 'calls waf with correct arguments when querying using .find_by_sql' do
expect(Datadog::AppSec.active_context).to(
receive(:run_rasp).with(
Datadog::AppSec::Ext::RASP_SQLI,
{},
{
'server.db.statement' => "SELECT * FROM users WHERE name = 'Bob'",
'server.db.system' => 'postgresql'
},
Datadog.configuration.appsec.waf_timeout
).and_call_original
)

User.find_by_sql("SELECT * FROM users WHERE name = 'Bob'").to_a
end

User.where(name: 'Bob').to_a
it 'adds an event to processor context if waf result is a match' do
result = Datadog::AppSec::SecurityEngine::Result::Match.new(
events: [], actions: {}, derivatives: {}, timeout: false, duration_ns: 0, duration_ext_ns: 0
)

expect(Datadog::AppSec.active_context).to receive(:run_rasp).and_return(result)
expect(Datadog::AppSec.active_context.events).to receive(:<<).and_call_original

User.where(name: 'Bob').to_a
end
end
end
Loading

0 comments on commit a214cff

Please sign in to comment.