Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Psych::DisallowedClass: Tried to load unspecified class: Time with Ruby 3.1 / Psych 4.0 #80

Closed
voxik opened this issue Mar 4, 2022 · 7 comments

Comments

@voxik
Copy link
Contributor

voxik commented Mar 4, 2022

Running Ronn test suite, I observe the following failure:

Error: test_converting_to_yaml(DocumentTest::TestSimpleConventionallyNamedDocument): Psych::DisallowedClass: Tried to load unspecified class: Time
/usr/share/gems/gems/psych-4.0.3/lib/psych/class_loader.rb:99:in `find'
/usr/share/gems/gems/psych-4.0.3/lib/psych/class_loader.rb:28:in `load'
/usr/share/gems/gems/psych-4.0.3/lib/psych/scalar_scanner.rb:109:in `parse_time'
/usr/share/gems/gems/psych-4.0.3/lib/psych/scalar_scanner.rb:52:in `tokenize'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:65:in `deserialize'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:128:in `visit_Psych_Nodes_Scalar'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:30:in `visit'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:6:in `accept'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:35:in `accept'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:345:in `block in revive_hash'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:343:in `each'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:343:in `each_slice'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:343:in `revive_hash'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:167:in `visit_Psych_Nodes_Mapping'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:30:in `visit'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:6:in `accept'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:35:in `accept'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:318:in `visit_Psych_Nodes_Document'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:30:in `visit'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/visitor.rb:6:in `accept'
/usr/share/gems/gems/psych-4.0.3/lib/psych/visitors/to_ruby.rb:35:in `accept'
/usr/share/ruby/psych.rb:335:in `safe_load'
/usr/share/ruby/psych.rb:370:in `load'
/builddir/build/BUILD/ronn-ng-0.9.1/usr/share/gems/gems/ronn-ng-0.9.1/test/test_ronn_document.rb:149:in `block (2 levels) in <class:DocumentTest>'

which seems to be related to ruby/psych#262.

There are several possible fixes. This is the easy one:

diff --git a/test/test_ronn_document.rb b/test/test_ronn_document.rb
index 75788dc..a86793f 100644
--- a/test/test_ronn_document.rb
+++ b/test/test_ronn_document.rb
@@ -146,7 +146,7 @@ class DocumentTest < Test::Unit::TestCase
                      'toc'          => [['NAME', 'NAME']],
                      'organization' => nil,
                      'manual'       => nil
-                   }, YAML.load(@doc.to_yaml))
+                   }, YAML.load(@doc.to_yaml, permitted_classes: [Time]))
     end
 
     test 'converting to json' do

But that seems to be more of workaround the test error then proper fix.

The other possibility is:

diff --git a/lib/ronn/document.rb b/lib/ronn/document.rb
index 15bef2c..6eca53f 100644
--- a/lib/ronn/document.rb
+++ b/lib/ronn/document.rb
@@ -294,7 +294,7 @@ module Ronn
 
     def to_yaml
       require 'yaml'
-      to_h.to_yaml
+      to_h.merge('date' => date.to_s).to_yaml
     end
 
     def to_json(*_args)
diff --git a/test/test_ronn_document.rb b/test/test_ronn_document.rb
index 75788dc..ef7bd2a 100644
--- a/test/test_ronn_document.rb
+++ b/test/test_ronn_document.rb
@@ -140,7 +140,7 @@ class DocumentTest < Test::Unit::TestCase
       assert_equal({
                      'section'      => '1',
                      'name'         => 'hello',
-                     'date'         => @now,
+                     'date'         => @now.to_s,
                      'tagline'      => 'hello world',
                      'styles'       => ['man'],
                      'toc'          => [['NAME', 'NAME']],

Which would be more in line to what to_json does already. But that would also mean that the date is treated as a String in YAML.

@apjanke
Copy link
Owner

apjanke commented Mar 5, 2022

So: I observe the same failures, and I agree they're a problem. Your second approach seems more like a "real fix" to me, and the first approach more like a hack or workaround, like you say.

Main problem here is that I'm no expert Ruby programmer, and know very little about Psych.

I suspect we should focus on your second approach and see if that works out. I'm also pretty busy this weekend, and distracted by World News stuff. Give me a week or two to try to better understand this issue and what the ramifications of doing the date-to-string conversion are here? Or if you know the ramifications, feel free to expound here, and I'll follow your lead.

Feel free to ping me here in a week if I haven't responded; I'm not great at managing my GitHub TODOs. :)

@voxik
Copy link
Contributor Author

voxik commented Mar 5, 2022

Thx for your thoughts and no worries take your time.

I think that the question here is backward compatibility, if somebody uses Ronn as a library. The workaround is keeping status quo and turn over the issue to the library users. The second approach is more owning the problem and admitting there is issue and providing fix with know consequences.

The question is who use ronn-ng as a library? Just a quick look on ronn-ng, there is not many. Looking at original Ronn [2], the Mustache compatibility would be probably the question.

[1] https://rubygems.org/gems/ronn-ng/reverse_dependencies
[2] https://rubygems.org/gems/ronn/reverse_dependencies

@keszybz
Copy link

keszybz commented Aug 20, 2022

So… what's the decision here?

@apjanke
Copy link
Owner

apjanke commented Aug 26, 2022

Well crap. I have no decision. I'm not good enough with Ruby to make a good call here without further study and experimentation.

My view is: ronn-ng is an application that provides a command, and the fact that it is uses Ruby is an internal implementation detail. I wasn't intending to support use of ronn-ng as a library at all. Writing and maintaining a library is harder and more complex than maintaining an application/command.

I don't know if this is the right view. I picked up Ronn as abandonware after the original author seemed to lose interest. I thought it was just for use as a command/program. But maybe that was wrong.

@voxik 's suggestion of the to_s/string conversion seems like the Right Thing to me here: it seems to make a cleaner separation between the in-mem-Ruby/object-aware internal representation and the "external"/interchange YAML format. But the fact of the matter is, I'm not good enough with Ruby or YAML to really make an informed call here, and I'm honestly not sure what to do.

My main point of reference is, when called as a command from an external process, does the ronn command provided by Ronn-NG provide the expected output, as observable by external processes? But as far as I can tell, that doesn't meaningfully inform a decision on this particular issue.

To voxik's last question/post: I didn't know that there were any people that consumed ronn as a library. I wasn't intending to support that; I didn't know that was a thing that people did. But I also don't want to screw over existing users if they're doing that already.

Sorry folks. I dunno really what to do here.

@voxik
Copy link
Contributor Author

voxik commented Aug 29, 2022

Looking into this again, I think that the right solution is the YAML.load(@doc.to_yaml, permitted_classes: [Time])) after all.

  1. I think that the YAML output is valid. The date field is properly formatted as defined by YAML specifications, the parser can read the date. It just happens that the YAML parser in Ruby prohibits it for some reasons (the Date is used as an example on the same place) and in fact, there might be some issues parsing the field when the format appears to be correct, but the values are not.
  2. Given that the date file is proper YAML construct, converting it to the string would be wrong. Because it would be treated as a string on other places instead of the YAML timestamp.
  3. While there is to_yaml method, there is not its opposite. Therefore I believe that anybody would use the to_yaml for anything serious. The thing is that serialization always worked fine, but the de-serialization is the issue and the issues would have been either fixed already or they simply don't exist.

I'll submit PR with the permitted_classes: [Time] fix tomorrow.

@apjanke
Copy link
Owner

apjanke commented Aug 30, 2022

That reasoning makes sense to me. Go for it.

voxik added a commit to voxik/ronn-ng that referenced this issue Aug 30, 2022
Since Psych 4.0, the `safe_load` is used as default loading mechanism.
There are just a few permitted classes and `Time` is not one of them
[[1]]. This results it test failure:

~~~
Error: test_converting_to_yaml(DocumentTest::TestSimpleConventionallyNamedDocument): Psych::DisallowedClass: Tried to load unspecified class: Time
~~~

Please also note that in YAML specs 1.2, the `timestamp` is not
listed as supported tag anymore [[2]].

Given that:

1) ronn-ng does not provide any supported way of loading the serialized
   YAML.
2) The `to_yaml` does not appear to be used internally/externally
   anywhere.
2) If there were users of this functionality, it would have been already
   know, reported and fixed at this moment.

The best course of action is fixing the test case by listing the `Time`
as valid class for parsing.

Fixes apjanke#80

[1]: https://docs.ruby-lang.org/en/master/Psych.html#method-c-safe_load
[2]: yaml/yaml-spec#268
voxik added a commit to voxik/ronn-ng that referenced this issue Aug 30, 2022
Since Psych 4.0, the `safe_load` is used as default loading mechanism.
There are just a few permitted classes and `Time` is not one of them
[[1]]. This results it test failure:

~~~
Error: test_converting_to_yaml(DocumentTest::TestSimpleConventionallyNamedDocument): Psych::DisallowedClass: Tried to load unspecified class: Time
~~~

Please also note that in YAML specs 1.2, the `timestamp` is not
listed as supported tag anymore [[2]].

Given that:

1) ronn-ng does not provide any supported way of loading the serialized
   YAML.
2) The `to_yaml` does not appear to be used internally/externally
   anywhere.
3) If there were users of this functionality, it would have been already
   know, reported and fixed at this moment.

The best course of action is fixing the test case by listing the `Time`
as valid class for parsing.

Fixes apjanke#80

[1]: https://docs.ruby-lang.org/en/master/Psych.html#method-c-safe_load
[2]: yaml/yaml-spec#268
@apjanke
Copy link
Owner

apjanke commented Jan 23, 2023

I think I've got this fixed with the changes I made for #87, and a Ronn-NG 0.10.1 release will be coming out shortly. Please re-open this bug report if you continue to have issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants