Skip to content

Commit bef825e

Browse files
committed
Merge PR rails#42006
2 parents 269f672 + 17c7607 commit bef825e

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

activerecord/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
* Filter attributes in SQL logs
2+
3+
Previously, SQL queries in logs containing `ActiveRecord::Base.filter_attributes` were not filtered.
4+
5+
Now, the filter attributes will be masked `[FILTERED]` in the logs when `prepared_statement` is enabled.
6+
7+
```
8+
# Before:
9+
Foo Load (0.2ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "hello"], ["LIMIT", 1]]
10+
11+
# After:
12+
Foo Load (0.5ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "[FILTERED]"], ["LIMIT", 1]]
13+
```
14+
15+
*Aishwarya Subramanian*
16+
117
* Remove deprecated `Tasks::DatabaseTasks.spec`.
218
319
*Rafael Mendonça França*

activerecord/lib/active_record/log_subscriber.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def sql(event)
5151

5252
binds = []
5353
payload[:binds].each_with_index do |attr, i|
54-
binds << render_bind(attr, casted_params[i])
54+
attribute_name = attr.respond_to?(:name) ? attr.name : attr[i].name
55+
filtered_params = filter(attribute_name, casted_params[i])
56+
57+
binds << render_bind(attr, filtered_params)
5558
end
5659
binds = binds.inspect
5760
binds.prepend(" ")
@@ -135,6 +138,10 @@ def log_query_source
135138
def extract_query_source_location(locations)
136139
backtrace_cleaner.clean(locations.lazy).first
137140
end
141+
142+
def filter(name, value)
143+
ActiveRecord::Base.inspection_filter.filter_param(name, value)
144+
end
138145
end
139146
end
140147

activerecord/test/cases/bind_parameter_test.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,16 @@ def test_nested_unprepared_statements
182182
assert_predicate @connection, :prepared_statements?
183183
end
184184

185+
def test_binds_with_filtered_attributes
186+
ActiveRecord::Base.filter_attributes = [:auth]
187+
188+
binds = [Relation::QueryAttribute.new("auth_token", "abcd", Type::String.new)]
189+
190+
assert_filtered_log_binds(binds)
191+
192+
ActiveRecord::Base.filter_attributes = []
193+
end
194+
185195
private
186196
def assert_bind_params_to_sql
187197
table = Author.quoted_table_name
@@ -270,6 +280,38 @@ def debug(str)
270280
logger.sql(event)
271281
assert_match %r(\[\["id", 10\]\]\z), logger.debugs.first
272282
end
283+
284+
def assert_filtered_log_binds(binds)
285+
payload = {
286+
name: "SQL",
287+
sql: "select * from users where auth_token = ?",
288+
binds: binds,
289+
type_casted_binds: @connection.send(:type_casted_binds, binds)
290+
}
291+
292+
event = ActiveSupport::Notifications::Event.new(
293+
"foo",
294+
Time.now,
295+
Time.now,
296+
123,
297+
payload)
298+
299+
logger = Class.new(ActiveRecord::LogSubscriber) {
300+
attr_reader :debugs
301+
302+
def initialize
303+
super
304+
@debugs = []
305+
end
306+
307+
def debug(str)
308+
@debugs << str
309+
end
310+
}.new
311+
312+
logger.sql(event)
313+
assert_match %r([[auth_token, [FILTERED]]]), logger.debugs.first
314+
end
273315
end
274316
end
275317
end

0 commit comments

Comments
 (0)