commit d8005c42c665c16d9d64b838252c1dd1118f78c6
Author: Ondřej Ezr <oezr@redhat.com>
Date:   Tue Mar 8 14:00:13 2022 +0100

    Fixes #34573 - encrypt DSL setting values
    
    DSL setting values were not properly encrypted as the encryption flag has not been propagated into DB model.

diff --git a/app/models/setting.rb b/app/models/setting.rb
index 78dcfba37..787d04a11 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -105,7 +105,7 @@ class Setting < ApplicationRecord
   def value=(v)
     v = v.to_yaml unless v.nil?
     # the has_attribute is for enabling DB migrations on older versions
-    if has_attribute?(:encrypted) && encrypted
+    if setting_definition&.encrypted?
       # Don't re-write the attribute if the current encrypted value is identical to the new one
       current_value = self[:value]
       unless is_decryptable?(current_value) && decrypt_field(current_value) == v
@@ -345,9 +345,13 @@ class Setting < ApplicationRecord
     readonly! if !new_record? && has_readonly_value?
   end
 
-  def refresh_registry_value
+  def setting_definition
     return unless Foreman.settings.ready?
-    Foreman.settings.find(name)&.tap do |definition|
+    Foreman.settings.find(name)
+  end
+
+  def refresh_registry_value
+    setting_definition&.tap do |definition|
       definition.updated_at = updated_at
       definition.value_from_db = value
     end
diff --git a/test/models/setting_test.rb b/test/models/setting_test.rb
index 360325296..deff70da6 100644
--- a/test/models/setting_test.rb
+++ b/test/models/setting_test.rb
@@ -30,9 +30,8 @@ class SettingTest < ActiveSupport::TestCase
   end
 
   test "encrypted value is saved encrypted when created" do
-    setting = Setting.create(:name => "foo", :value => 5, :default => 5, :description => "test foo", :encrypted => true)
-    setting.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
-    setting.value = "123456"
+    Setting.any_instance.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
+    setting = Foreman.settings.set_user_value('root_pass', '123456')
     as_admin do
       assert setting.save
     end
@@ -40,21 +39,22 @@ class SettingTest < ActiveSupport::TestCase
   end
 
   test "#value= with previously unencrypted value is encrypted when set" do
-    setting = Setting.create(name: 'encrypted', value: 'first', default: 'test', description: 'Test', encrypted: false)
-    setting.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
-    setting.encrypted = true
-    setting.value = 'new'
+    Setting['foreman_url'] = 'http://unencrypted-foreman.example.net'
+    Setting.any_instance.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
+    Foreman.settings.find('foreman_url').encrypted = true
+    setting = Foreman.settings.set_user_value('foreman_url', 'http://new.example.net')
     assert_difference 'setting.audits.count' do
       as_admin { setting.save! }
     end
     assert_includes setting.read_attribute(:value), EncryptValue::ENCRYPTION_PREFIX
-    assert_equal 'new', setting.value
+    assert_equal 'http://new.example.net', setting.value
   end
 
   test "update an encrypted value should saved encrypted in db with audit, and decrypted while reading" do
-    setting = settings(:attributes63)
-    setting.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
-    setting.value = '123456'
+    Setting['foreman_url'] = 'http://unencrypted-foreman.example.net'
+    Setting.any_instance.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
+    Foreman.settings.find('foreman_url').encrypted = true
+    setting = Foreman.settings.set_user_value('foreman_url', 'http://new.example.net')
     assert_difference 'setting.audits.count' do
       as_admin { assert setting.save }
     end
@@ -63,17 +63,16 @@ class SettingTest < ActiveSupport::TestCase
   end
 
   test "#value= with unchanged value on encrypted setting does not modify DB or create audit" do
-    setting = Setting.create(name: 'encrypted', value: 'first', default: 'test', description: 'Test', encrypted: true)
+    Setting['root_pass'] = 'somepass'
+    setting = Setting.find_by(name: 'root_pass')
     setting.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
-    setting.value = 'new'
-    as_admin { setting.save! }
     db_value = setting.read_attribute(:value)
     assert_includes db_value, EncryptValue::ENCRYPTION_PREFIX
     assert_no_difference 'setting.audits.count' do
-      setting.value = 'new'
+      setting.value = 'somepass'
       setting.save!
-      assert_equal db_value, setting.read_attribute(:value)
     end
+    assert_equal db_value, setting.read_attribute(:value)
   end
 
   test 'proxy the value get to the registry' do
diff --git a/test/unit/setting_registry_test.rb b/test/unit/setting_registry_test.rb
index 0ec93199c..9770b2e99 100644
--- a/test/unit/setting_registry_test.rb
+++ b/test/unit/setting_registry_test.rb
@@ -102,28 +102,51 @@ class SettingRegistryTest < ActiveSupport::TestCase
   end
 
   describe '#set_user_value' do
-    setup do
-      registry._add('test',
-        category: 'Setting',
-        default: default,
-        type: :integer,
-        full_name: 'Test Foo',
-        description: 'test update',
-        context: :test)
-    end
+    context 'integer setting' do
+      setup do
+        registry._add('test',
+          category: 'Setting',
+          default: default,
+          type: :integer,
+          full_name: 'Test Foo',
+          description: 'test update',
+          context: :test)
+      end
 
-    it 'initiates the DB model if none exists yet' do
-      model = registry.set_user_value('test', '10')
-      assert_not_nil model
-      assert model.valid?
-      assert model.save
-      assert_equal 10, model.reload.value
+      it 'initiates the DB model if none exists yet' do
+        model = registry.set_user_value('test', '10')
+        assert_not_nil model
+        assert model.valid?
+        assert model.save
+        assert_equal 10, model.reload.value
+      end
+
+      it 'updates the DB model if already exists' do
+        model = Setting.create(registry.find('test').attributes.merge(value: setting_value))
+        registry.set_user_value('test', '10').save
+        assert_equal 10, model.reload.value
+      end
     end
 
-    it 'updates the DB model if already exists' do
-      model = Setting.create(registry.find('test').attributes.merge(value: setting_value))
-      registry.set_user_value('test', '10').save
-      assert_equal 10, model.reload.value
+    context 'encrypted setting' do
+      setup do
+        registry._add('test',
+          category: 'Setting',
+          default: 'foo',
+          type: :string,
+          full_name: 'Test Encrypted Foo',
+          description: 'test update',
+          encrypted: true,
+          context: :test)
+        Setting.any_instance.expects(:encryption_key).at_least_once.returns('25d224dd383e92a7e0c82b8bf7c985e815f34cf5')
+      end
+
+      it 'encrypts the value' do
+        Setting.any_instance.stubs(:setting_definition).returns(registry.find('test'))
+        model = registry.set_user_value('test', 'foobar')
+        model.save
+        assert_includes model.read_attribute(:value), EncryptValue::ENCRYPTION_PREFIX
+      end
     end
   end
 
