Defect #37476
closedPsych::DisallowedClass exception when loading default plugin settings
0%
Description
After r21722 redmine keeps throwing a Psych::DisallowedClass (Tried to load unspecified class: Symbol)
when accessing default plugin setting using Setting.plugin_name
.
Turns out settings for plugins are loading either from database (which is HashWithIndifferentAccess
) and if it is not found then fallbacks to init.rb where it's a simple Hash object. Passing latter to YAML.safe_load
raises a error.
To reproduce install any plugin that defines default settings in init.rb and call Setting.plugin_name.
Here for example I installed redmine_issue_templates
and then in console trying to get its settings:
$ bundle exec rails db:reset RAILS_ENV=development Dropped database 'db/development.sqlite3' Created database 'db/development.sqlite3' makurin@makurin:~/Work/clean-redmine$ rails c Loading development environment (Rails 6.1.6.1) irb(main):001:0> Setting.plugin_redmine_issue_templates (2.4ms) SELECT sqlite_version(*) Setting Load (0.4ms) SELECT "settings".* FROM "settings" WHERE "settings"."name" = ? ORDER BY "settings"."id" DESC LIMIT ? [["name", "plugin_redmine_issue_templates"], ["LIMIT", 1]] Traceback (most recent call last): 3: from app/models/setting.rb:320:in `plugin_redmine_issue_templates' 2: from app/models/setting.rb:125:in `[]' 1: from app/models/setting.rb:111:in `value' Psych::DisallowedClass (Tried to load unspecified class: Symbol)
So far I found two options to resolve it.
Tell YAML that Symbol
is allowed:
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 53b88bcad4..bc59306476 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -108,7 +108,7 @@ class Setting < ActiveRecord::Base
v = read_attribute(:value)
# Unserialize serialized settings
if available_settings[name]['serialized'] && v.is_a?(String)
- v = YAML.safe_load(v, permitted_classes: [ActiveSupport::HashWithIndifferentAccess])
+ v = YAML.safe_load(v, permitted_classes: [ActiveSupport::HashWithIndifferentAccess, Symbol])
v = force_utf8_strings(v)
end
v = v.to_sym if available_settings[name]['format'] == 'symbol' && !v.blank?
Or convert default plugin settings to HashWithIndifferentAccess:
diff --git a/app/models/setting.rb b/app/models/setting.rb
index 53b88bcad4..a5f7b7966c 100644
--- a/app/models/setting.rb
+++ b/app/models/setting.rb
@@ -293,7 +293,7 @@ class Setting < ActiveRecord::Base
def self.define_plugin_setting(plugin)
if plugin.settings
name = "plugin_#{plugin.id}"
- define_setting name, {'default' => plugin.settings[:default], 'serialized' => true}
+ define_setting name, {'default' => plugin.settings[:default].with_indifferent_access, 'serialized' => true}
end
end