Skip to content

Commit c118a50

Browse files
committed
re-add support for loading aliases in yaml files
Ruby 3.1 includes Psych 4.0 which no longer loads aliases by default. Since aliases are part of the yaml spec, it seems sensible to re-add support. We need to read the file first to be compatible with ruby2.7 which does not support the aliases option on YAML.load_file. Use temp files in rspec tests to avoid needing to mock read.
1 parent 928ca48 commit c118a50

File tree

2 files changed

+73
-13
lines changed

2 files changed

+73
-13
lines changed

Diff for: lib/puppet/parser/functions/loadyaml.rb

+5-2
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ module Puppet::Parser::Functions
4949
warning("Can't load '#{url}' HTTP Error Code: '#{res.status[0]}'")
5050
args[1]
5151
end
52-
YAML.safe_load(contents) || args[1]
52+
YAML.safe_load(contents, aliases: true) || args[1]
5353
elsif File.exist?(args[0])
54-
YAML.load_file(args[0]) || args[1]
54+
# Read the file first rather than calling YAML.load_file as ruby2.7
55+
# doesn't support the aliases option on YAML.load_file
56+
contents = File.read(args[0])
57+
YAML.safe_load(contents, aliases: true) || args[1]
5558
else
5659
warning("Can't load '#{args[0]}' File does not exist!")
5760
args[1]

Diff for: spec/functions/loadyaml_spec.rb

+68-11
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,48 @@
1212
it "'default' => 'value'" do
1313
allow(File).to receive(:exist?).and_call_original
1414
expect(File).to receive(:exist?).with(filename).and_return(false).once
15-
expect(YAML).not_to receive(:load_file)
15+
expect(YAML).not_to receive(:safe_load)
1616
expect(subject).to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
1717
end
1818
end
1919

2020
context 'when an existing file is specified' do
21-
let(:filename) { '/tmp/doesexist' }
21+
let(:tempfile) { Tempfile.new }
22+
let(:filename) { tempfile.path }
2223
let(:data) { { 'key' => 'value', 'ķęŷ' => 'νậŀųề', 'キー' => '値' } }
24+
let(:yaml) do
25+
<<~YAML
26+
key: 'value'
27+
ķęŷ: 'νậŀųề'
28+
キー: '値'
29+
YAML
30+
end
2331

2432
it "returns 'key' => 'value', 'ķęŷ' => 'νậŀųề', 'キー' => '値'" do
33+
tempfile.write(yaml)
34+
tempfile.rewind
2535
allow(File).to receive(:exist?).and_call_original
2636
expect(File).to receive(:exist?).with(filename).and_return(true).once
27-
expect(YAML).to receive(:load_file).with(filename).and_return(data).once
37+
expect(YAML).to receive(:safe_load).and_call_original
2838
expect(subject).to run.with_params(filename).and_return(data)
2939
end
3040
end
3141

32-
context 'when the file could not be parsed' do
33-
let(:filename) { '/tmp/doesexist' }
42+
context 'when the file could not be parsed, with default specified' do
43+
let(:tempfile) { Tempfile.new }
44+
let(:filename) { tempfile.path }
45+
let(:yaml) do
46+
<<~YAML
47+
,,,,
48+
YAML
49+
end
3450

35-
it 'filename /tmp/doesexist' do
51+
it 'is expected to return the default value' do
52+
tempfile.write(yaml)
53+
tempfile.rewind
3654
allow(File).to receive(:exist?).and_call_original
3755
expect(File).to receive(:exist?).with(filename).and_return(true).once
38-
allow(YAML).to receive(:load_file).with(filename).once.and_raise(StandardError, 'Something terrible have happened!')
56+
allow(YAML).to receive(:safe_load).with(yaml, aliases: true).once.and_raise(StandardError, 'Something terrible have happened!')
3957
expect(subject).to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
4058
end
4159
end
@@ -48,7 +66,7 @@
4866

4967
it {
5068
expect(OpenURI).to receive(:open_uri).with(filename, basic_auth).and_return(yaml)
51-
expect(YAML).to receive(:safe_load).with(yaml).and_return(data).once
69+
expect(YAML).to receive(:safe_load).with(yaml, aliases: true).and_return(data).once
5270
expect(subject).to run.with_params(filename).and_return(data)
5371
}
5472
end
@@ -62,7 +80,7 @@
6280

6381
it {
6482
expect(OpenURI).to receive(:open_uri).with(url_no_auth, basic_auth).and_return(yaml)
65-
expect(YAML).to receive(:safe_load).with(yaml).and_return(data).once
83+
expect(YAML).to receive(:safe_load).with(yaml, aliases: true).and_return(data).once
6684
expect(subject).to run.with_params(filename).and_return(data)
6785
}
6886
end
@@ -76,7 +94,7 @@
7694

7795
it {
7896
expect(OpenURI).to receive(:open_uri).with(url_no_auth, basic_auth).and_return(yaml)
79-
expect(YAML).to receive(:safe_load).with(yaml).and_return(data).once
97+
expect(YAML).to receive(:safe_load).with(yaml, aliases: true).and_return(data).once
8098
expect(subject).to run.with_params(filename).and_return(data)
8199
}
82100
end
@@ -88,7 +106,7 @@
88106

89107
it {
90108
expect(OpenURI).to receive(:open_uri).with(filename, basic_auth).and_return(yaml)
91-
expect(YAML).to receive(:safe_load).with(yaml).and_raise StandardError, 'Cannot parse data'
109+
expect(YAML).to receive(:safe_load).with(yaml, aliases: true).and_raise StandardError, 'Cannot parse data'
92110
expect(subject).to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
93111
}
94112
end
@@ -103,4 +121,43 @@
103121
expect(subject).to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
104122
}
105123
end
124+
125+
context 'when the file contains aliases' do
126+
let(:tempfile) { Tempfile.new }
127+
let(:filename) { tempfile.path }
128+
let(:yaml) do
129+
<<~YAML
130+
some_numbers: &nums
131+
- one
132+
- two
133+
more_numbers: *nums
134+
YAML
135+
end
136+
let(:data) { { 'some_numbers' => ['one', 'two'], 'more_numbers' => ['one', 'two'] } }
137+
138+
it 'parses the aliases' do
139+
tempfile.write(yaml)
140+
tempfile.rewind
141+
expect(subject).to run.with_params(filename).and_return(data)
142+
end
143+
end
144+
145+
context 'when a URL returns yaml with aliases' do
146+
let(:filename) { 'https://example.local/myhash.yaml' }
147+
let(:basic_auth) { { http_basic_authentication: ['', ''] } }
148+
let(:yaml) do
149+
<<~YAML
150+
some_numbers: &nums
151+
- one
152+
- two
153+
more_numbers: *nums
154+
YAML
155+
end
156+
let(:data) { { 'some_numbers' => ['one', 'two'], 'more_numbers' => ['one', 'two'] } }
157+
158+
it {
159+
expect(OpenURI).to receive(:open_uri).with(filename, basic_auth).and_return(yaml)
160+
expect(subject).to run.with_params(filename).and_return(data)
161+
}
162+
end
106163
end

0 commit comments

Comments
 (0)