Add detumbled_email column to emails table

What does this MR do and why?

Related to: https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/806

In preparation for onboarding email intelligence from Arkose, our third-party user risk vendor, we are adding the detumbled_email field to the emails table. Once email intelligence is onboarded, we can use this new field to identify abusive users with the same email address and perform mitigative actions against all accounts.

For context:

Some providers let users create multiple email address aliases by adding specific symbols to their main email address. For example, in GMail you can insert periods in the email handle and append “+” and an additional string to your address. So an email_address value of e.n.ginee.ri.ng1234+suffix@gmail.com is detumbled back to engineering1234@gmail.com. We also account for other websites with slightly different detumbling rules.

Store this as the primary version of the email address the user provided you. This provides a much better aggregation method to help understand whether the same user is coming back to your platform multiple times to abuse a certain offer.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

Migration output

▶ bundle exec rake db:migrate
main: == [advisory_lock_connection] object_id: 130720, pg_backend_pid: 1694786
main: == 20240716215128 AddDetumbledEmailToEmails: migrating ========================
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- add_column(:emails, :detumbled_email, :text, {:if_not_exists=>true})
main:    -> 0.0063s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- transaction_open?(nil)
main:    -> 0.0000s
main: -- execute("ALTER TABLE emails\nADD CONSTRAINT check_319f6999dc\nCHECK ( char_length(detumbled_email) <= 255 )\nNOT VALID;\n")
main:    -> 0.0007s
main: -- execute("SET statement_timeout TO 0")
main:    -> 0.0002s
main: -- execute("ALTER TABLE emails VALIDATE CONSTRAINT check_319f6999dc;")
main:    -> 0.0003s
main: -- execute("RESET statement_timeout")
main:    -> 0.0002s
main: == 20240716215128 AddDetumbledEmailToEmails: migrated (0.0231s) ===============

main: == [advisory_lock_connection] object_id: 130720, pg_backend_pid: 1694786


▶ bundle exec rake db:migrate:down:main VERSION=20240716215128
main: == [advisory_lock_connection] object_id: 130380, pg_backend_pid: 1692718
main: == 20240716215128 AddDetumbledEmailToEmails: reverting ========================
main: -- remove_column(:emails, :detumbled_email, {:if_exists=>true})
main:    -> 0.0092s
main: == 20240716215128 AddDetumbledEmailToEmails: reverted (0.0139s) ===============

main: == [advisory_lock_connection] object_id: 130380, pg_backend_pid: 1692718

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

Edited by Ian Anderson

Merge request reports

Loading