Back to Feed
article 2m read

A log cleanup that deleted an email address from the database too

A sweep to keep email addresses out of my webhook logs also pulled the address out of an invitation insert a few lines below a log call. A one-line follow-up put it back, with no test, and I still can't tell whether any blank rows were stored.

Article DepthPractice

Flow

Where an address can appear

  1. 1Log call

    Written to a logger or the console. Safe to remove or mask.

  2. 2Saved value

    Part of a database insert or update. Keep it, and test that it arrives.

  3. 3Lookup key

    Used to find records, like invitations for a new user. Keep it.

  4. 4Test expectation

    Checked by a test. Keep it, and see what the test is guarding.

Keeping email addresses out of my logs also took one out of the database.

The app gets webhooks from an outside login provider when an invitation is created, accepted or revoked, or a user signs up. Every handler wrote the person's email address into its logs, and the admin side had old debug prints full of addresses. One commit, labelled as code review fixes, took nearly all of that out.

The one line that wasn't a log

One handler logs that it's saving a local copy and then saves a new row, a few lines apart. Both lines had the address in them, and the sweep removed it from both. In a long diff of matching one-line deletions, the one in the save looked like every other one:

await invites.insert({ teamId, address, externalRef, state: "open" });

Take address out of that and the code would still build if the column is optional.

What that does to the data

I can't tell from the change whether the column allows empty values. If it does, the app stores an invitation that names nobody. If it doesn't, the save fails, and I would expect the webhook to report an error. I also don't know if the broken version ever ran on a server. Both outcomes are bad, because that row is my record of who was invited, and the admin app's pending list reads from it.

The address isn't decoration here. A test fix that same day made a lookup expect the lowercased address, after another handler switched to using it.

Put back the same day, still untested

A one-line commit the same day put the address back and called the removal an accident. It added no test.

If you're doing this kind of cleanup, three things help:

  • Only edit logging calls. Anything else in the diff gets a second look.
  • Test the save. Run the handler with a fake database and check the stored row has the address.
  • Hide personal fields inside the logger, so you never edit call sites at all.

The second one is the one I'd add before anything else, because the test suite already runs these handlers with fakes.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward