safe_yaml 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +5 -2
- data/bundle_install_all_ruby_versions.sh +6 -16
- data/lib/safe_yaml/load.rb +1 -1
- data/lib/safe_yaml/resolver.rb +1 -1
- data/lib/safe_yaml/version.rb +1 -1
- data/run_specs_all_ruby_versions.sh +9 -0
- data/spec/libyaml_checker_spec.rb +2 -2
- data/spec/resolver_specs.rb +26 -26
- data/spec/safe_yaml_spec.rb +90 -90
- data/spec/spec_helper.rb +6 -6
- data/spec/transform/base64_spec.rb +2 -2
- data/spec/transform/to_date_spec.rb +17 -17
- data/spec/transform/to_float_spec.rb +10 -10
- data/spec/transform/to_integer_spec.rb +16 -16
- data/spec/transform/to_symbol_spec.rb +7 -7
- data/spec/yaml_spec.rb +2 -2
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbb2ac04a98ae5516c34c7dc2baf6348304c6e17
|
4
|
+
data.tar.gz: 097dd3a02c37a63f7a899b8897839b3c60a82117
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93c0fd49c34c71dfcb0cb76d127aa52e9178a6cf6d9b8a6a94728b1ea336c956c228cc71bbefa4790fe31d35229b0e9783e930f7a97ec69053dcfdd4441571cb
|
7
|
+
data.tar.gz: 5d068fabdc5b89a544958e0a139a82bcc40c38828840f6a9d02baca82e3b574868397fa45b74042320ea403f13388ebd2db32164eef4df97f261475049f4f86f
|
data/Rakefile
CHANGED
@@ -6,18 +6,21 @@ task :spec => ['spec:app', 'spec:lib']
|
|
6
6
|
namespace :spec do
|
7
7
|
desc "Run only specs tagged 'solo'"
|
8
8
|
RSpec::Core::RakeTask.new(:solo) do |t|
|
9
|
+
t.verbose = false
|
9
10
|
t.rspec_opts = %w(--color --tag solo)
|
10
11
|
end
|
11
12
|
|
12
13
|
desc "Run only specs tagged NOT tagged 'libraries' (for applications)"
|
13
14
|
RSpec::Core::RakeTask.new(:app) do |t|
|
14
|
-
|
15
|
+
t.verbose = false
|
16
|
+
ENV["MONKEYPATCH_YAML"] = "true"
|
15
17
|
t.rspec_opts = %w(--color --tag ~libraries)
|
16
18
|
end
|
17
19
|
|
18
20
|
desc "Run only specs tagged 'libraries'"
|
19
21
|
RSpec::Core::RakeTask.new(:lib) do |t|
|
20
|
-
|
22
|
+
t.verbose = false
|
23
|
+
ENV["MONKEYPATCH_YAML"] = "false"
|
21
24
|
t.rspec_opts = %w(--color --tag libraries)
|
22
25
|
end
|
23
26
|
end
|
@@ -2,20 +2,10 @@
|
|
2
2
|
|
3
3
|
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"
|
4
4
|
|
5
|
-
|
6
|
-
bundle install
|
5
|
+
declare -a versions=("1.8.7" "1.9.2" "1.9.3" "2.0.0" "2.1.0" "2.1.1" "2.1.2" "ruby-head" "jruby")
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
rvm use 2.0.0
|
15
|
-
bundle install
|
16
|
-
|
17
|
-
rvm use ruby-head
|
18
|
-
bundle install
|
19
|
-
|
20
|
-
rvm use jruby
|
21
|
-
bundle install
|
7
|
+
for i in "${versions[@]}"
|
8
|
+
do
|
9
|
+
rvm use $i
|
10
|
+
bundle install
|
11
|
+
done
|
data/lib/safe_yaml/load.rb
CHANGED
@@ -4,7 +4,7 @@ require "yaml"
|
|
4
4
|
# This needs to be defined up front in case any internal classes need to base
|
5
5
|
# their behavior off of this.
|
6
6
|
module SafeYAML
|
7
|
-
YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
|
7
|
+
YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : (defined?(Psych) && YAML == Psych ? "psych" : "syck")
|
8
8
|
end
|
9
9
|
|
10
10
|
require "safe_yaml/libyaml_checker"
|
data/lib/safe_yaml/resolver.rb
CHANGED
@@ -52,7 +52,7 @@ module SafeYAML
|
|
52
52
|
tag = get_and_check_node_tag(node)
|
53
53
|
arr = @initializers.include?(tag) ? @initializers[tag].call : []
|
54
54
|
|
55
|
-
seq.inject(arr) { |array,
|
55
|
+
seq.inject(arr) { |array, n| array << resolve_node(n) }
|
56
56
|
end
|
57
57
|
|
58
58
|
def resolve_scalar(node)
|
data/lib/safe_yaml/version.rb
CHANGED
@@ -18,6 +18,15 @@ YAMLER=psych bundle exec rake spec
|
|
18
18
|
rvm use 2.0.0
|
19
19
|
bundle exec rake spec
|
20
20
|
|
21
|
+
rvm use 2.1.0
|
22
|
+
bundle exec rake spec
|
23
|
+
|
24
|
+
rvm use 2.1.1
|
25
|
+
bundle exec rake spec
|
26
|
+
|
27
|
+
rvm use 2.1.2
|
28
|
+
bundle exec rake spec
|
29
|
+
|
21
30
|
rvm use ruby-head
|
22
31
|
bundle exec rake spec
|
23
32
|
|
@@ -8,7 +8,7 @@ describe SafeYAML::LibyamlChecker do
|
|
8
8
|
let(:libyaml_patched) { false }
|
9
9
|
|
10
10
|
before :each do
|
11
|
-
SafeYAML::LibyamlChecker.
|
11
|
+
allow(SafeYAML::LibyamlChecker).to receive(:libyaml_patched?).and_return(libyaml_patched)
|
12
12
|
end
|
13
13
|
|
14
14
|
after :each do
|
@@ -22,7 +22,7 @@ describe SafeYAML::LibyamlChecker do
|
|
22
22
|
silence_warnings do
|
23
23
|
SafeYAML.const_set("YAML_ENGINE", yaml_engine)
|
24
24
|
SafeYAML::LibyamlChecker.const_set("LIBYAML_VERSION", libyaml_version)
|
25
|
-
SafeYAML::LibyamlChecker.libyaml_version_ok
|
25
|
+
expect(SafeYAML::LibyamlChecker.libyaml_version_ok?).to eq(expected_result)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
data/spec/resolver_specs.rb
CHANGED
@@ -39,7 +39,7 @@ module ResolverSpecs
|
|
39
39
|
Kernel.warn "#{exception_thrown.inspect}\n"
|
40
40
|
|
41
41
|
else
|
42
|
-
safe_result.
|
42
|
+
expect(safe_result).to eq(unsafe_result)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -50,10 +50,10 @@ module ResolverSpecs
|
|
50
50
|
tomayto: tomahto
|
51
51
|
YAML
|
52
52
|
|
53
|
-
result.
|
53
|
+
expect(result).to eq({
|
54
54
|
"potayto" => "potahto",
|
55
55
|
"tomayto" => "tomahto"
|
56
|
-
}
|
56
|
+
})
|
57
57
|
end
|
58
58
|
|
59
59
|
it "translates sequences to arrays" do
|
@@ -63,32 +63,32 @@ module ResolverSpecs
|
|
63
63
|
- baz
|
64
64
|
YAML
|
65
65
|
|
66
|
-
result.
|
66
|
+
expect(result).to eq(["foo", "bar", "baz"])
|
67
67
|
end
|
68
68
|
|
69
69
|
it "translates most values to strings" do
|
70
70
|
parse "string: value"
|
71
|
-
result.
|
71
|
+
expect(result).to eq({ "string" => "value" })
|
72
72
|
end
|
73
73
|
|
74
74
|
it "does not deserialize symbols" do
|
75
75
|
parse ":symbol: value"
|
76
|
-
result.
|
76
|
+
expect(result).to eq({ ":symbol" => "value" })
|
77
77
|
end
|
78
78
|
|
79
79
|
it "translates valid integral numbers to integers" do
|
80
80
|
parse "integer: 1"
|
81
|
-
result.
|
81
|
+
expect(result).to eq({ "integer" => 1 })
|
82
82
|
end
|
83
83
|
|
84
84
|
it "translates valid decimal numbers to floats" do
|
85
85
|
parse "float: 3.14"
|
86
|
-
result.
|
86
|
+
expect(result).to eq({ "float" => 3.14 })
|
87
87
|
end
|
88
88
|
|
89
89
|
it "translates valid dates" do
|
90
90
|
parse "date: 2013-01-24"
|
91
|
-
result.
|
91
|
+
expect(result).to eq({ "date" => Date.parse("2013-01-24") })
|
92
92
|
end
|
93
93
|
|
94
94
|
it "translates valid true/false values to booleans" do
|
@@ -99,7 +99,7 @@ module ResolverSpecs
|
|
99
99
|
- false
|
100
100
|
YAML
|
101
101
|
|
102
|
-
result.
|
102
|
+
expect(result).to eq([true, true, false, false])
|
103
103
|
end
|
104
104
|
|
105
105
|
it "translates valid nulls to nil" do
|
@@ -109,7 +109,7 @@ module ResolverSpecs
|
|
109
109
|
- null
|
110
110
|
YAML
|
111
111
|
|
112
|
-
result.
|
112
|
+
expect(result).to eq([nil] * 3)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "matches the behavior of the underlying YAML engine w/ respect to capitalization of boolean values" do
|
@@ -143,12 +143,12 @@ module ResolverSpecs
|
|
143
143
|
|
144
144
|
it "translates quoted empty strings to strings (not nil)" do
|
145
145
|
parse "foo: ''"
|
146
|
-
result.
|
146
|
+
expect(result).to eq({ "foo" => "" })
|
147
147
|
end
|
148
148
|
|
149
149
|
it "correctly reverse-translates strings encoded via #to_yaml" do
|
150
150
|
parse "5.10".to_yaml
|
151
|
-
result.
|
151
|
+
expect(result).to eq("5.10")
|
152
152
|
end
|
153
153
|
|
154
154
|
it "does not specially parse any double-quoted strings" do
|
@@ -161,7 +161,7 @@ module ResolverSpecs
|
|
161
161
|
- "2013-02-03 16:27:00 -0600"
|
162
162
|
YAML
|
163
163
|
|
164
|
-
result.
|
164
|
+
expect(result).to eq(["1", "3.14", "true", "false", "2013-02-03", "2013-02-03 16:27:00 -0600"])
|
165
165
|
end
|
166
166
|
|
167
167
|
it "does not specially parse any single-quoted strings" do
|
@@ -174,7 +174,7 @@ module ResolverSpecs
|
|
174
174
|
- '2013-02-03 16:27:00 -0600'
|
175
175
|
YAML
|
176
176
|
|
177
|
-
result.
|
177
|
+
expect(result).to eq(["1", "3.14", "true", "false", "2013-02-03", "2013-02-03 16:27:00 -0600"])
|
178
178
|
end
|
179
179
|
|
180
180
|
it "deals just fine with nested maps" do
|
@@ -184,7 +184,7 @@ module ResolverSpecs
|
|
184
184
|
marco: polo
|
185
185
|
YAML
|
186
186
|
|
187
|
-
result.
|
187
|
+
expect(result).to eq({ "foo" => { "bar" => { "marco" => "polo" } } })
|
188
188
|
end
|
189
189
|
|
190
190
|
it "deals just fine with nested sequences" do
|
@@ -198,7 +198,7 @@ module ResolverSpecs
|
|
198
198
|
- baz2
|
199
199
|
YAML
|
200
200
|
|
201
|
-
result.
|
201
|
+
expect(result).to eq(["foo", ["bar1", "bar2", ["baz1", "baz2"]]])
|
202
202
|
end
|
203
203
|
|
204
204
|
it "applies the same transformations to keys as to values" do
|
@@ -210,13 +210,13 @@ module ResolverSpecs
|
|
210
210
|
2013-01-24: date
|
211
211
|
YAML
|
212
212
|
|
213
|
-
result.
|
213
|
+
expect(result).to eq({
|
214
214
|
"foo" => "string",
|
215
215
|
":bar" => "symbol",
|
216
216
|
1 => "integer",
|
217
217
|
3.14 => "float",
|
218
218
|
Date.parse("2013-01-24") => "date",
|
219
|
-
}
|
219
|
+
})
|
220
220
|
end
|
221
221
|
|
222
222
|
it "applies the same transformations to elements in sequences as to all values" do
|
@@ -228,24 +228,24 @@ module ResolverSpecs
|
|
228
228
|
- 2013-01-24
|
229
229
|
YAML
|
230
230
|
|
231
|
-
result.
|
231
|
+
expect(result).to eq(["foo", ":bar", 1, 3.14, Date.parse("2013-01-24")])
|
232
232
|
end
|
233
233
|
end
|
234
234
|
|
235
235
|
context "for Ruby version #{RUBY_VERSION}" do
|
236
236
|
it "translates valid time values" do
|
237
237
|
parse "time: 2013-01-29 05:58:00 -0800"
|
238
|
-
result.
|
238
|
+
expect(result).to eq({ "time" => Time.utc(2013, 1, 29, 13, 58, 0) })
|
239
239
|
end
|
240
240
|
|
241
241
|
it "applies the same transformation to elements in sequences" do
|
242
242
|
parse "- 2013-01-29 05:58:00 -0800"
|
243
|
-
result.
|
243
|
+
expect(result).to eq([Time.utc(2013, 1, 29, 13, 58, 0)])
|
244
244
|
end
|
245
245
|
|
246
246
|
it "applies the same transformation to keys" do
|
247
247
|
parse "2013-01-29 05:58:00 -0800: time"
|
248
|
-
result.
|
248
|
+
expect(result).to eq({ Time.utc(2013, 1, 29, 13, 58, 0) => "time" })
|
249
249
|
end
|
250
250
|
end
|
251
251
|
|
@@ -260,17 +260,17 @@ module ResolverSpecs
|
|
260
260
|
|
261
261
|
it "translates values starting with ':' to symbols" do
|
262
262
|
parse "symbol: :value"
|
263
|
-
result.
|
263
|
+
expect(result).to eq({ "symbol" => :value })
|
264
264
|
end
|
265
265
|
|
266
266
|
it "applies the same transformation to keys" do
|
267
267
|
parse ":bar: symbol"
|
268
|
-
result.
|
268
|
+
expect(result).to eq({ :bar => "symbol" })
|
269
269
|
end
|
270
270
|
|
271
271
|
it "applies the same transformation to elements in sequences" do
|
272
272
|
parse "- :bar"
|
273
|
-
result.
|
273
|
+
expect(result).to eq([:bar])
|
274
274
|
end
|
275
275
|
end
|
276
276
|
end
|
data/spec/safe_yaml_spec.rb
CHANGED
@@ -28,18 +28,18 @@ describe YAML do
|
|
28
28
|
if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.3"
|
29
29
|
it "allows exploits through objects defined in YAML w/ !ruby/hash via custom :[]= methods" do
|
30
30
|
backdoor = YAML.unsafe_load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
|
31
|
-
backdoor.
|
31
|
+
expect(backdoor).to be_exploited_through_setter
|
32
32
|
end
|
33
33
|
|
34
34
|
it "allows exploits through objects defined in YAML w/ !ruby/object via the :init_with method" do
|
35
35
|
backdoor = YAML.unsafe_load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
36
|
-
backdoor.
|
36
|
+
expect(backdoor).to be_exploited_through_init_with
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
it "allows exploits through objects w/ sensitive instance variables defined in YAML w/ !ruby/object" do
|
41
41
|
backdoor = YAML.unsafe_load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
42
|
-
backdoor.
|
42
|
+
expect(backdoor).to be_exploited_through_ivars
|
43
43
|
end
|
44
44
|
|
45
45
|
context "with special whitelisted tags defined" do
|
@@ -55,8 +55,8 @@ describe YAML do
|
|
55
55
|
foo: bar
|
56
56
|
YAML
|
57
57
|
|
58
|
-
result.
|
59
|
-
result.backdoor.
|
58
|
+
expect(result).to be_a(OpenStruct)
|
59
|
+
expect(result.backdoor).to be_exploited_through_ivars
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -64,12 +64,12 @@ describe YAML do
|
|
64
64
|
describe "safe_load" do
|
65
65
|
it "does NOT allow exploits through objects defined in YAML w/ !ruby/hash" do
|
66
66
|
object = YAML.safe_load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
|
67
|
-
object.
|
67
|
+
expect(object).not_to be_a(ExploitableBackDoor)
|
68
68
|
end
|
69
69
|
|
70
70
|
it "does NOT allow exploits through objects defined in YAML w/ !ruby/object" do
|
71
71
|
object = YAML.safe_load("--- !ruby/object:ExploitableBackDoor\nfoo: bar\n")
|
72
|
-
object.
|
72
|
+
expect(object).not_to be_a(ExploitableBackDoor)
|
73
73
|
end
|
74
74
|
|
75
75
|
context "for YAML engine #{SafeYAML::YAML_ENGINE}" do
|
@@ -79,7 +79,7 @@ describe YAML do
|
|
79
79
|
|
80
80
|
context "when no tags are whitelisted" do
|
81
81
|
it "constructs a SafeYAML::PsychHandler to resolve nodes as they're parsed, for optimal performance" do
|
82
|
-
Psych::Parser.
|
82
|
+
expect(Psych::Parser).to receive(:new).with an_instance_of(SafeYAML::PsychHandler)
|
83
83
|
# This won't work now; we just want to ensure Psych::Parser#parse was in fact called.
|
84
84
|
YAML.safe_load(*arguments) rescue nil
|
85
85
|
end
|
@@ -91,7 +91,7 @@ describe YAML do
|
|
91
91
|
}
|
92
92
|
|
93
93
|
it "instead uses Psych to construct a full tree before examining the nodes" do
|
94
|
-
Psych.
|
94
|
+
expect(Psych).to receive(:parse)
|
95
95
|
# This won't work now; we just want to ensure Psych::Parser#parse was in fact called.
|
96
96
|
YAML.safe_load(*arguments) rescue nil
|
97
97
|
end
|
@@ -100,7 +100,7 @@ describe YAML do
|
|
100
100
|
|
101
101
|
if SafeYAML::YAML_ENGINE == "syck"
|
102
102
|
it "uses Syck internally to parse YAML" do
|
103
|
-
YAML.
|
103
|
+
expect(YAML).to receive(:parse).with("foo: bar")
|
104
104
|
# This won't work now; we just want to ensure YAML::parse was in fact called.
|
105
105
|
YAML.safe_load("foo: bar") rescue nil
|
106
106
|
end
|
@@ -120,7 +120,7 @@ describe YAML do
|
|
120
120
|
- bye
|
121
121
|
YAML
|
122
122
|
|
123
|
-
result.
|
123
|
+
expect(result).to eq({
|
124
124
|
"foo" => {
|
125
125
|
"number" => 1,
|
126
126
|
"boolean" => true,
|
@@ -129,7 +129,7 @@ describe YAML do
|
|
129
129
|
"symbol" => ":blah",
|
130
130
|
"sequence" => ["hi", "bye"]
|
131
131
|
}
|
132
|
-
}
|
132
|
+
})
|
133
133
|
end
|
134
134
|
|
135
135
|
it "works for YAML documents with anchors and aliases" do
|
@@ -139,7 +139,7 @@ describe YAML do
|
|
139
139
|
- *id001
|
140
140
|
YAML
|
141
141
|
|
142
|
-
result.
|
142
|
+
expect(result).to eq([{}, {}, {}])
|
143
143
|
end
|
144
144
|
|
145
145
|
it "works for YAML documents with binary tagged keys" do
|
@@ -152,7 +152,7 @@ describe YAML do
|
|
152
152
|
: "baz"
|
153
153
|
YAML
|
154
154
|
|
155
|
-
result.
|
155
|
+
expect(result).to eq({"foo" => "bar", "bar" => "baz"})
|
156
156
|
end
|
157
157
|
|
158
158
|
it "works for YAML documents with binary tagged values" do
|
@@ -163,7 +163,7 @@ describe YAML do
|
|
163
163
|
YmF6
|
164
164
|
YAML
|
165
165
|
|
166
|
-
result.
|
166
|
+
expect(result).to eq({"foo" => "bar", "bar" => "baz"})
|
167
167
|
end
|
168
168
|
|
169
169
|
it "works for YAML documents with binary tagged array values" do
|
@@ -174,7 +174,7 @@ describe YAML do
|
|
174
174
|
YmFy
|
175
175
|
YAML
|
176
176
|
|
177
|
-
result.
|
177
|
+
expect(result).to eq(["foo", "bar"])
|
178
178
|
end
|
179
179
|
|
180
180
|
it "works for YAML documents with sections" do
|
@@ -191,7 +191,7 @@ describe YAML do
|
|
191
191
|
host: localhost
|
192
192
|
YAML
|
193
193
|
|
194
|
-
result.
|
194
|
+
expect(result).to eq({
|
195
195
|
"mysql" => {
|
196
196
|
"adapter" => "mysql",
|
197
197
|
"pool" => 30
|
@@ -207,7 +207,7 @@ describe YAML do
|
|
207
207
|
"password" => "password123",
|
208
208
|
"host" => "localhost"
|
209
209
|
}
|
210
|
-
}
|
210
|
+
})
|
211
211
|
end
|
212
212
|
|
213
213
|
it "correctly prefers explicitly defined values over default values from included sections" do
|
@@ -225,11 +225,11 @@ describe YAML do
|
|
225
225
|
baz: custom_baz
|
226
226
|
YAML
|
227
227
|
|
228
|
-
result["custom"].
|
228
|
+
expect(result["custom"]).to eq({
|
229
229
|
"foo" => "foo",
|
230
230
|
"bar" => "custom_bar",
|
231
231
|
"baz" => "custom_baz"
|
232
|
-
}
|
232
|
+
})
|
233
233
|
end
|
234
234
|
end
|
235
235
|
|
@@ -247,26 +247,26 @@ describe YAML do
|
|
247
247
|
<<: *custom
|
248
248
|
YAML
|
249
249
|
|
250
|
-
result.
|
250
|
+
expect(result).to eq({
|
251
251
|
"defaults" => { "foo" => "foo", "bar" => "bar", "baz" => "baz" },
|
252
252
|
"custom" => { "foo" => "foo", "bar" => "custom_bar", "baz" => "custom_baz" },
|
253
253
|
"grandcustom" => { "foo" => "foo", "bar" => "custom_bar", "baz" => "custom_baz" }
|
254
|
-
}
|
254
|
+
})
|
255
255
|
end
|
256
256
|
|
257
257
|
it "returns false when parsing an empty document" do
|
258
|
-
[
|
258
|
+
expect([
|
259
259
|
YAML.safe_load(""),
|
260
260
|
YAML.safe_load(" "),
|
261
261
|
YAML.safe_load("\n")
|
262
|
-
].
|
262
|
+
]).to eq([false, false, false])
|
263
263
|
end
|
264
264
|
|
265
265
|
it "returns nil when parsing a single value representing nil" do
|
266
|
-
[
|
266
|
+
expect([
|
267
267
|
YAML.safe_load("~"),
|
268
268
|
YAML.safe_load("null")
|
269
|
-
].
|
269
|
+
]).to eq([nil, nil])
|
270
270
|
end
|
271
271
|
|
272
272
|
context "with custom initializers defined" do
|
@@ -292,8 +292,8 @@ describe YAML do
|
|
292
292
|
- 3
|
293
293
|
YAML
|
294
294
|
|
295
|
-
result.
|
296
|
-
result.to_a.
|
295
|
+
expect(result).to be_a(Set)
|
296
|
+
expect(result.to_a).to match_array([1, 2, 3])
|
297
297
|
end
|
298
298
|
|
299
299
|
it "will use a custom initializer to instantiate a hash-like class upon deserialization" do
|
@@ -302,8 +302,8 @@ describe YAML do
|
|
302
302
|
foo: bar
|
303
303
|
YAML
|
304
304
|
|
305
|
-
result.
|
306
|
-
result.to_hash.
|
305
|
+
expect(result).to be_a(Hashie::Mash)
|
306
|
+
expect(result.to_hash).to eq({ "foo" => "bar" })
|
307
307
|
end
|
308
308
|
end
|
309
309
|
|
@@ -317,14 +317,14 @@ describe YAML do
|
|
317
317
|
|
318
318
|
it "will allow objects to be deserialized for whitelisted tags" do
|
319
319
|
result = YAML.safe_load("--- !ruby/object:OpenStruct\ntable:\n foo: bar\n")
|
320
|
-
result.
|
321
|
-
result.instance_variable_get(:@table).
|
320
|
+
expect(result).to be_a(OpenStruct)
|
321
|
+
expect(result.instance_variable_get(:@table)).to eq({ "foo" => "bar" })
|
322
322
|
end
|
323
323
|
|
324
324
|
it "will not deserialize objects without whitelisted tags" do
|
325
325
|
result = YAML.safe_load("--- !ruby/hash:ExploitableBackDoor\nfoo: bar\n")
|
326
|
-
result.
|
327
|
-
result.
|
326
|
+
expect(result).not_to be_a(ExploitableBackDoor)
|
327
|
+
expect(result).to eq({ "foo" => "bar" })
|
328
328
|
end
|
329
329
|
|
330
330
|
it "will not allow non-whitelisted objects to be embedded within objects with whitelisted tags" do
|
@@ -335,9 +335,9 @@ describe YAML do
|
|
335
335
|
foo: bar
|
336
336
|
YAML
|
337
337
|
|
338
|
-
result.
|
339
|
-
result.backdoor.
|
340
|
-
result.backdoor.
|
338
|
+
expect(result).to be_a(OpenStruct)
|
339
|
+
expect(result.backdoor).not_to be_a(ExploitableBackDoor)
|
340
|
+
expect(result.backdoor).to eq({ "foo" => "bar" })
|
341
341
|
end
|
342
342
|
|
343
343
|
context "with the :raise_on_unknown_tag option enabled" do
|
@@ -350,23 +350,23 @@ describe YAML do
|
|
350
350
|
end
|
351
351
|
|
352
352
|
it "raises an exception if a non-nil, non-whitelisted tag is encountered" do
|
353
|
-
|
353
|
+
expect {
|
354
354
|
YAML.safe_load <<-YAML.unindent
|
355
355
|
--- !ruby/object:Unknown
|
356
356
|
foo: bar
|
357
357
|
YAML
|
358
|
-
}.
|
358
|
+
}.to raise_error
|
359
359
|
end
|
360
360
|
|
361
361
|
it "checks all tags, even those within objects with trusted tags" do
|
362
|
-
|
362
|
+
expect {
|
363
363
|
YAML.safe_load <<-YAML.unindent
|
364
364
|
--- !ruby/object:OpenStruct
|
365
365
|
table:
|
366
366
|
:backdoor: !ruby/object:Unknown
|
367
367
|
foo: bar
|
368
368
|
YAML
|
369
|
-
}.
|
369
|
+
}.to raise_error
|
370
370
|
end
|
371
371
|
|
372
372
|
it "does not raise an exception as long as all tags are whitelisted" do
|
@@ -383,8 +383,8 @@ describe YAML do
|
|
383
383
|
hash: {}
|
384
384
|
YAML
|
385
385
|
|
386
|
-
result.
|
387
|
-
result.backdoor.
|
386
|
+
expect(result).to be_a(OpenStruct)
|
387
|
+
expect(result.backdoor).to eq({
|
388
388
|
"string" => "foo",
|
389
389
|
"integer" => 1,
|
390
390
|
"float" => 3.14,
|
@@ -392,13 +392,13 @@ describe YAML do
|
|
392
392
|
"date" => Date.parse("2013-02-20"),
|
393
393
|
"array" => [],
|
394
394
|
"hash" => {}
|
395
|
-
}
|
395
|
+
})
|
396
396
|
end
|
397
397
|
|
398
398
|
it "does not raise an exception on the non-specific '!' tag" do
|
399
399
|
result = nil
|
400
400
|
expect { result = YAML.safe_load "--- ! 'foo'" }.to_not raise_error
|
401
|
-
result.
|
401
|
+
expect(result).to eq("foo")
|
402
402
|
end
|
403
403
|
|
404
404
|
context "with whitelisted custom class" do
|
@@ -415,7 +415,7 @@ describe YAML do
|
|
415
415
|
it "does not raise an exception on the non-specific '!' tag" do
|
416
416
|
result = nil
|
417
417
|
expect { result = YAML.safe_load(instance.to_yaml) }.to_not raise_error
|
418
|
-
result.foo.
|
418
|
+
expect(result.foo).to eq('with trailing whitespace: ')
|
419
419
|
end
|
420
420
|
end
|
421
421
|
end
|
@@ -433,14 +433,14 @@ describe YAML do
|
|
433
433
|
|
434
434
|
it "goes with the default option when it is not overridden" do
|
435
435
|
silence_warnings do
|
436
|
-
YAML.load(":foo: bar").
|
436
|
+
expect(YAML.load(":foo: bar")).to eq({ :foo => "bar" })
|
437
437
|
end
|
438
438
|
end
|
439
439
|
|
440
440
|
it "allows the default option to be overridden on a per-call basis" do
|
441
441
|
silence_warnings do
|
442
|
-
YAML.load(":foo: bar", :deserialize_symbols => false).
|
443
|
-
YAML.load(":foo: bar", :deserialize_symbols => true).
|
442
|
+
expect(YAML.load(":foo: bar", :deserialize_symbols => false)).to eq({ ":foo" => "bar" })
|
443
|
+
expect(YAML.load(":foo: bar", :deserialize_symbols => true)).to eq({ :foo => "bar" })
|
444
444
|
end
|
445
445
|
end
|
446
446
|
end
|
@@ -457,16 +457,16 @@ describe YAML do
|
|
457
457
|
|
458
458
|
it "goes with the default option when it is not overridden" do
|
459
459
|
result = safe_load_round_trip(OpenStruct.new(:foo => "bar"))
|
460
|
-
result.
|
461
|
-
result.foo.
|
460
|
+
expect(result).to be_a(OpenStruct)
|
461
|
+
expect(result.foo).to eq("bar")
|
462
462
|
end
|
463
463
|
|
464
464
|
it "allows the default option to be overridden on a per-call basis" do
|
465
465
|
result = safe_load_round_trip(OpenStruct.new(:foo => "bar"), :whitelisted_tags => [])
|
466
|
-
result.
|
466
|
+
expect(result).to eq({ "table" => { :foo => "bar" } })
|
467
467
|
|
468
468
|
result = safe_load_round_trip(OpenStruct.new(:foo => "bar"), :deserialize_symbols => false, :whitelisted_tags => [])
|
469
|
-
result.
|
469
|
+
expect(result).to eq({ "table" => { ":foo" => "bar" } })
|
470
470
|
end
|
471
471
|
end
|
472
472
|
end
|
@@ -476,36 +476,36 @@ describe YAML do
|
|
476
476
|
if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.3"
|
477
477
|
it "allows exploits through objects defined in YAML w/ !ruby/hash via custom :[]= methods" do
|
478
478
|
backdoor = YAML.unsafe_load_file "spec/exploit.1.9.3.yaml"
|
479
|
-
backdoor.
|
479
|
+
expect(backdoor).to be_exploited_through_setter
|
480
480
|
end
|
481
481
|
end
|
482
482
|
|
483
483
|
if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.2"
|
484
484
|
it "allows exploits through objects defined in YAML w/ !ruby/object via the :init_with method" do
|
485
485
|
backdoor = YAML.unsafe_load_file "spec/exploit.1.9.2.yaml"
|
486
|
-
backdoor.
|
486
|
+
expect(backdoor).to be_exploited_through_init_with
|
487
487
|
end
|
488
488
|
end
|
489
489
|
|
490
490
|
it "allows exploits through objects w/ sensitive instance variables defined in YAML w/ !ruby/object" do
|
491
491
|
backdoor = YAML.unsafe_load_file "spec/exploit.1.9.2.yaml"
|
492
|
-
backdoor.
|
492
|
+
expect(backdoor).to be_exploited_through_ivars
|
493
493
|
end
|
494
494
|
end
|
495
495
|
|
496
496
|
describe "safe_load_file" do
|
497
497
|
it "does NOT allow exploits through objects defined in YAML w/ !ruby/hash" do
|
498
498
|
object = YAML.safe_load_file "spec/exploit.1.9.3.yaml"
|
499
|
-
object.
|
499
|
+
expect(object).not_to be_a(ExploitableBackDoor)
|
500
500
|
end
|
501
501
|
|
502
502
|
it "does NOT allow exploits through objects defined in YAML w/ !ruby/object" do
|
503
503
|
object = YAML.safe_load_file "spec/exploit.1.9.2.yaml"
|
504
|
-
object.
|
504
|
+
expect(object).not_to be_a(ExploitableBackDoor)
|
505
505
|
end
|
506
506
|
|
507
507
|
it "returns false when parsing an empty file" do
|
508
|
-
YAML.safe_load_file("spec/issue49.yml").
|
508
|
+
expect(YAML.safe_load_file("spec/issue49.yml")).to eq(false)
|
509
509
|
end
|
510
510
|
end
|
511
511
|
|
@@ -523,13 +523,13 @@ describe YAML do
|
|
523
523
|
context "as long as a :default_mode has been specified" do
|
524
524
|
it "doesn't issue a warning for safe mode, since an explicit mode has been set" do
|
525
525
|
SafeYAML::OPTIONS[:default_mode] = :safe
|
526
|
-
Kernel.
|
526
|
+
expect(Kernel).not_to receive(:warn)
|
527
527
|
YAML.load(*arguments)
|
528
528
|
end
|
529
529
|
|
530
530
|
it "doesn't issue a warning for unsafe mode, since an explicit mode has been set" do
|
531
531
|
SafeYAML::OPTIONS[:default_mode] = :unsafe
|
532
|
-
Kernel.
|
532
|
+
expect(Kernel).not_to receive(:warn)
|
533
533
|
YAML.load(*arguments)
|
534
534
|
end
|
535
535
|
end
|
@@ -539,12 +539,12 @@ describe YAML do
|
|
539
539
|
let(:options) { { :safe => safe_mode } }
|
540
540
|
|
541
541
|
it "doesn't issue a warning" do
|
542
|
-
Kernel.
|
542
|
+
expect(Kernel).not_to receive(:warn)
|
543
543
|
YAML.load(*arguments)
|
544
544
|
end
|
545
545
|
|
546
546
|
it "calls #safe_load if the :safe option is set to true" do
|
547
|
-
YAML.
|
547
|
+
expect(YAML).to receive(:safe_load)
|
548
548
|
YAML.load(*arguments)
|
549
549
|
end
|
550
550
|
|
@@ -552,7 +552,7 @@ describe YAML do
|
|
552
552
|
let(:safe_mode) { false }
|
553
553
|
|
554
554
|
it "calls #unsafe_load if the :safe option is set to false" do
|
555
|
-
YAML.
|
555
|
+
expect(YAML).to receive(:unsafe_load)
|
556
556
|
YAML.load(*arguments)
|
557
557
|
end
|
558
558
|
end
|
@@ -560,21 +560,21 @@ describe YAML do
|
|
560
560
|
|
561
561
|
it "issues a warning when the :safe option is omitted" do
|
562
562
|
silence_warnings do
|
563
|
-
Kernel.
|
563
|
+
expect(Kernel).to receive(:warn)
|
564
564
|
YAML.load(*arguments)
|
565
565
|
end
|
566
566
|
end
|
567
567
|
|
568
568
|
it "only issues a warning once (to avoid spamming an app's output)" do
|
569
569
|
silence_warnings do
|
570
|
-
Kernel.
|
570
|
+
expect(Kernel).to receive(:warn).once
|
571
571
|
2.times { YAML.load(*arguments) }
|
572
572
|
end
|
573
573
|
end
|
574
574
|
|
575
575
|
it "defaults to safe mode if the :safe option is omitted" do
|
576
576
|
silence_warnings do
|
577
|
-
YAML.
|
577
|
+
expect(YAML).to receive(:safe_load)
|
578
578
|
YAML.load(*arguments)
|
579
579
|
end
|
580
580
|
end
|
@@ -586,13 +586,13 @@ describe YAML do
|
|
586
586
|
|
587
587
|
it "defaults to unsafe mode if the :safe option is omitted" do
|
588
588
|
silence_warnings do
|
589
|
-
YAML.
|
589
|
+
expect(YAML).to receive(:unsafe_load)
|
590
590
|
YAML.load(*arguments)
|
591
591
|
end
|
592
592
|
end
|
593
593
|
|
594
594
|
it "calls #safe_load if the :safe option is set to true" do
|
595
|
-
YAML.
|
595
|
+
expect(YAML).to receive(:safe_load)
|
596
596
|
YAML.load(*(arguments + [{ :safe => true }]))
|
597
597
|
end
|
598
598
|
end
|
@@ -603,30 +603,30 @@ describe YAML do
|
|
603
603
|
|
604
604
|
it "issues a warning if the :safe option is omitted" do
|
605
605
|
silence_warnings do
|
606
|
-
Kernel.
|
606
|
+
expect(Kernel).to receive(:warn)
|
607
607
|
YAML.load_file(filename)
|
608
608
|
end
|
609
609
|
end
|
610
610
|
|
611
611
|
it "doesn't issue a warning as long as the :safe option is specified" do
|
612
|
-
Kernel.
|
612
|
+
expect(Kernel).not_to receive(:warn)
|
613
613
|
YAML.load_file(filename, :safe => true)
|
614
614
|
end
|
615
615
|
|
616
616
|
it "defaults to safe mode if the :safe option is omitted" do
|
617
617
|
silence_warnings do
|
618
|
-
YAML.
|
618
|
+
expect(YAML).to receive(:safe_load_file)
|
619
619
|
YAML.load_file(filename)
|
620
620
|
end
|
621
621
|
end
|
622
622
|
|
623
623
|
it "calls #safe_load_file if the :safe option is set to true" do
|
624
|
-
YAML.
|
624
|
+
expect(YAML).to receive(:safe_load_file)
|
625
625
|
YAML.load_file(filename, :safe => true)
|
626
626
|
end
|
627
627
|
|
628
628
|
it "calls #unsafe_load_file if the :safe option is set to false" do
|
629
|
-
YAML.
|
629
|
+
expect(YAML).to receive(:unsafe_load_file)
|
630
630
|
YAML.load_file(filename, :safe => false)
|
631
631
|
end
|
632
632
|
|
@@ -637,30 +637,30 @@ describe YAML do
|
|
637
637
|
|
638
638
|
it "defaults to unsafe mode if the :safe option is omitted" do
|
639
639
|
silence_warnings do
|
640
|
-
YAML.
|
640
|
+
expect(YAML).to receive(:unsafe_load_file)
|
641
641
|
YAML.load_file(filename)
|
642
642
|
end
|
643
643
|
end
|
644
644
|
|
645
645
|
it "calls #safe_load if the :safe option is set to true" do
|
646
|
-
YAML.
|
646
|
+
expect(YAML).to receive(:safe_load_file)
|
647
647
|
YAML.load_file(filename, :safe => true)
|
648
648
|
end
|
649
649
|
end
|
650
650
|
|
651
651
|
it "handles files starting with --- (see issue #48)" do
|
652
|
-
YAML.load_file("spec/issue48.txt", :safe => true).
|
652
|
+
expect(YAML.load_file("spec/issue48.txt", :safe => true)).to eq({
|
653
653
|
"title" => "Blah",
|
654
654
|
"key" => "value"
|
655
|
-
}
|
655
|
+
})
|
656
656
|
end
|
657
657
|
|
658
658
|
it "handles content starting with --- (see issue #48)" do
|
659
659
|
yaml = File.read("spec/issue48.txt")
|
660
|
-
YAML.load(yaml, :safe => true).
|
660
|
+
expect(YAML.load(yaml, :safe => true)).to eq({
|
661
661
|
"title" => "Blah",
|
662
662
|
"key" => "value"
|
663
|
-
}
|
663
|
+
})
|
664
664
|
end
|
665
665
|
end
|
666
666
|
|
@@ -668,21 +668,21 @@ describe YAML do
|
|
668
668
|
context "not a class" do
|
669
669
|
it "should raise" do
|
670
670
|
expect { SafeYAML::whitelist! :foo }.to raise_error(/not a Class/)
|
671
|
-
SafeYAML::OPTIONS[:whitelisted_tags].
|
671
|
+
expect(SafeYAML::OPTIONS[:whitelisted_tags]).to be_empty
|
672
672
|
end
|
673
673
|
end
|
674
674
|
|
675
675
|
context "anonymous class" do
|
676
676
|
it "should raise" do
|
677
677
|
expect { SafeYAML::whitelist! Class.new }.to raise_error(/cannot be anonymous/)
|
678
|
-
SafeYAML::OPTIONS[:whitelisted_tags].
|
678
|
+
expect(SafeYAML::OPTIONS[:whitelisted_tags]).to be_empty
|
679
679
|
end
|
680
680
|
end
|
681
681
|
|
682
682
|
context "with a Class as its argument" do
|
683
683
|
it "should configure correctly" do
|
684
684
|
expect { SafeYAML::whitelist! OpenStruct }.to_not raise_error
|
685
|
-
SafeYAML::OPTIONS[:whitelisted_tags].grep(/OpenStruct\Z/).
|
685
|
+
expect(SafeYAML::OPTIONS[:whitelisted_tags].grep(/OpenStruct\Z/)).not_to be_empty
|
686
686
|
end
|
687
687
|
|
688
688
|
it "successfully deserializes the specified class" do
|
@@ -692,23 +692,23 @@ describe YAML do
|
|
692
692
|
SafeYAML::OPTIONS[:deserialize_symbols] = true
|
693
693
|
|
694
694
|
result = safe_load_round_trip(OpenStruct.new(:foo => "bar"))
|
695
|
-
result.
|
696
|
-
result.foo.
|
695
|
+
expect(result).to be_a(OpenStruct)
|
696
|
+
expect(result.foo).to eq("bar")
|
697
697
|
end
|
698
698
|
|
699
699
|
it "works for ranges" do
|
700
700
|
SafeYAML.whitelist!(Range)
|
701
|
-
safe_load_round_trip(1..10).
|
701
|
+
expect(safe_load_round_trip(1..10)).to eq(1..10)
|
702
702
|
end
|
703
703
|
|
704
704
|
it "works for regular expressions" do
|
705
705
|
SafeYAML.whitelist!(Regexp)
|
706
|
-
safe_load_round_trip(/foo/).
|
706
|
+
expect(safe_load_round_trip(/foo/)).to eq(/foo/)
|
707
707
|
end
|
708
708
|
|
709
709
|
it "works for multiple classes" do
|
710
710
|
SafeYAML.whitelist!(Range, Regexp)
|
711
|
-
safe_load_round_trip([(1..10), /bar/]).
|
711
|
+
expect(safe_load_round_trip([(1..10), /bar/])).to eq([(1..10), /bar/])
|
712
712
|
end
|
713
713
|
|
714
714
|
it "works for arbitrary Exception subclasses" do
|
@@ -723,8 +723,8 @@ describe YAML do
|
|
723
723
|
SafeYAML.whitelist!(CustomException)
|
724
724
|
|
725
725
|
ex = safe_load_round_trip(CustomException.new("blah"))
|
726
|
-
ex.
|
727
|
-
ex.custom_message.
|
726
|
+
expect(ex).to be_a(CustomException)
|
727
|
+
expect(ex.custom_message).to eq("blah")
|
728
728
|
end
|
729
729
|
end
|
730
730
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -13,13 +13,13 @@ ruby_version = defined?(JRUBY_VERSION) ? "JRuby #{JRUBY_VERSION} in #{RUBY_VERSI
|
|
13
13
|
yaml_engine = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
|
14
14
|
libyaml_version = yaml_engine == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : "N/A"
|
15
15
|
|
16
|
-
|
16
|
+
env_info = [
|
17
|
+
ruby_version,
|
18
|
+
"YAML: #{yaml_engine} (#{YAML::VERSION}) (libyaml: #{libyaml_version})",
|
19
|
+
"Monkeypatch: #{ENV['MONKEYPATCH_YAML']}"
|
20
|
+
]
|
17
21
|
|
18
|
-
|
19
|
-
YAML engine version: #{YAML::VERSION}
|
20
|
-
libyaml version: #{libyaml_version}
|
21
|
-
|
22
|
-
EOM
|
22
|
+
puts env_info.join(", ")
|
23
23
|
|
24
24
|
# Caching references to these methods before loading safe_yaml in order to test
|
25
25
|
# that they aren't touched unless you actually require safe_yaml (see yaml_spec.rb).
|
@@ -5,7 +5,7 @@ describe SafeYAML::Transform do
|
|
5
5
|
value = "c3VyZS4="
|
6
6
|
decoded = SafeYAML::Transform.to_proper_type(value, false, "!binary")
|
7
7
|
|
8
|
-
decoded.
|
9
|
-
decoded.encoding.
|
8
|
+
expect(decoded).to eq("sure.")
|
9
|
+
expect(decoded.encoding).to eq(value.encoding) if decoded.respond_to?(:encoding)
|
10
10
|
end
|
11
11
|
end
|
@@ -2,19 +2,19 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe SafeYAML::Transform::ToDate do
|
4
4
|
it "returns true when the value matches a valid Date" do
|
5
|
-
subject.transform?("2013-01-01").
|
5
|
+
expect(subject.transform?("2013-01-01")).to eq([true, Date.parse("2013-01-01")])
|
6
6
|
end
|
7
7
|
|
8
8
|
it "returns false when the value does not match a valid Date" do
|
9
|
-
subject.transform?("foobar").
|
9
|
+
expect(subject.transform?("foobar")).to be_falsey
|
10
10
|
end
|
11
11
|
|
12
12
|
it "returns false when the value does not end with a Date" do
|
13
|
-
subject.transform?("2013-01-01\nNOT A DATE").
|
13
|
+
expect(subject.transform?("2013-01-01\nNOT A DATE")).to be_falsey
|
14
14
|
end
|
15
15
|
|
16
16
|
it "returns false when the value does not begin with a Date" do
|
17
|
-
subject.transform?("NOT A DATE\n2013-01-01").
|
17
|
+
expect(subject.transform?("NOT A DATE\n2013-01-01")).to be_falsey
|
18
18
|
end
|
19
19
|
|
20
20
|
it "correctly parses the remaining formats of the YAML spec" do
|
@@ -27,30 +27,30 @@ describe SafeYAML::Transform::ToDate do
|
|
27
27
|
|
28
28
|
equivalent_values.each do |value|
|
29
29
|
success, result = subject.transform?(value)
|
30
|
-
success.
|
31
|
-
result.
|
30
|
+
expect(success).to be_truthy
|
31
|
+
expect(result).to eq(Time.utc(2001, 12, 15, 2, 59, 43, 100000))
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
it "converts times to the local timezone" do
|
36
36
|
success, result = subject.transform?("2012-12-01 10:33:45 +11:00")
|
37
|
-
success.
|
38
|
-
result.
|
39
|
-
result.gmt_offset.
|
37
|
+
expect(success).to be_truthy
|
38
|
+
expect(result).to eq(Time.utc(2012, 11, 30, 23, 33, 45))
|
39
|
+
expect(result.gmt_offset).to eq(Time.local(2012, 11, 30).gmt_offset)
|
40
40
|
end
|
41
41
|
|
42
42
|
it "returns strings for invalid dates" do
|
43
|
-
subject.transform?("0000-00-00").
|
44
|
-
subject.transform?("2013-13-01").
|
45
|
-
subject.transform?("2014-01-32").
|
43
|
+
expect(subject.transform?("0000-00-00")).to eq([true, "0000-00-00"])
|
44
|
+
expect(subject.transform?("2013-13-01")).to eq([true, "2013-13-01"])
|
45
|
+
expect(subject.transform?("2014-01-32")).to eq([true, "2014-01-32"])
|
46
46
|
end
|
47
47
|
|
48
48
|
it "returns strings for invalid date/times" do
|
49
|
-
subject.transform?("0000-00-00 00:00:00 -0000").
|
50
|
-
subject.transform?("2013-13-01 21:59:43 -05:00").
|
51
|
-
subject.transform?("2013-01-32 21:59:43 -05:00").
|
52
|
-
subject.transform?("2013-01-30 25:59:43 -05:00").
|
53
|
-
subject.transform?("2013-01-30 21:69:43 -05:00").
|
49
|
+
expect(subject.transform?("0000-00-00 00:00:00 -0000")).to eq([true, "0000-00-00 00:00:00 -0000"])
|
50
|
+
expect(subject.transform?("2013-13-01 21:59:43 -05:00")).to eq([true, "2013-13-01 21:59:43 -05:00"])
|
51
|
+
expect(subject.transform?("2013-01-32 21:59:43 -05:00")).to eq([true, "2013-01-32 21:59:43 -05:00"])
|
52
|
+
expect(subject.transform?("2013-01-30 25:59:43 -05:00")).to eq([true, "2013-01-30 25:59:43 -05:00"])
|
53
|
+
expect(subject.transform?("2013-01-30 21:69:43 -05:00")).to eq([true, "2013-01-30 21:69:43 -05:00"])
|
54
54
|
|
55
55
|
# Interesting. It seems that in some older Ruby versions, the below actually parses successfully
|
56
56
|
# w/ DateTime.parse; but it fails w/ YAML.load. Whom to follow???
|
@@ -2,41 +2,41 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe SafeYAML::Transform::ToFloat do
|
4
4
|
it "returns true when the value matches a valid Float" do
|
5
|
-
subject.transform?("20.00").
|
5
|
+
expect(subject.transform?("20.00")).to eq([true, 20.0])
|
6
6
|
end
|
7
7
|
|
8
8
|
it "returns false when the value does not match a valid Float" do
|
9
|
-
subject.transform?("foobar").
|
9
|
+
expect(subject.transform?("foobar")).to be_falsey
|
10
10
|
end
|
11
11
|
|
12
12
|
it "returns false when the value spans multiple lines" do
|
13
|
-
subject.transform?("20.00\nNOT A FLOAT").
|
13
|
+
expect(subject.transform?("20.00\nNOT A FLOAT")).to be_falsey
|
14
14
|
end
|
15
15
|
|
16
16
|
it "correctly parses all formats in the YAML spec" do
|
17
17
|
# canonical
|
18
|
-
subject.transform?("6.8523015e+5").
|
18
|
+
expect(subject.transform?("6.8523015e+5")).to eq([true, 685230.15])
|
19
19
|
|
20
20
|
# exponentioal
|
21
|
-
subject.transform?("685.230_15e+03").
|
21
|
+
expect(subject.transform?("685.230_15e+03")).to eq([true, 685230.15])
|
22
22
|
|
23
23
|
# fixed
|
24
|
-
subject.transform?("685_230.15").
|
24
|
+
expect(subject.transform?("685_230.15")).to eq([true, 685230.15])
|
25
25
|
|
26
26
|
# sexagesimal
|
27
|
-
subject.transform?("190:20:30.15").
|
27
|
+
expect(subject.transform?("190:20:30.15")).to eq([true, 685230.15])
|
28
28
|
|
29
29
|
# infinity
|
30
|
-
subject.transform?("-.inf").
|
30
|
+
expect(subject.transform?("-.inf")).to eq([true, (-1.0 / 0.0)])
|
31
31
|
|
32
32
|
# not a number
|
33
33
|
# NOTE: can't use == here since NaN != NaN
|
34
34
|
success, result = subject.transform?(".NaN")
|
35
|
-
success.
|
35
|
+
expect(success).to be_truthy; expect(result).to be_nan
|
36
36
|
end
|
37
37
|
|
38
38
|
# issue 29
|
39
39
|
it "returns false for the string '.'" do
|
40
|
-
subject.transform?(".").
|
40
|
+
expect(subject.transform?(".")).to be_falsey
|
41
41
|
end
|
42
42
|
end
|
@@ -2,63 +2,63 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe SafeYAML::Transform::ToInteger do
|
4
4
|
it "returns true when the value matches a valid Integer" do
|
5
|
-
subject.transform?("10").
|
5
|
+
expect(subject.transform?("10")).to eq([true, 10])
|
6
6
|
end
|
7
7
|
|
8
8
|
it "returns false when the value does not match a valid Integer" do
|
9
|
-
subject.transform?("foobar").
|
9
|
+
expect(subject.transform?("foobar")).to be_falsey
|
10
10
|
end
|
11
11
|
|
12
12
|
it "returns false when the value spans multiple lines" do
|
13
|
-
subject.transform?("10\nNOT AN INTEGER").
|
13
|
+
expect(subject.transform?("10\nNOT AN INTEGER")).to be_falsey
|
14
14
|
end
|
15
15
|
|
16
16
|
it "allows commas in the number" do
|
17
|
-
subject.transform?("1,000").
|
17
|
+
expect(subject.transform?("1,000")).to eq([true, 1000])
|
18
18
|
end
|
19
19
|
|
20
20
|
it "correctly parses numbers in octal format" do
|
21
|
-
subject.transform?("010").
|
21
|
+
expect(subject.transform?("010")).to eq([true, 8])
|
22
22
|
end
|
23
23
|
|
24
24
|
it "correctly parses numbers in hexadecimal format" do
|
25
|
-
subject.transform?("0x1FF").
|
25
|
+
expect(subject.transform?("0x1FF")).to eq([true, 511])
|
26
26
|
end
|
27
27
|
|
28
28
|
it "defaults to a string for a number that resembles octal format but is not" do
|
29
|
-
subject.transform?("09").
|
29
|
+
expect(subject.transform?("09")).to be_falsey
|
30
30
|
end
|
31
31
|
|
32
32
|
it "correctly parses 0 in decimal" do
|
33
|
-
subject.transform?("0").
|
33
|
+
expect(subject.transform?("0")).to eq([true, 0])
|
34
34
|
end
|
35
35
|
|
36
36
|
it "defaults to a string for a number that resembles hexadecimal format but is not" do
|
37
|
-
subject.transform?("0x1G").
|
37
|
+
expect(subject.transform?("0x1G")).to be_falsey
|
38
38
|
end
|
39
39
|
|
40
40
|
it "correctly parses all formats in the YAML spec" do
|
41
41
|
# canonical
|
42
|
-
subject.transform?("685230").
|
42
|
+
expect(subject.transform?("685230")).to eq([true, 685230])
|
43
43
|
|
44
44
|
# decimal
|
45
|
-
subject.transform?("+685_230").
|
45
|
+
expect(subject.transform?("+685_230")).to eq([true, 685230])
|
46
46
|
|
47
47
|
# octal
|
48
|
-
subject.transform?("02472256").
|
48
|
+
expect(subject.transform?("02472256")).to eq([true, 685230])
|
49
49
|
|
50
50
|
# hexadecimal:
|
51
|
-
subject.transform?("0x_0A_74_AE").
|
51
|
+
expect(subject.transform?("0x_0A_74_AE")).to eq([true, 685230])
|
52
52
|
|
53
53
|
# binary
|
54
|
-
subject.transform?("0b1010_0111_0100_1010_1110").
|
54
|
+
expect(subject.transform?("0b1010_0111_0100_1010_1110")).to eq([true, 685230])
|
55
55
|
|
56
56
|
# sexagesimal
|
57
|
-
subject.transform?("190:20:30").
|
57
|
+
expect(subject.transform?("190:20:30")).to eq([true, 685230])
|
58
58
|
end
|
59
59
|
|
60
60
|
# see https://github.com/dtao/safe_yaml/pull/51
|
61
61
|
it "strips out underscores before parsing decimal values" do
|
62
|
-
subject.transform?("_850_").
|
62
|
+
expect(subject.transform?("_850_")).to eq([true, 850])
|
63
63
|
end
|
64
64
|
end
|
@@ -20,32 +20,32 @@ describe SafeYAML::Transform::ToSymbol do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "returns true when the value matches a valid Symbol" do
|
23
|
-
with_symbol_deserialization { subject.transform?(":foo")[0].
|
23
|
+
with_symbol_deserialization { expect(subject.transform?(":foo")[0]).to be_truthy }
|
24
24
|
end
|
25
25
|
|
26
26
|
it "returns true when the value matches a valid String+Symbol" do
|
27
|
-
with_symbol_deserialization { subject.transform?(':"foo"')[0].
|
27
|
+
with_symbol_deserialization { expect(subject.transform?(':"foo"')[0]).to be_truthy }
|
28
28
|
end
|
29
29
|
|
30
30
|
it "returns true when the value matches a valid String+Symbol with 's" do
|
31
|
-
with_symbol_deserialization { subject.transform?(":'foo'")[0].
|
31
|
+
with_symbol_deserialization { expect(subject.transform?(":'foo'")[0]).to be_truthy }
|
32
32
|
end
|
33
33
|
|
34
34
|
it "returns true when the value has special characters and is wrapped in a String" do
|
35
|
-
with_symbol_deserialization { subject.transform?(':"foo.bar"')[0].
|
35
|
+
with_symbol_deserialization { expect(subject.transform?(':"foo.bar"')[0]).to be_truthy }
|
36
36
|
end
|
37
37
|
|
38
38
|
it "returns false when symbol deserialization is disabled" do
|
39
|
-
without_symbol_deserialization { subject.transform?(":foo").
|
39
|
+
without_symbol_deserialization { expect(subject.transform?(":foo")).to be_falsey }
|
40
40
|
end
|
41
41
|
|
42
42
|
it "returns false when the value does not match a valid Symbol" do
|
43
|
-
with_symbol_deserialization { subject.transform?("foo").
|
43
|
+
with_symbol_deserialization { expect(subject.transform?("foo")).to be_falsey }
|
44
44
|
end
|
45
45
|
|
46
46
|
it "returns false when the symbol does not begin the line" do
|
47
47
|
with_symbol_deserialization do
|
48
|
-
subject.transform?("NOT A SYMBOL\n:foo").
|
48
|
+
expect(subject.transform?("NOT A SYMBOL\n:foo")).to be_falsey
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
data/spec/yaml_spec.rb
CHANGED
@@ -5,11 +5,11 @@ require "spec_helper"
|
|
5
5
|
describe YAML do
|
6
6
|
context "when you've only required safe_yaml/load", :libraries => true do
|
7
7
|
it "YAML.load doesn't get monkey patched" do
|
8
|
-
YAML.method(:load).
|
8
|
+
expect(YAML.method(:load)).to eq(ORIGINAL_YAML_LOAD)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "YAML.load_file doesn't get monkey patched" do
|
12
|
-
YAML.method(:load_file).
|
12
|
+
expect(YAML.method(:load_file)).to eq(ORIGINAL_YAML_LOAD_FILE)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe_yaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Tao
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Parse YAML safely
|
14
14
|
email: daniel.tao@gmail.com
|
@@ -17,8 +17,8 @@ executables:
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- .gitignore
|
21
|
-
- .travis.yml
|
20
|
+
- ".gitignore"
|
21
|
+
- ".travis.yml"
|
22
22
|
- CHANGES.md
|
23
23
|
- Gemfile
|
24
24
|
- LICENSE.txt
|
@@ -78,17 +78,17 @@ require_paths:
|
|
78
78
|
- lib
|
79
79
|
required_ruby_version: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 1.8.7
|
84
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- -
|
86
|
+
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
89
|
requirements: []
|
90
90
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.1.11
|
92
92
|
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: SameYAML provides an alternative implementation of YAML.load suitable for
|