Skip to content

Commit d997c55

Browse files
committed
[Fix rails#50604] Restore compatibility of ARE configs with eager loading mode
Configure ActiveRecord::Encryption (ARE) on ActiveRecord::Base (AR) loading, so that ARE configs are ready before AR models start using `encrypts` to declare encrypted attributes. This means that you can add ARE configurations in initializers, as long as you don't trigger the loading of ActiveRecord::Base or your AR models in prior initializers.
1 parent f5910f7 commit d997c55

File tree

3 files changed

+88
-10
lines changed

3 files changed

+88
-10
lines changed

activerecord/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Fix an issue where `ActiveRecord::Encryption` configurations are not ready before the loading
2+
of Active Record models, when an application is eager loaded. As a result, encrypted attributes
3+
could be misconfigured in some cases.
4+
5+
*Maxime Réty*
6+
17
* Deprecate defining an `enum` with keyword arguments.
28

39
```ruby

activerecord/lib/active_record/railtie.rb

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -378,23 +378,20 @@ class Railtie < Rails::Railtie # :nodoc:
378378
end
379379

380380
initializer "active_record_encryption.configuration" do |app|
381-
auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
382-
383-
config.after_initialize do |app|
381+
ActiveSupport.on_load(:active_record) do
384382
ActiveRecord::Encryption.configure \
385383
primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
386384
deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
387385
key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
388-
**config.active_record.encryption
386+
**app.config.active_record.encryption
389387

388+
auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
390389
auto_filtered_parameters.enable if ActiveRecord::Encryption.config.add_to_filter_parameters
391390

392-
ActiveSupport.on_load(:active_record) do
393-
# Support extended queries for deterministic attributes and validations
394-
if ActiveRecord::Encryption.config.extend_queries
395-
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
396-
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
397-
end
391+
# Support extended queries for deterministic attributes and validations
392+
if ActiveRecord::Encryption.config.extend_queries
393+
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
394+
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
398395
end
399396
end
400397

railties/test/application/configuration_test.rb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ def self.safe_list_sanitizer
3131
end
3232
end
3333

34+
class ::MyCustomKeyProvider
35+
attr_reader :primary_key
36+
def initialize(primary_key); @primary_key = primary_key; end
37+
end
38+
39+
class ::MyOldKeyProvider; end
40+
3441
module ApplicationTests
3542
class ConfigurationTest < ActiveSupport::TestCase
3643
include ActiveSupport::Testing::Isolation
@@ -3819,6 +3826,74 @@ class Post < ActiveRecord::Base
38193826
assert_not_includes ActiveRecord::Base.filter_attributes, :content
38203827
end
38213828

3829+
test "ActiveRecord::Encryption.config is ready for encrypted attributes when app is lazy loaded" do
3830+
add_to_config <<-RUBY
3831+
config.enable_reloading = false
3832+
config.eager_load = false
3833+
RUBY
3834+
3835+
app_file "config/initializers/active_record.rb", <<-RUBY
3836+
Rails.application.config.active_record.encryption.primary_key = "dummy_key"
3837+
Rails.application.config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]
3838+
3839+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
3840+
ActiveRecord::Migration.verbose = false
3841+
ActiveRecord::Schema.define(version: 1) do
3842+
create_table :posts do |t|
3843+
t.string :content
3844+
end
3845+
end
3846+
3847+
ActiveRecord::Base.connection.schema_cache.add("posts")
3848+
RUBY
3849+
3850+
app_file "app/models/post.rb", <<-RUBY
3851+
class Post < ActiveRecord::Base
3852+
encrypts :content, key_provider: MyCustomKeyProvider.new(ActiveRecord::Encryption.config.primary_key)
3853+
end
3854+
RUBY
3855+
3856+
app "development"
3857+
3858+
assert_kind_of ::MyOldKeyProvider, Post.attribute_types["content"].previous_schemes.first.key_provider
3859+
assert_kind_of ::MyCustomKeyProvider, Post.attribute_types["content"].scheme.key_provider
3860+
assert_equal "dummy_key", Post.attribute_types["content"].scheme.key_provider.primary_key
3861+
end
3862+
3863+
test "ActiveRecord::Encryption.config is ready for encrypted attributes when app is eager loaded" do
3864+
add_to_config <<-RUBY
3865+
config.enable_reloading = false
3866+
config.eager_load = true
3867+
RUBY
3868+
3869+
app_file "app/models/post.rb", <<-RUBY
3870+
class Post < ActiveRecord::Base
3871+
encrypts :content, key_provider: MyCustomKeyProvider.new(ActiveRecord::Encryption.config.primary_key)
3872+
end
3873+
RUBY
3874+
3875+
app_file "config/initializers/active_record.rb", <<-RUBY
3876+
Rails.application.config.active_record.encryption.primary_key = "dummy_key"
3877+
Rails.application.config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]
3878+
3879+
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
3880+
ActiveRecord::Migration.verbose = false
3881+
ActiveRecord::Schema.define(version: 1) do
3882+
create_table :posts do |t|
3883+
t.string :content
3884+
end
3885+
end
3886+
3887+
ActiveRecord::Base.connection.schema_cache.add("posts")
3888+
RUBY
3889+
3890+
app "production"
3891+
3892+
assert_kind_of ::MyOldKeyProvider, Post.attribute_types["content"].previous_schemes.first&.key_provider
3893+
assert_kind_of ::MyCustomKeyProvider, Post.attribute_types["content"].scheme.key_provider
3894+
assert_equal "dummy_key", Post.attribute_types["content"].scheme.key_provider.primary_key
3895+
end
3896+
38223897
test "ActiveStorage.routes_prefix can be configured via config.active_storage.routes_prefix" do
38233898
app_file "config/environments/development.rb", <<-RUBY
38243899
Rails.application.configure do

0 commit comments

Comments
 (0)