diff options
author | Nick Thomas <nick@gitlab.com> | 2018-11-22 19:17:08 +0300 |
---|---|---|
committer | Nick Thomas <nick@gitlab.com> | 2018-11-27 21:24:18 +0300 |
commit | 6ddefe7cada5268469561c70a8557cf1545684b2 (patch) | |
tree | 3f54240e3472da4c4f6004ae19da20f78ba476f3 /lib/gitlab/background_migration | |
parent | 0afce35d65aa433d221e41632c6d8095ab68c39f (diff) |
Correctly handle data-loss scenarios when encrypting columns
If the EncryptColumns background migration runs in a sidekiq with a
stale view of the database schema, or when the purported destination
columns don't actually exist, data loss can result. Attempt to work
around these issues by reloading schema information before running
the migration, and raising errors if the model reports that any of its
source or destination columns are missing.
Diffstat (limited to 'lib/gitlab/background_migration')
-rw-r--r-- | lib/gitlab/background_migration/encrypt_columns.rb | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/lib/gitlab/background_migration/encrypt_columns.rb b/lib/gitlab/background_migration/encrypt_columns.rb index 0d333e47e7b..bd5f12276ab 100644 --- a/lib/gitlab/background_migration/encrypt_columns.rb +++ b/lib/gitlab/background_migration/encrypt_columns.rb @@ -17,6 +17,12 @@ module Gitlab class EncryptColumns def perform(model, attributes, from, to) model = model.constantize if model.is_a?(String) + + # If sidekiq hasn't undergone a restart, its idea of what columns are + # present may be inaccurate, so ensure this is as fresh as possible + model.reset_column_information + model.define_attribute_methods + attributes = expand_attributes(model, Array(attributes).map(&:to_sym)) model.transaction do @@ -41,6 +47,14 @@ module Gitlab raise "Couldn't determine encrypted column for #{klass}##{attribute}" if crypt_column_name.nil? + raise "#{klass} source column: #{attribute} is missing" unless + klass.column_names.include?(attribute.to_s) + + # Running the migration without the destination column being present + # leads to data loss + raise "#{klass} destination column: #{crypt_column_name} is missing" unless + klass.column_names.include?(crypt_column_name.to_s) + [attribute, crypt_column_name] end |