Skip to content

Job arguments and request params reach the errors database and email unfiltered #117

Open

Description

@namolnad

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 with body:, to: or url: 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 email

The 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:

  1. 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.
  2. Record arguments only when they're GlobalID-able records (the gid is already recorded), and use a placeholder for anything else.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions