hiera-file 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,44 +1,80 @@
1
+ require 'hiera/config'
2
+
1
3
  class Hiera
2
4
  module Backend
3
5
  class File_backend
4
6
  def initialize
5
7
  Hiera.debug("Hiera File backend starting")
8
+
9
+ if Hiera::Config.include?(:file) and Hiera::Config[:file].has_key? :interpolate
10
+ @interpolate = Hiera::Config[:file][:interpolate]
11
+ else
12
+ @interpolate = true
13
+ end
6
14
  end
7
15
 
8
16
  def lookup(key, scope, order_override, resolution_type)
9
17
  answer = nil
10
18
 
11
- Hiera.debug("Looking up #{key} in JSON backend")
19
+ Hiera.debug("Looking up #{key} in File backend")
12
20
 
13
21
  Backend.datasources(scope, order_override) do |source|
14
22
  Hiera.debug("Hiera File_backend: looking for data source '#{source}'")
15
23
 
16
24
  datadir = Backend.datafile(:file, scope, source, "d") or next
17
25
 
18
- # Expand the datadir and path, and ensure that the datadir contains
19
- # the given key. If the expanded key is outside of the datadir then
20
- # this is a directory traversal attack and should be aborted.
21
- abs_datadir = File.expand_path(datadir)
22
- abs_path = File.expand_path(File.join(abs_datadir, key))
23
- unless abs_path.index(abs_datadir) == 0
24
- raise Exception, "Hiera File backend: key lookup outside of datadir '#{key}'"
25
- end
26
+ validate_key_lookup!(datadir, key)
27
+
28
+ path = File.join(datadir, key)
29
+ next unless File.exist?(path)
26
30
 
27
- next unless File.exist?(abs_path)
28
- data = File.read(abs_path)
31
+ data = File.read(path)
29
32
 
30
33
  case resolution_type
31
34
  when :array
32
35
  answer ||= []
33
- answer << Backend.parse_answer(data, scope)
36
+ answer << parse_answer(data, scope)
34
37
  else
35
- answer = Backend.parse_answer(data, scope)
38
+ answer = parse_answer(data, scope)
36
39
  break
37
40
  end
38
41
  end
39
42
 
40
43
  answer
41
44
  end
45
+
46
+ # Ensure that looked up files are within the datadir to prevent directory traversal
47
+ #
48
+ # @param datadir [String] The directory being used for the lookup
49
+ # @param key [String] The key being looked up
50
+ #
51
+ # @todo Raise a SecurityError instead of an Exception
52
+ # @raise [Exception] If the path to the data file is outside of the datadir
53
+ def validate_key_lookup!(datadir, key)
54
+
55
+ # Expand the datadir and path, and ensure that the datadir contains
56
+ # the given key. If the expanded key is outside of the datadir then
57
+ # this is a directory traversal attack and should be aborted.
58
+ abs_datadir = File.expand_path(datadir)
59
+ abs_path = File.expand_path(File.join(abs_datadir, key))
60
+ unless abs_path.index(abs_datadir) == 0
61
+ raise Exception, "Hiera File backend: key lookup outside of datadir '#{key}'"
62
+ end
63
+ end
64
+
65
+ # Parse the answer according to the chosen interpolation mode
66
+ #
67
+ # @param data [String] The value to parse
68
+ # @param scope [Hash] The variable scope to use for interpolation
69
+ #
70
+ # @return [String] The interpolated data
71
+ def parse_answer(data, scope)
72
+ if @interpolate
73
+ Backend.parse_answer(data, scope)
74
+ else
75
+ data
76
+ end
77
+ end
42
78
  end
43
79
  end
44
80
  end
@@ -7,8 +7,9 @@ class Hiera
7
7
  before do
8
8
  Hiera.stubs(:debug)
9
9
  Hiera.stubs(:warn)
10
- end
11
10
 
11
+ Hiera::Config.load(:backends => :file)
12
+ end
12
13
 
13
14
  describe "#initialize" do
14
15
  it "should announce its creation" do # because other specs checks this
@@ -23,8 +24,6 @@ class Hiera
23
24
  Backend.stubs(:datasources).multiple_yields(["one"], ["two"])
24
25
  end
25
26
 
26
- subject { File_backend.new }
27
-
28
27
  it "should look for data in all sources" do
29
28
  Backend.expects(:datafile).with(:file, {}, "one", "d")
30
29
  Backend.expects(:datafile).with(:file, {}, "two", "d")
@@ -59,16 +58,60 @@ class Hiera
59
58
  subject.lookup("key", {}, nil, :array).should == ['value one', 'value two']
60
59
  end
61
60
 
62
- it "should parse the answer for scope variables" do
63
- scope = {'scope_val' => 'v'}
61
+ describe "With interpolation" do
62
+ after do
63
+ Hiera::Config.load({:file => {}})
64
+ end
64
65
 
65
- Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
66
- Backend.expects(:datafile).with(:file, scope, "two", "d").never
66
+ describe "explicitly enabled" do
67
+ before do
68
+ Hiera::Config.load({:file => {:interpolate => true}})
69
+ end
67
70
 
68
- File.expects(:exist?).with("/datadir/one.d/key").returns true
69
- File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
71
+ it "should parse the answer for scope variables" do
72
+ scope = {'scope_val' => 'v'}
73
+
74
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
75
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
76
+
77
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
78
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
79
+
80
+ subject.lookup("key", scope, nil, :priority).should == 'value'
81
+ end
82
+ end
83
+
84
+ describe "set to default" do
85
+ it "should parse the answer for scope variables" do
86
+ scope = {'scope_val' => 'v'}
87
+
88
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
89
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
90
+
91
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
92
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
93
+
94
+ subject.lookup("key", scope, nil, :priority).should == 'value'
95
+ end
96
+ end
97
+
98
+ describe "explicitly disabled" do
99
+ before do
100
+ Hiera::Config.load({:file => {:interpolate => false}})
101
+ end
102
+
103
+ it "should not parse the answer for scope variables" do
104
+ scope = {'scope_val' => 'v'}
105
+
106
+ Backend.expects(:datafile).with(:file, scope, "one", "d").returns("/datadir/one.d")
107
+ Backend.expects(:datafile).with(:file, scope, "two", "d").never
108
+
109
+ File.expects(:exist?).with("/datadir/one.d/key").returns true
110
+ File.expects(:read).with("/datadir/one.d/key").returns '%{scope_val}alue'
70
111
 
71
- subject.lookup("key", scope, nil, :priority).should == 'value'
112
+ subject.lookup("key", scope, nil, :priority).should == '%{scope_val}alue'
113
+ end
114
+ end
72
115
  end
73
116
 
74
117
  it "should prevent directory traversal attacks" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiera-file
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-11 00:00:00.000000000 Z
12
+ date: 2013-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hiera