[ruby/psych] Introduce `Psych.unsafe_load`

In future versions of Psych, the `load` method will be mostly the same
as the `safe_load` method.  In other words, the `load` method won't
allow arbitrary object deserialization (which can be used to escalate to
an RCE).  People that need to load *trusted* documents can use the
`unsafe_load` method.

This commit introduces the `unsafe_load` method so that people can
incrementally upgrade.  For example, if they try to upgrade to 4.0.0 and
something breaks, they can downgrade, audit callsites, change to
`safe_load` or `unsafe_load` as required, and then upgrade to 4.0.0
smoothly.

https://github.com/ruby/psych/commit/cb50aa8d3f
This commit is contained in:
Aaron Patterson 2021-05-10 09:50:06 -07:00 коммит произвёл Hiroshi SHIBATA
Родитель bcaa6aecea
Коммит c7c2ad5749
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: F9CF13417264FAC2
26 изменённых файлов: 156 добавлений и 123 удалений

Просмотреть файл

@ -271,7 +271,7 @@ module Psych
# YAML documents that are supplied via user input. Instead, please use the
# safe_load method.
#
def self.load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false, freeze: false
def self.unsafe_load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false, freeze: false
if legacy_filename != NOT_GIVEN
warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
filename = legacy_filename
@ -281,6 +281,7 @@ module Psych
return fallback unless result
result.to_ruby(symbolize_names: symbolize_names, freeze: freeze)
end
class << self; alias :load :unsafe_load; end
###
# Safely load the yaml string in +yaml+. By default, only the following
@ -577,11 +578,12 @@ module Psych
# NOTE: This method *should not* be used to parse untrusted documents, such as
# YAML documents that are supplied via user input. Instead, please use the
# safe_load_file method.
def self.load_file filename, **kwargs
def self.unsafe_load_file filename, **kwargs
File.open(filename, 'r:bom|utf-8') { |f|
self.load f, filename: filename, **kwargs
self.unsafe_load f, filename: filename, **kwargs
}
end
class << self; alias :load_file :unsafe_load_file; end
###
# Safely loads the document contained in +filename+. Returns the yaml contained in

Просмотреть файл

@ -1,8 +1,8 @@
# frozen_string_literal: true
module Psych
# The version of Psych you are using
VERSION = '3.3.1'
VERSION = '3.3.2'
if RUBY_ENGINE == 'jruby'
DEFAULT_SNAKEYAML_VERSION = '1.28'.freeze

Просмотреть файл

@ -41,24 +41,30 @@ module Psych
# Convert between Psych and the object to verify correct parsing and
# emitting
#
def assert_to_yaml( obj, yaml )
assert_equal( obj, Psych::load( yaml ) )
def assert_to_yaml( obj, yaml, loader = :load )
assert_equal( obj, Psych.send(loader, yaml) )
assert_equal( obj, Psych::parse( yaml ).transform )
assert_equal( obj, Psych::load( obj.to_yaml ) )
assert_equal( obj, Psych.send(loader, obj.to_yaml) )
assert_equal( obj, Psych::parse( obj.to_yaml ).transform )
assert_equal( obj, Psych::load(
assert_equal( obj, Psych.send(loader,
obj.to_yaml(
:UseVersion => true, :UseHeader => true, :SortKeys => true
)
))
rescue Psych::DisallowedClass, Psych::BadAlias
assert_to_yaml obj, yaml, :unsafe_load
end
#
# Test parser only
#
def assert_parse_only( obj, yaml )
assert_equal( obj, Psych::load( yaml ) )
assert_equal( obj, Psych::parse( yaml ).transform )
begin
assert_equal obj, Psych::load( yaml )
rescue Psych::DisallowedClass, Psych::BadAlias
assert_equal obj, Psych::unsafe_load( yaml )
end
assert_equal obj, Psych::parse( yaml ).transform
end
def assert_cycle( obj )
@ -69,9 +75,15 @@ module Psych
assert_nil Psych::load(Psych.dump(obj))
assert_nil Psych::load(obj.to_yaml)
else
assert_equal(obj, Psych.load(v.tree.yaml))
assert_equal(obj, Psych::load(Psych.dump(obj)))
assert_equal(obj, Psych::load(obj.to_yaml))
begin
assert_equal(obj, Psych.load(v.tree.yaml))
assert_equal(obj, Psych::load(Psych.dump(obj)))
assert_equal(obj, Psych::load(obj.to_yaml))
rescue Psych::DisallowedClass, Psych::BadAlias
assert_equal(obj, Psych.unsafe_load(v.tree.yaml))
assert_equal(obj, Psych::unsafe_load(Psych.dump(obj)))
assert_equal(obj, Psych::unsafe_load(obj.to_yaml))
end
end
end

Просмотреть файл

@ -19,7 +19,7 @@ module Psych
- *id001
- *id001
EOYAML
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each {|el| assert_same(result[0], el) }
end
@ -33,7 +33,7 @@ EOYAML
- *id001
EOYAML
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each do |el|
assert_same(result[0], el)
assert_equal('test1', el.var1)
@ -50,7 +50,7 @@ EOYAML
- *id001
- *id001
EOYAML
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each do |el|
assert_same(result[0], el)
assert_equal('test', el.var1)
@ -62,7 +62,7 @@ EOYAML
original = [o,o,o]
yaml = Psych.dump original
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each {|el| assert_same(result[0], el) }
end
@ -73,7 +73,7 @@ EOYAML
original = [o,o,o]
yaml = Psych.dump original
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each do |el|
assert_same(result[0], el)
assert_equal('test1', el.var1)
@ -87,7 +87,7 @@ EOYAML
original = [o,o,o]
yaml = Psych.dump original
result = Psych.load yaml
result = Psych.unsafe_load yaml
result.each do |el|
assert_same(result[0], el)
assert_equal('test', el.var1)

Просмотреть файл

@ -24,7 +24,7 @@ module Psych
def test_another_subclass_with_attributes
y = Y.new.tap {|o| o.val = 1}
y << "foo" << "bar"
y = Psych.load Psych.dump y
y = Psych.unsafe_load Psych.dump y
assert_equal %w{foo bar}, y
assert_equal Y, y.class
@ -42,13 +42,13 @@ module Psych
end
def test_subclass_with_attributes
y = Psych.load Psych.dump Y.new.tap {|o| o.val = 1}
y = Psych.unsafe_load Psych.dump Y.new.tap {|o| o.val = 1}
assert_equal Y, y.class
assert_equal 1, y.val
end
def test_backwards_with_syck
x = Psych.load "--- !seq:#{X.name} []\n\n"
x = Psych.unsafe_load "--- !seq:#{X.name} []\n\n"
assert_equal X, x.class
end

Просмотреть файл

@ -124,7 +124,7 @@ module Psych
def test_self_referential
x = Referential.new
copy = Psych.load Psych.dump x
copy = Psych.unsafe_load Psych.dump x
assert_equal copy, copy.a
end
@ -163,23 +163,23 @@ module Psych
end
def test_represent_map
thing = Psych.load(Psych.dump(RepresentWithMap.new))
thing = Psych.unsafe_load(Psych.dump(RepresentWithMap.new))
assert_equal({ "string" => 'a', :symbol => 'b' }, thing.map)
end
def test_represent_sequence
thing = Psych.load(Psych.dump(RepresentWithSeq.new))
thing = Psych.unsafe_load(Psych.dump(RepresentWithSeq.new))
assert_equal %w{ foo bar }, thing.seq
end
def test_represent_with_init
thing = Psych.load(Psych.dump(RepresentWithInit.new))
thing = Psych.unsafe_load(Psych.dump(RepresentWithInit.new))
assert_equal 'bar', thing.str
end
def test_represent!
assert_match(/foo/, Psych.dump(Represent.new))
assert_instance_of(Represent, Psych.load(Psych.dump(Represent.new)))
assert_instance_of(Represent, Psych.unsafe_load(Psych.dump(Represent.new)))
end
def test_scalar_coder
@ -189,7 +189,7 @@ module Psych
def test_load_dumped_tagging
foo = InitApi.new
bar = Psych.load(Psych.dump(foo))
bar = Psych.unsafe_load(Psych.dump(foo))
assert_equal false, bar.implicit
assert_equal "!ruby/object:Psych::TestCoder::InitApi", bar.tag
assert_equal Psych::Nodes::Mapping::BLOCK, bar.style
@ -208,7 +208,7 @@ module Psych
def test_dump_init_with
foo = InitApi.new
bar = Psych.load(Psych.dump(foo))
bar = Psych.unsafe_load(Psych.dump(foo))
assert_equal foo.a, bar.a
assert_equal foo.b, bar.b
assert_nil bar.c

Просмотреть файл

@ -22,7 +22,7 @@ module Psych
def test_timezone_offset
times = [Time.new(2017, 4, 13, 12, 0, 0, "+09:00"),
Time.new(2017, 4, 13, 12, 0, 0, "-05:00")]
cycled = Psych::load(Psych.dump times)
cycled = Psych::unsafe_load(Psych.dump times)
assert_match(/12:00:00 \+0900/, cycled.first.to_s)
assert_match(/12:00:00 -0500/, cycled.last.to_s)
end
@ -39,7 +39,7 @@ module Psych
def test_datetime_timezone_offset
times = [DateTime.new(2017, 4, 13, 12, 0, 0, "+09:00"),
DateTime.new(2017, 4, 13, 12, 0, 0, "-05:00")]
cycled = Psych::load(Psych.dump times)
cycled = Psych::unsafe_load(Psych.dump times)
assert_match(/12:00:00\+09:00/, cycled.first.to_s)
assert_match(/12:00:00-05:00/, cycled.last.to_s)
end

Просмотреть файл

@ -41,7 +41,7 @@ module Psych
def test_recursive_quick_emit_encode_with
qeew = QuickEmitterEncodeWith.new
hash = { :qe => qeew }
hash2 = Psych.load Psych.dump hash
hash2 = Psych.unsafe_load Psych.dump hash
qe = hash2[:qe]
assert_equal qeew.name, qe.name
@ -72,7 +72,7 @@ module Psych
# receive the yaml_initialize call.
def test_yaml_initialize_and_init_with
hash = { :yi => YamlInitAndInitWith.new }
hash2 = Psych.load Psych.dump hash
hash2 = Psych.unsafe_load Psych.dump hash
yi = hash2[:yi]
assert_equal 'TGIF!', yi.name

Просмотреть файл

@ -33,13 +33,13 @@ module Psych
def test_backtrace
err = make_ex
new_err = Psych.load(Psych.dump(err))
new_err = Psych.unsafe_load(Psych.dump(err))
assert_equal err.backtrace, new_err.backtrace
end
def test_naming_exception
err = String.xxx rescue $!
new_err = Psych.load(Psych.dump(err))
new_err = Psych.unsafe_load(Psych.dump(err))
assert_equal err.message, new_err.message
end
@ -56,7 +56,7 @@ module Psych
# deprecated interface
ex = assert_raise(Psych::SyntaxError) do
Psych.load '--- `', 'deprecated'
Psych.unsafe_load '--- `', 'deprecated'
end
assert_equal 'deprecated', ex.file
end
@ -165,7 +165,7 @@ module Psych
end
def test_convert
w = Psych.load(Psych.dump(@wups))
w = Psych.unsafe_load(Psych.dump(@wups))
assert_equal @wups.message, w.message
assert_equal @wups.backtrace, w.backtrace
assert_equal 1, w.foo

Просмотреть файл

@ -39,7 +39,7 @@ module Psych
def test_hash_with_ivar
t1 = HashWithIvar.new
t1[:foo] = :bar
t2 = Psych.load(Psych.dump(t1))
t2 = Psych.unsafe_load(Psych.dump(t1))
assert_equal t1, t2
assert_cycle t1
end
@ -54,14 +54,14 @@ module Psych
def test_custom_initialized
a = [1,2,3,4,5]
t1 = HashWithCustomInit.new(a)
t2 = Psych.load(Psych.dump(t1))
t2 = Psych.unsafe_load(Psych.dump(t1))
assert_equal t1, t2
assert_cycle t1
end
def test_custom_initialize_no_ivar
t1 = HashWithCustomInitNoIvar.new(nil)
t2 = Psych.load(Psych.dump(t1))
t2 = Psych.unsafe_load(Psych.dump(t1))
assert_equal t1, t2
assert_cycle t1
end
@ -70,25 +70,25 @@ module Psych
x = X.new
x[:a] = 'b'
x.instance_variable_set :@foo, 'bar'
dup = Psych.load Psych.dump x
dup = Psych.unsafe_load Psych.dump x
assert_cycle x
assert_equal 'bar', dup.instance_variable_get(:@foo)
assert_equal X, dup.class
end
def test_load_with_class_syck_compatibility
hash = Psych.load "--- !ruby/object:Hash\n:user_id: 7\n:username: Lucas\n"
hash = Psych.unsafe_load "--- !ruby/object:Hash\n:user_id: 7\n:username: Lucas\n"
assert_equal({ user_id: 7, username: 'Lucas'}, hash)
end
def test_empty_subclass
assert_match "!ruby/hash:#{X}", Psych.dump(X.new)
x = Psych.load Psych.dump X.new
x = Psych.unsafe_load Psych.dump X.new
assert_equal X, x.class
end
def test_map
x = Psych.load "--- !map:#{X} { }\n"
x = Psych.unsafe_load "--- !map:#{X} { }\n"
assert_equal X, x.class
end
@ -102,7 +102,7 @@ module Psych
end
def test_ref_append
hash = Psych.load(<<-eoyml)
hash = Psych.unsafe_load(<<-eoyml)
---
foo: &foo
hello: world

Просмотреть файл

@ -6,7 +6,7 @@ module Psych
class TestMarshalable < TestCase
def test_objects_defining_marshal_dump_and_marshal_load_can_be_dumped
sd = SimpleDelegator.new(1)
loaded = Psych.load(Psych.dump(sd))
loaded = Psych.unsafe_load(Psych.dump(sd))
assert_instance_of(SimpleDelegator, loaded)
assert_equal(sd, loaded)
@ -46,7 +46,7 @@ module Psych
def test_init_with_takes_priority_over_marshal_methods
obj = PsychCustomMarshalable.new(1)
loaded = Psych.load(Psych.dump(obj))
loaded = Psych.unsafe_load(Psych.dump(obj))
assert(PsychCustomMarshalable === loaded)
assert_equal(2, loaded.foo)
@ -54,7 +54,7 @@ module Psych
def test_init_symbolize_names
obj = PsychCustomMarshalable.new(1)
loaded = Psych.load(Psych.dump(obj), symbolize_names: true)
loaded = Psych.unsafe_load(Psych.dump(obj), symbolize_names: true)
assert(PsychCustomMarshalable === loaded)
assert_equal(2, loaded.foo)

Просмотреть файл

@ -34,7 +34,7 @@ map:
end
def test_explicit_string
doc = Psych.load <<-eoyml
doc = Psych.unsafe_load <<-eoyml
a: &me { hello: world }
b: { !!str '<<': *me }
eoyml
@ -55,7 +55,7 @@ product:
!ruby/object:#{Product.name}
<<: *foo
eoyml
hash = Psych.load s
hash = Psych.unsafe_load s
assert_equal({"bar" => 10}, hash["foo"])
product = hash["product"]
assert_equal 10, product.bar
@ -67,7 +67,7 @@ defaults: &defaults
development:
<<: *defaults
eoyml
assert_equal({'<<' => nil }, Psych.load(yaml)['development'])
assert_equal({'<<' => nil }, Psych.unsafe_load(yaml)['development'])
end
def test_merge_array
@ -77,7 +77,7 @@ foo: &hello
baz:
<<: *hello
eoyml
assert_equal({'<<' => [1]}, Psych.load(yaml)['baz'])
assert_equal({'<<' => [1]}, Psych.unsafe_load(yaml)['baz'])
end
def test_merge_is_not_partial
@ -89,9 +89,9 @@ foo: &hello
baz:
<<: [*hello, *default]
eoyml
doc = Psych.load yaml
doc = Psych.unsafe_load yaml
refute doc['baz'].key? 'hello'
assert_equal({'<<' => [[1], {"hello"=>"world"}]}, Psych.load(yaml)['baz'])
assert_equal({'<<' => [[1], {"hello"=>"world"}]}, Psych.unsafe_load(yaml)['baz'])
end
def test_merge_seq_nil
@ -100,7 +100,7 @@ foo: &hello
baz:
<<: [*hello]
eoyml
assert_equal({'<<' => [nil]}, Psych.load(yaml)['baz'])
assert_equal({'<<' => [nil]}, Psych.unsafe_load(yaml)['baz'])
end
def test_bad_seq_merge
@ -109,7 +109,7 @@ defaults: &defaults [1, 2, 3]
development:
<<: *defaults
eoyml
assert_equal({'<<' => [1,2,3]}, Psych.load(yaml)['development'])
assert_equal({'<<' => [1,2,3]}, Psych.unsafe_load(yaml)['development'])
end
def test_missing_merge_key
@ -134,7 +134,7 @@ bar:
hash = {
"foo" => { "hello" => "world"},
"bar" => { "hello" => "world", "baz" => "boo" } }
assert_equal hash, Psych.load(yaml)
assert_equal hash, Psych.unsafe_load(yaml)
end
def test_multiple_maps
@ -159,7 +159,7 @@ bar:
'label' => 'center/big'
}
assert_equal hash, Psych.load(yaml)[4]
assert_equal hash, Psych.unsafe_load(yaml)[4]
end
def test_override
@ -185,7 +185,7 @@ bar:
'label' => 'center/big'
}
assert_equal hash, Psych.load(yaml)[4]
assert_equal hash, Psych.unsafe_load(yaml)[4]
end
end
end

Просмотреть файл

@ -28,7 +28,7 @@ module Psych
def test_tag_round_trip
tag = Tagged.new
tag2 = Psych.load(Psych.dump(tag))
tag2 = Psych.unsafe_load(Psych.dump(tag))
assert_equal tag.baz, tag2.baz
assert_instance_of(Tagged, tag2)
end
@ -36,7 +36,7 @@ module Psych
def test_cyclic_references
foo = Foo.new(nil)
foo.parent = foo
loaded = Psych.load Psych.dump foo
loaded = Psych.unsafe_load Psych.dump foo
assert_instance_of(Foo, loaded)
assert_equal loaded, loaded.parent

Просмотреть файл

@ -34,12 +34,16 @@ module Psych
def assert_reference_trip obj
yml = Psych.dump([obj, obj])
assert_match(/\*-?\d+/, yml)
data = Psych.load yml
begin
data = Psych.load yml
rescue Psych::DisallowedClass
data = Psych.unsafe_load yml
end
assert_equal data.first.object_id, data.last.object_id
end
def test_float_references
data = Psych.load <<-eoyml
data = Psych.unsafe_load <<-eoyml
---\s
- &name 1.2
- *name
@ -49,7 +53,7 @@ module Psych
end
def test_binary_references
data = Psych.load <<-eoyml
data = Psych.unsafe_load <<-eoyml
---
- &name !binary |-
aGVsbG8gd29ybGQh
@ -60,7 +64,7 @@ module Psych
end
def test_regexp_references
data = Psych.load <<-eoyml
data = Psych.unsafe_load <<-eoyml
---\s
- &name !ruby/regexp /pattern/i
- *name

Просмотреть файл

@ -4,7 +4,7 @@ require_relative 'helper'
module Psych
class TestOmap < TestCase
def test_parse_as_map
o = Psych.load "--- !!omap\na: 1\nb: 2"
o = Psych.unsafe_load "--- !!omap\na: 1\nb: 2"
assert_kind_of Psych::Omap, o
assert_equal 1, o['a']
assert_equal 2, o['b']
@ -14,7 +14,7 @@ module Psych
map = Psych::Omap.new
map['foo'] = 'bar'
map['self'] = map
assert_equal(map, Psych.load(Psych.dump(map)))
assert_equal(map, Psych.unsafe_load(Psych.dump(map)))
end
def test_keys

Просмотреть файл

@ -84,7 +84,7 @@ class TestPsych < Psych::TestCase
def test_non_existing_class_on_deserialize
e = assert_raise(ArgumentError) do
Psych.load("--- !ruby/object:NonExistent\nfoo: 1")
Psych.unsafe_load("--- !ruby/object:NonExistent\nfoo: 1")
end
assert_equal 'undefined class/module NonExistent', e.message
end
@ -222,28 +222,28 @@ class TestPsych < Psych::TestCase
end
def test_load_default_fallback
assert_equal false, Psych.load("")
assert_equal false, Psych.unsafe_load("")
end
def test_load_with_fallback
assert_equal 42, Psych.load("", "file", fallback: 42)
assert_equal 42, Psych.load("", filename: "file", fallback: 42)
end
def test_load_with_fallback_nil_or_false
assert_nil Psych.load("", "file", fallback: nil)
assert_equal false, Psych.load("", "file", fallback: false)
assert_nil Psych.load("", filename: "file", fallback: nil)
assert_equal false, Psych.load("", filename: "file", fallback: false)
end
def test_load_with_fallback_hash
assert_equal Hash.new, Psych.load("", "file", fallback: Hash.new)
assert_equal Hash.new, Psych.load("", filename: "file", fallback: Hash.new)
end
def test_load_with_fallback_for_nil
assert_nil Psych.load("--- null", "file", fallback: 42)
assert_nil Psych.unsafe_load("--- null", "file", fallback: 42)
end
def test_load_with_fallback_for_false
assert_equal false, Psych.load("--- false", "file", fallback: 42)
assert_equal false, Psych.unsafe_load("--- false", "file", fallback: 42)
end
def test_load_file
@ -278,7 +278,7 @@ class TestPsych < Psych::TestCase
def test_load_file_default_fallback
Tempfile.create(['empty', 'yml']) {|t|
assert_equal false, Psych.load_file(t.path)
assert_equal false, Psych.unsafe_load_file(t.path)
}
end
@ -347,9 +347,9 @@ class TestPsych < Psych::TestCase
end
def test_degenerate_strings
assert_equal false, Psych.load(' ')
assert_equal false, Psych.unsafe_load(' ')
assert_equal false, Psych.parse(' ')
assert_equal false, Psych.load('')
assert_equal false, Psych.unsafe_load('')
assert_equal false, Psych.parse('')
end

Просмотреть файл

@ -6,7 +6,7 @@ class TestPsychRactor < Test::Unit::TestCase
assert_ractor(<<~RUBY, require_relative: 'helper')
obj = {foo: [42]}
obj2 = Ractor.new(obj) do |obj|
Psych.load(Psych.dump(obj))
Psych.unsafe_load(Psych.dump(obj))
end.take
assert_equal obj, obj2
RUBY

Просмотреть файл

@ -17,7 +17,7 @@ module Psych
def test_some_object
so = SomeObject.new('foo', [1,2,3])
assert_equal so, Psych.load(Psych.dump(so))
assert_equal so, Psych.unsafe_load(Psych.dump(so))
end
class StructSubclass < Struct.new(:foo)
@ -33,7 +33,7 @@ module Psych
def test_struct_subclass
so = StructSubclass.new('foo', [1,2,3])
assert_equal so, Psych.load(Psych.dump(so))
assert_equal so, Psych.unsafe_load(Psych.dump(so))
end
end
end

Просмотреть файл

@ -21,7 +21,7 @@ module Psych
###
# FIXME: Syck should also support !!set as shorthand
def test_load_from_yaml
loaded = Psych.load(<<-eoyml)
loaded = Psych.unsafe_load(<<-eoyml)
--- !set
foo: bar
bar: baz
@ -30,11 +30,11 @@ bar: baz
end
def test_loaded_class
assert_instance_of(Psych::Set, Psych.load(Psych.dump(@set)))
assert_instance_of(Psych::Set, Psych.unsafe_load(Psych.dump(@set)))
end
def test_set_shorthand
loaded = Psych.load(<<-eoyml)
loaded = Psych.unsafe_load(<<-eoyml)
--- !!set
foo: bar
bar: baz

Просмотреть файл

@ -104,7 +104,7 @@ module Psych
end
def test_string_subclass_with_anchor
y = Psych.load <<-eoyml
y = Psych.unsafe_load <<-eoyml
---
body:
string: &70121654388580 !ruby/string
@ -116,7 +116,7 @@ body:
end
def test_self_referential_string
y = Psych.load <<-eoyml
y = Psych.unsafe_load <<-eoyml
---
string: &70121654388580 !ruby/string
str: ! 'foo'
@ -129,32 +129,32 @@ string: &70121654388580 !ruby/string
end
def test_another_subclass_with_attributes
y = Psych.load Psych.dump Y.new("foo").tap {|o| o.val = 1}
y = Psych.unsafe_load Psych.dump Y.new("foo").tap {|o| o.val = 1}
assert_equal "foo", y
assert_equal Y, y.class
assert_equal 1, y.val
end
def test_backwards_with_syck
x = Psych.load "--- !str:#{X.name} foo\n\n"
x = Psych.unsafe_load "--- !str:#{X.name} foo\n\n"
assert_equal X, x.class
assert_equal 'foo', x
end
def test_empty_subclass
assert_match "!ruby/string:#{X}", Psych.dump(X.new)
x = Psych.load Psych.dump X.new
x = Psych.unsafe_load Psych.dump X.new
assert_equal X, x.class
end
def test_empty_character_subclass
assert_match "!ruby/string:#{Z}", Psych.dump(Z.new)
x = Psych.load Psych.dump Z.new
x = Psych.unsafe_load Psych.dump Z.new
assert_equal Z, x.class
end
def test_subclass_with_attributes
y = Psych.load Psych.dump Y.new.tap {|o| o.val = 1}
y = Psych.unsafe_load Psych.dump Y.new.tap {|o| o.val = 1}
assert_equal Y, y.class
assert_equal 1, y.val
end

Просмотреть файл

@ -22,7 +22,7 @@ module Psych
ss = StructSubclass.new(nil, 'foo')
ss.foo = ss
loaded = Psych.load(Psych.dump(ss))
loaded = Psych.unsafe_load(Psych.dump(ss))
assert_instance_of(StructSubclass, loaded.foo)
assert_equal(ss, loaded)
@ -30,14 +30,14 @@ module Psych
def test_roundtrip
thing = PsychStructWithIvar.new('bar')
struct = Psych.load(Psych.dump(thing))
struct = Psych.unsafe_load(Psych.dump(thing))
assert_equal 'hello', struct.bar
assert_equal 'bar', struct.foo
end
def test_load
obj = Psych.load(<<-eoyml)
obj = Psych.unsafe_load(<<-eoyml)
--- !ruby/struct:PsychStructWithIvar
:foo: bar
:@bar: hello

Просмотреть файл

@ -573,7 +573,7 @@ EOY
end
def test_spec_root_mapping
y = Psych::load( <<EOY
y = Psych::unsafe_load( <<EOY
# This stream is an example of a top-level mapping.
invoice : 34843
date : 2001-01-23
@ -1077,7 +1077,7 @@ EOY
# Read Psych dumped by the ruby 1.8.3.
assert_to_yaml( Rational(1, 2), "!ruby/object:Rational 1/2\n" )
assert_raise( ArgumentError ) { Psych.load("!ruby/object:Rational INVALID/RATIONAL\n") }
assert_raise( ArgumentError ) { Psych.unsafe_load("!ruby/object:Rational INVALID/RATIONAL\n") }
end
def test_ruby_complex
@ -1089,7 +1089,7 @@ EOY
# Read Psych dumped by the ruby 1.8.3.
assert_to_yaml( Complex(3, 4), "!ruby/object:Complex 3+4i\n" )
assert_raise( ArgumentError ) { Psych.load("!ruby/object:Complex INVALID+COMPLEXi\n") }
assert_raise( ArgumentError ) { Psych.unsafe_load("!ruby/object:Complex INVALID+COMPLEXi\n") }
end
def test_emitting_indicators
@ -1209,7 +1209,7 @@ EOY
def test_circular_references
a = []; a[0] = a; a[1] = a
inspect_str = "[[...], [...]]"
assert_equal( inspect_str, Psych::load(Psych.dump(a)).inspect )
assert_equal( inspect_str, Psych::unsafe_load(Psych.dump(a)).inspect )
end
#
@ -1264,11 +1264,11 @@ EOY
end
def test_date_out_of_range
Psych::load('1900-01-01T00:00:00+00:00')
Psych::unsafe_load('1900-01-01T00:00:00+00:00')
end
def test_normal_exit
Psych.load("2000-01-01 00:00:00.#{"0"*1000} +00:00\n")
Psych.unsafe_load("2000-01-01 00:00:00.#{"0"*1000} +00:00\n")
# '[ruby-core:13735]'
end

Просмотреть файл

@ -13,7 +13,7 @@ module Psych
def test_empty_string
s = ""
assert_equal false, Psych.load(s)
assert_equal false, Psych.unsafe_load(s)
assert_equal [], Psych.load_stream(s)
assert_equal false, Psych.parse(s)
assert_equal [], Psych.parse_stream(s).transform

Просмотреть файл

@ -4,7 +4,22 @@ require 'yaml/store'
require 'tmpdir'
module Psych
Psych::Store = YAML::Store unless defined?(Psych::Store)
class YAML::Store
alias :old_load :load
def load(content)
table = YAML.load(content, fallback: false)
if table == false
{}
else
table
end
end
end
unless defined?(Psych::Store)
Psych::Store = YAML::Store
end
class YAMLStoreTest < TestCase
def setup
@ -24,61 +39,61 @@ module Psych
def test_opening_new_file_in_readonly_mode_should_result_in_empty_values
@yamlstore.transaction(true) do
assert_nil @yamlstore[:foo]
assert_nil @yamlstore[:bar]
assert_nil @yamlstore["foo"]
assert_nil @yamlstore["bar"]
end
end
def test_opening_new_file_in_readwrite_mode_should_result_in_empty_values
@yamlstore.transaction do
assert_nil @yamlstore[:foo]
assert_nil @yamlstore[:bar]
assert_nil @yamlstore["foo"]
assert_nil @yamlstore["bar"]
end
end
def test_data_should_be_loaded_correctly_when_in_readonly_mode
@yamlstore.transaction do
@yamlstore[:foo] = "bar"
@yamlstore["foo"] = "bar"
end
@yamlstore.transaction(true) do
assert_equal "bar", @yamlstore[:foo]
assert_equal "bar", @yamlstore["foo"]
end
end
def test_data_should_be_loaded_correctly_when_in_readwrite_mode
@yamlstore.transaction do
@yamlstore[:foo] = "bar"
@yamlstore["foo"] = "bar"
end
@yamlstore.transaction do
assert_equal "bar", @yamlstore[:foo]
assert_equal "bar", @yamlstore["foo"]
end
end
def test_changes_after_commit_are_discarded
@yamlstore.transaction do
@yamlstore[:foo] = "bar"
@yamlstore["foo"] = "bar"
@yamlstore.commit
@yamlstore[:foo] = "baz"
@yamlstore["foo"] = "baz"
end
@yamlstore.transaction(true) do
assert_equal "bar", @yamlstore[:foo]
assert_equal "bar", @yamlstore["foo"]
end
end
def test_changes_are_not_written_on_abort
@yamlstore.transaction do
@yamlstore[:foo] = "bar"
@yamlstore["foo"] = "bar"
@yamlstore.abort
end
@yamlstore.transaction(true) do
assert_nil @yamlstore[:foo]
assert_nil @yamlstore["foo"]
end
end
def test_writing_inside_readonly_transaction_raises_error
assert_raise(PStore::Error) do
@yamlstore.transaction(true) do
@yamlstore[:foo] = "bar"
@yamlstore["foo"] = "bar"
end
end
end

Просмотреть файл

@ -20,13 +20,13 @@ module Psych
end
def test_tz_00_00_loads_without_error
assert Psych.load('1900-01-01T00:00:00+00:00')
assert Psych.unsafe_load('1900-01-01T00:00:00+00:00')
end
def test_legacy_struct
Struct.send(:remove_const, :AWESOME) if Struct.const_defined?(:AWESOME)
foo = Struct.new('AWESOME', :bar)
assert_equal foo.new('baz'), Psych.load(<<-eoyml)
assert_equal foo.new('baz'), Psych.unsafe_load(<<-eoyml)
!ruby/struct:AWESOME
bar: baz
eoyml

Просмотреть файл

@ -62,19 +62,19 @@ module Psych
def test_struct_anon
s = Struct.new(:foo).new('bar')
obj = Psych.load(Psych.dump(s))
obj = Psych.unsafe_load(Psych.dump(s))
assert_equal s.foo, obj.foo
end
def test_override_method
s = Struct.new(:method).new('override')
obj = Psych.load(Psych.dump(s))
obj = Psych.unsafe_load(Psych.dump(s))
assert_equal s.method, obj.method
end
def test_exception
ex = Exception.new 'foo'
loaded = Psych.load(Psych.dump(ex))
loaded = Psych.unsafe_load(Psych.dump(ex))
assert_equal ex.message, loaded.message
assert_equal ex.class, loaded.class
@ -88,7 +88,7 @@ module Psych
def test_time
t = Time.now
assert_equal t, Psych.load(Psych.dump(t))
assert_equal t, Psych.unsafe_load(Psych.dump(t))
end
def test_date