Repository navigation
Job arguments and request params reach the errors database and email unfiltered #117
Description
Since 0.9.0 (#115), an occurrence records the failing job's arguments and the failing request's params, and the error email shows them. That's useful context, but the only filter is config.filter_parameters, which matches keys. Anything private that isn't under a filtered key goes into the errors database and out by email:
- positional job arguments (
SomeJob.perform_later(user, message_text)) - keyword arguments with ordinary names (
body:,content:,note:,entries:) - every mail delivery job, because
ActionMailer::MailDeliveryJob's arguments are the mail's own params. A mailer called withbody:,to:orurl:puts the email's contents, recipients or a link with a token in it into the occurrence. - webhook params (a Stripe or Shopify payload, with customers' names and addresses)
Repro, in an app with send_emails on:
class NotifyMailer < ApplicationMailer
def note(to:, body:)
raise "boom"
end
end
NotifyMailer.note(to: "someone@example.com", body: "something private").deliver_later
# once the job runs, SolidErrors::Occurrence.last.context[:arguments] contains
# "someone@example.com" and "something private", and so does the error emailThe same goes for a controller action that raises with params[:message][:content] set.
Across four of my apps that I checked, all of them pass user content through job or mailer arguments under keys filter_parameters doesn't cover. In one of them that included a live user invitation URL with auth params. Adding every such key to filter_parameters may not always be workable: positional arguments have no key, and the list also controls what the logs show.
Possible shapes, in rough order of how small they are:
- A switch to record the job class, id and queue and the
Controller#action, but not the arguments or params:config.solid_errors.record_arguments = false, or the same for params. That's what we've ended up doing. - Record arguments only when they're GlobalID-able records (the gid is already recorded), and use a placeholder for anything else.
- Leave the default as it is, and add a README warning that arguments and params are stored and emailed, filtered only by
filter_parameters.
What we do today, in case it's useful: readable_context only fills in :arguments and :params when the context doesn't already have them. So a before_perform and a before_action that call Rails.error.set_context(arguments: "[withheld]") / set_context(params: "[withheld]") take precedence, and they cover the framework's own jobs and controllers too. That works, but it depends on the ||=, so it would be good to know whether that's intended to stay.
I'm happy to open a PR for whichever shape you'd prefer.
Also, if it's helpful, here is a repo I've created for my apps with common settings/thin layers on top of SolidErrors. If you want anything from there upstream, feel free to pull any of that in.
Activity