Skip to content

Convert credit card validation data to hashes in database

Hinam Mehra requested to merge 413525-add-credit-card-hashes into master

What does this MR do and why?

  • Resolves sub-task 1 of https://gitlab.com/gitlab-org/gitlab/-/issues/413525
  • Create 4 columns, last_digits_hash, expiration_date_hash, holder_name_hash and network_hash to store the data we currently have in the Users::CreditCardValidation table as hashes instead of plain-text.
  • Create a background migration to convert plain-text data into hashes.
  • Update Users::CreditCardValidation model to save hashed data when a record is created/updated
  • Update the Users::UpsertCreditCardValidationService to use save method to save records to the database, instead of upsert, since upsert doesn't instantiate the model.

Screenshots or screen recordings

db:migrate

main: == 20230815072912 AddHashesToCreditCardValidations: migrating =================
main: -- transaction_open?()
main:    -> 0.0000s
main: -- add_column(:user_credit_card_validations, :last_digits_hash, :text, {:if_not_exists=>true})
main:    -> 0.0050s
main: -- add_column(:user_credit_card_validations, :holder_name_hash, :text, {:if_not_exists=>true})
main:    -> 0.0030s
main: -- add_column(:user_credit_card_validations, :expiration_date_hash, :text, {:if_not_exists=>true})
main:    -> 0.0031s
main: -- add_column(:user_credit_card_validations, :network_hash, :text, {:if_not_exists=>true})
main:    -> 0.0028s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- execute("ALTER TABLE user_credit_card_validations\nADD CONSTRAINT check_f5c35b1a6e\nCHECK ( char_length(last_digits_hash) <= 44 )\nNOT VALID;\n")
main:    -> 0.0011s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- execute("ALTER TABLE user_credit_card_validations\nADD CONSTRAINT check_aca7c2607c\nCHECK ( char_length(holder_name_hash) <= 44 )\nNOT VALID;\n")
main:    -> 0.0010s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- execute("ALTER TABLE user_credit_card_validations\nADD CONSTRAINT check_83f1e2ace3\nCHECK ( char_length(expiration_date_hash) <= 44 )\nNOT VALID;\n")
main:    -> 0.0009s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- transaction_open?()
main:    -> 0.0000s
main: -- execute("ALTER TABLE user_credit_card_validations\nADD CONSTRAINT check_7721e1961a\nCHECK ( char_length(network_hash) <= 44 )\nNOT VALID;\n")
main:    -> 0.0008s
main: == 20230815072912 AddHashesToCreditCardValidations: migrated (0.0489s) ========
main: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: migrating =====
main: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: migrated (0.0535s) 

main: == [advisory_lock_connection] object_id: 38187840, pg_backend_pid: 10170
ci: == [advisory_lock_connection] object_id: 38188100, pg_backend_pid: 10172
ci: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: migrating =====
ci: -- The migration is skipped since it modifies the schemas: [:gitlab_main].
ci: -- This database can only apply migrations in one of the following schemas: [:gitlab_ci, :gitlab_internal, :gitlab_shared].
ci: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: migrated (0.0230s)

db:rollback

main: == 20230815072912 AddHashesToCreditCardValidations: reverting =================
main: -- transaction_open?()
main:    -> 0.0000s
main: -- remove_column(:user_credit_card_validations, :last_digits_hash, {:if_exists=>true})
main:    -> 0.0033s
main: -- remove_column(:user_credit_card_validations, :holder_name_hash, {:if_exists=>true})
main:    -> 0.0028s
main: -- remove_column(:user_credit_card_validations, :expiration_date_hash, {:if_exists=>true})
main:    -> 0.0025s
main: -- remove_column(:user_credit_card_validations, :network_hash, {:if_exists=>true})
main:    -> 0.0023s
main: == 20230815072912 AddHashesToCreditCardValidations: reverted (0.0186s) ========
main: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: reverting =====
main: == 20230821081603 QueueConvertCreditCardValidationDataToHashes: reverted (0.0516s)

Results of the db:gitlabcom-database-testing pipeline - !129350 (comment 1513858652)

How to set up and validate locally

  1. Run the migrations
  2. Create a credit card validation record in the rails console:
> Users::CreditCardValidation.create(user_id: 1, last_digits: 1111, credit_card_validated_at: Date.today, expiration_date: Date.today, holder_name: 'John Doe', network: 'Visa')

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #413525

Edited by Hinam Mehra

Merge request reports