FinalizeAuditEventDestinationMigrations: no implicit conversion of nil into String
Summary
The FixIncompleteInstanceExternalAuditDestinations and FinalizeAuditEventDestinationMigrations background migrations may fail during an 18.4.2 or 18.4.3 with the error:
rake aborted!
StandardError: An error has occurred, all later migrations canceled:
no implicit conversion of nil into String
/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/crypto_helper.rb:39:in `block in aes256_gcm_decrypt'
The failure is caused by a nil value being passed to the encryption library while attempting to decrypt verification tokens.
The error originates in the decrypt_verification_token method. Specifically, the Gitlab::CryptoHelper.aes256_gcm_decrypt method received malformed or incomplete encrypted data, where the auth_tag value was nil, causing the encryptor gem to fail.
Workaround
- Once these are available, upgrade to backport versions in 18.4 and 18.5.
- Run the script below in
sudo gitlab-rails consoleto manually migrate the corrupted audit event destination records before running the actual database migration. When this is complete, re-run the migration withsudo gitlab:db:migrate
# Hotfix: Pre-migrate specific rows using attr_encrypted
module Hotfix
class InstanceExternalAuditEventDestination < ::ApplicationRecord
include ::Gitlab::EncryptedAttribute
self.table_name = 'audit_events_instance_external_audit_event_destinations'
attr_accessor :verification_token
attr_encrypted :verification_token,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
key: :db_key_base_32,
encode: false,
encode_iv: false
end
class InstanceStreamingDestination < ::ApplicationRecord
include ::Gitlab::EncryptedAttribute
self.table_name = 'audit_events_instance_external_streaming_destinations'
attr_accessor :secret_token
attr_encrypted :secret_token,
mode: :per_attribute_iv,
key: :db_key_base_32,
algorithm: 'aes-256-gcm',
encode: false,
encode_iv: false
end
end
destination_to_fix = Hotfix::InstanceExternalAuditEventDestination.where(stream_destination_id: nil)
destination_to_fix.each do |destination|
token = destination.verification_token rescue SecureRandom.base58(18)
token = SecureRandom.base58(18) if token.blank?
new_dest = Hotfix::InstanceStreamingDestination.new(
name: destination.name,
category: 0,
config: {
'url' => destination.destination_url,
'headers' => {
'X-Gitlab-Event-Streaming-Token' => {
'value' => token,
'active' => true
}
}
},
legacy_destination_ref: destination.id,
created_at: destination.created_at,
updated_at: destination.updated_at
)
new_dest.secret_token = token
new_dest.save!
destination.update_column(:stream_destination_id, new_dest.id)
puts "✓ Migrated #{destination.id} → #{new_dest.id}"
end
Edited by 🤖 GitLab Bot 🤖