diff --git a/app/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task.rb b/app/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task.rb new file mode 100644 index 000000000..396aa946d --- /dev/null +++ b/app/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Maintenance + class CopySuperAdminOtpSecretToRails7EncryptedAttrTask < MaintenanceTasks::Task + # Cette tâche finalise la mise à niveau vers devies-two-factor 5 + # qui utilise les encrypted attributes de Rails 7. + # Elle copie les secrets OTP des super admins vers la nouvelle colonne + # avant une suppression plus tard des anciennes colonnes. + # Plus d'informations : https://github.com/devise-two-factor/devise-two-factor/blob/main/UPGRADING.md + # Introduit 2024-08-29, https://github.com/demarches-simplifiees/demarches-simplifiees.fr/pull/10722 + def collection + SuperAdmin.all + end + + def process(super_admin) + # From https://github.com/devise-two-factor/devise-two-factor/blob/main/UPGRADING.md + otp_secret = super_admin.otp_secret # read from otp_secret column, fall back to legacy columns if new column is empty + # This is NOOP when otp_secret column has already the same value + super_admin.update!(otp_secret: otp_secret) + end + + def count + SuperAdmin.count + end + end +end diff --git a/spec/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task_spec.rb b/spec/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task_spec.rb new file mode 100644 index 000000000..51e176b5e --- /dev/null +++ b/spec/tasks/maintenance/copy_super_admin_otp_secret_to_rails7_encrypted_attr_task_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "rails_helper" + +module Maintenance + RSpec.describe CopySuperAdminOtpSecretToRails7EncryptedAttrTask do + describe "#process" do + let(:super_admin) { create(:super_admin) } + subject(:process) { described_class.process(super_admin) } + + context "when otp_secret is not set" do + let(:legacy_otp_secret) { "legacy_secret" } + + before do + super_admin.update_column(:otp_secret, nil) + allow(super_admin).to receive(:otp_secret).and_return(legacy_otp_secret) + end + + it "copies the legacy otp_secret to the new column" do + expect { process }.to change { super_admin.reload.read_attribute(:otp_secret) }.from(nil).to(legacy_otp_secret) + end + end + end + end +end