Project

General

Profile

Actions

Defect #37476

closed

Psych::DisallowedClass exception when loading default plugin settings

Added by Dmitry Makurin almost 2 years ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Plugin API
Target version:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Resolution:
Fixed
Affected version:

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
Actions

Also available in: Atom PDF