Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: Return message when sql is over the obfuscation limit #1149

Merged
2 changes: 1 addition & 1 deletion helpers/sql-obfuscation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ end

Make sure the `Instrumentation` class for your gem contains configuration options for:

- `:obfuscation_limit`: the length at which the obfuscated SQL string will be truncated.
- `:obfuscation_limit`: the length at which the SQL string will not be obfuscated
Example: `option :obfuscation_limit, default: 2000, validate: :integer`

If you want to add support for a new adapter, update the following constants to include keys for your adapter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,16 @@ def generate_regex(dialect)
# This is a SQL obfuscation utility intended for use in database adapter instrumentation.
#
# @param sql [String] The SQL to obfuscate.
# @param obfuscation_limit [optional Integer] The maximum length of an obfuscated sql statement.
# @param obfuscation_limit [optional Integer] the length at which the SQL string will not be obfuscated
# @param adapter [optional Symbol] the type of database adapter calling the method. `:default`, `:mysql` and `:postgres` are supported.
# @return [String] The SQL query string where the values are replaced with "?". When the sql statement exceeds the obufscation limit
# the first matched pair from the SQL statement will be returned, with an appended truncation message. If trunaction is unsuccessful,
# a string describing the error will be returned.
#
# @api public
def obfuscate_sql(sql, obfuscation_limit: 2000, adapter: :default)
return "SQL not obfuscated, query exceeds #{obfuscation_limit} characters" if sql.size > obfuscation_limit

regex = case adapter
when :mysql
MYSQL_COMPONENTS_REGEX
Expand All @@ -115,7 +117,6 @@ def obfuscate_sql(sql, obfuscation_limit: 2000, adapter: :default)
# https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/160
# https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/345
sql = OpenTelemetry::Common::Utilities.utf8_encode(sql, binary: true)
return truncate_statement(sql, regex, obfuscation_limit) if sql.size > obfuscation_limit

sql = sql.gsub(regex, PLACEHOLDER)
return 'Failed to obfuscate SQL query - quote characters remained after obfuscation' if CLEANUP_REGEX[adapter].match(sql)
Expand All @@ -124,16 +125,6 @@ def obfuscate_sql(sql, obfuscation_limit: 2000, adapter: :default)
rescue StandardError => e
OpenTelemetry.handle_error(message: 'Failed to obfuscate SQL', exception: e)
end

# @api private
def truncate_statement(sql, regex, limit)
first_match_index = sql.index(regex)
truncation_message = "SQL truncated (> #{limit} characters)"
return truncation_message unless first_match_index

truncated_sql = sql[..first_match_index - 1]
"#{truncated_sql}...\n#{truncation_message}"
end
end
end
end
12 changes: 2 additions & 10 deletions helpers/sql-obfuscation/test/helpers/sql_obfuscation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,9 @@ def test_named_arg_defaults_obfuscates
assert_equal(expected, result)
end

def test_obfuscation_limit_truncates_query_after_first_match
def test_obfuscation_returns_message_when_limit_is_reached
sql = "SELECT * from users where users.id = 1 and users.email = '[email protected]'"
expected = "SELECT * from users where users.id = ...\nSQL truncated (> 42 characters)"
result = OpenTelemetry::Helpers::SqlObfuscation.obfuscate_sql(sql, obfuscation_limit: 42)

assert_equal(expected, result)
end

def test_obfuscation_limit_truncates_when_query_not_encoded_with_utf8
sql = "SELECT * from 😄 where users.id = 1 and users.😄 = '[email protected]'"
expected = "SELECT * from where users.id = ...\nSQL truncated (> 42 characters)"
expected = 'SQL not obfuscated, query exceeds 42 characters'
result = OpenTelemetry::Helpers::SqlObfuscation.obfuscate_sql(sql, obfuscation_limit: 42)

assert_equal(expected, result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,20 +236,9 @@
describe 'with obfuscation_limit' do
let(:config) { { db_statement: :obfuscate, obfuscation_limit: 10 } }

it 'truncates SQL using config limit' do
it 'returns a message when the limit is reached' do
sql = "SELECT * from users where users.id = 1 and users.email = '[email protected]'"
obfuscated_sql = "SELECT * from users where users.id = ...\nSQL truncated (> 10 characters)"
expect do
client.query(sql)
end.must_raise Mysql2::Error

_(span.attributes['db.statement']).must_equal obfuscated_sql
end

it 'handles regex non-matches' do
sql = 'ALTER TABLE my_table DISABLE TRIGGER ALL;'
obfuscated_sql = 'SQL truncated (> 10 characters)'

obfuscated_sql = 'SQL not obfuscated, query exceeds 10 characters'
expect do
client.query(sql)
end.must_raise Mysql2::Error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,20 +297,9 @@
describe 'with obfuscation_limit' do
let(:config) { { db_statement: :obfuscate, obfuscation_limit: 10 } }

it 'truncates SQL using config limit' do
it 'returns a message when the limit is reached' do
sql = "SELECT * from users where users.id = 1 and users.email = '[email protected]'"
obfuscated_sql = "SELECT * from users where users.id = ...\nSQL truncated (> 10 characters)"
expect do
client.exec(sql)
end.must_raise PG::UndefinedTable

_(span.attributes['db.statement']).must_equal obfuscated_sql
end

it 'handles regex non-matches' do
sql = 'ALTER TABLE my_table DISABLE TRIGGER ALL;'
obfuscated_sql = 'SQL truncated (> 10 characters)'

obfuscated_sql = 'SQL not obfuscated, query exceeds 10 characters'
expect do
client.exec(sql)
end.must_raise PG::UndefinedTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,20 +323,9 @@
describe 'with obfuscation_limit' do
let(:config) { { db_statement: :obfuscate, obfuscation_limit: 10 } }

it 'truncates SQL using config limit' do
it 'returns a message when the limit is reached' do
sql = "SELECT * from users where users.id = 1 and users.email = '[email protected]'"
obfuscated_sql = "SELECT * from users where users.id = ...\nSQL truncated (> 10 characters)"
expect do
client.query(sql)
end.must_raise Trilogy::Error

_(span.attributes['db.statement']).must_equal obfuscated_sql
end

it 'handles regex non-matches' do
sql = 'ALTER TABLE my_table DISABLE TRIGGER ALL;'
obfuscated_sql = 'SQL truncated (> 10 characters)'

obfuscated_sql = 'SQL not obfuscated, query exceeds 10 characters'
expect do
client.query(sql)
end.must_raise Trilogy::Error
Expand Down
Loading