Repository navigation
Keep Rails' parameter filtering working, and filter every value LogStruct logs - #16
Merged
Merged
Conversation
merge_rails_filter_parameters! copied Rails' filter_parameters into LogStruct's filters and then cleared Rails' list. Everything else that reads that list stopped filtering: request.filtered_parameters, Sentry's and other error reporters' parameter filters, ActionDispatch's request inspection and ActiveRecord's filter_attributes. Rails' list is now left in place, and values Rails has already replaced are logged as "[FILTERED]" instead of a second _filtered summary. ActiveRecord::Base.filter_attributes was also empty for a second reason: replace_rails_logger referenced ActiveRecord::Base, ActionController::Base, ActionMailer::Base, ActiveJob::Base and ActionView::Base during boot to set their loggers. Loading those classes that early runs their on_load hooks before the app's initializers, so ActiveRecord copied an empty filter_parameters into filter_attributes and inspected records showed passwords and tokens. The loggers are now set from on_load hooks, and the ActionMailer integration registers its prepends the same way.
process_values stops recursing after 20 levels so circular references can't loop forever, but it returned the remaining value untouched. Keys below that depth skipped filtering and string scrubbing, so a password or email nested deep enough was written to the log as is. The rescue at the end of process_values had the same problem: any error while processing a value logged the original value. Both paths now return a summary of the value (its class and size) instead. Hash and T::Struct log values were also symbolized with deep_symbolize_keys, which recursed forever on a circular hash before process_values ever saw it; symbolize_keys stops at the same depth. Fixes #15
json 3 rejects the quirks_mode option that ActiveSupport's JSON encoder passes to JSON.generate in every released Rails version up to 8.0.4, so a freshly generated test app raised ArgumentError on every to_json call. Rails main no longer passes it.
LogStruct turned Rails' filter_parameters entries into exact key names, so keys Rails filters by partial match (:passw filters user_password, :_key filters stripe_key) were logged in job arguments and logged Hashes. Symbols, Strings and Regexps now go through ActiveSupport::ParameterFilter, so they match the keys Rails matches. Merging again replaces the earlier list. Partial matches don't apply to the names of LogStruct's own fields at the top of a line, so Rails' default :_key doesn't filter GoodJob's cron_key. Exact names and LogStruct's own filters still do, and the fields' values are filtered as before. Rails' filter blocks may change the value they're given, as the Rails guides' example does, so they now get copies instead of the logged value. Tests restore the filters after each test, since several change them in place.
Structs, ActionController::Parameters and other objects were written by to_json without filtering or scrubbing, so a password in logged params was logged raw. The formatter now filters what as_json returns. A Hash that referred back to itself from two keys took exponential time and wrote a huge line, because only the depth limit stopped it. The formatter now tracks the Hashes and Arrays it's inside and summarizes a value that refers back to one of them.
The SQL logging integration checked ActiveRecord::Base for verbose_query_logs=, which loaded ActiveRecord::Base during setup and never matched, because the setting is on the ActiveRecord module.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 16
✨ Finishing Touches
Comment |
This was referenced Oct 17, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The first of twelve stacked PRs for 0.2.0. Merge them in order.
What this fixes
filter_parametersstayed empty. LogStruct copied Rails' list into its own filters and then cleared it, sorequest.filtered_parameters, error reporters' parameter filters and Rails' request inspection stopped filtering. Setting component loggers at boot also loadedActiveRecord::Basebefore the app's initializers, sofilter_attributeswas empty and inspected records showed passwords and tokens. Rails' list is now left alone, and the loggers are set from load hooks.:passwdidn't filteruser_password. Symbols, Strings and Regexps now go throughActiveSupport::ParameterFilter, so they match what Rails matches. Partial matches don't apply to LogStruct's own top-level field names (Rails' default:_keywould filter GoodJob'scron_key). Rails' filter blocks get copies of the key and value.ActionController::Parametersand other objects were serialized without filtering. The formatter now filters whatas_jsonreturns.ActiveRecordmodule, without loadingActiveRecord::Base.Also pins
jsonbelow 3 in the Rails test app (json 3 rejects an option ActiveSupport passes to it).Addresses #15.
Testing
Every regression test fails without its fix. Sorbet and the unit suite (284 tests) pass at this branch's tip.
Stack for 0.2.0, merged in order: #16 → #17 → #18 → #19 → #20 → #21 → #22 → #23 → #24 → #25 → #26 → #27
Summary by CodeRabbit
New Features
[FILTERED], and custom filters can still be configured.Documentation