puppet 2.6.13 → 2.6.14
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +19 -0
- data/lib/puppet.rb +1 -1
- data/lib/puppet/daemon.rb +2 -2
- data/lib/puppet/network/server.rb +1 -1
- data/lib/puppet/provider/user/user_role_add.rb +32 -17
- data/lib/puppet/rails/benchmark.rb +1 -1
- data/lib/puppet/type/k5login.rb +3 -2
- data/lib/puppet/util.rb +77 -23
- data/lib/puppet/util/reference.rb +8 -7
- data/lib/puppet/util/suidmanager.rb +50 -35
- data/spec/unit/parser/ast/asthash_spec.rb +1 -2
- data/spec/unit/property/keyvalue_spec.rb +5 -2
- data/spec/unit/provider/user/user_role_add_spec.rb +48 -11
- data/spec/unit/type/k5login_spec.rb +115 -0
- data/spec/unit/util/suidmanager_spec.rb +82 -72
- data/spec/unit/util/zaml_spec.rb +10 -8
- data/spec/unit/util_spec.rb +104 -0
- metadata +6 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
2.6.14
|
2
|
+
===
|
3
|
+
d48ad59 Revert "(#5246) Puppetd does not remove it's pidfile when it exits"
|
4
|
+
ade5965 Remove unnecessary fallbacks in change_{user,group}
|
5
|
+
0a09a64 Document uid/gid-related methods in Puppet::Util
|
6
|
+
2599d56 Copy owner/group in replace_file
|
7
|
+
ead36ff (#12463) eliminate `secure_open` in favour of `replace_file`
|
8
|
+
1469538 (#12460) use `replace_file` for the .k5login file
|
9
|
+
8461203 (#12462) user_role_add: use `replace_file` for /etc/shadow
|
10
|
+
0ad532a (#12463) add secure `replace_file` to Puppet::Util
|
11
|
+
76d0749 (#12459) drop supplementary groups when permanently dropping UID
|
12
|
+
50909b9 (#12458) default to users primary group, not root, in `asuser`
|
13
|
+
d00c5cc (#12457) add users primary group, not Process.gid, in initgroups
|
14
|
+
d937ae3 (#6541) Use the same filebucket for backup and restore
|
15
|
+
a758066 (#11996) Fix test failures due to hash processing order changes.
|
16
|
+
e0e31d5 (#5246) Puppetd does not remove it's pidfile when it exits
|
17
|
+
0ab4597 (#11764) Fix failing cron test
|
18
|
+
073ca03 (#11764) Fix cron jobs for passing block to method
|
19
|
+
|
1
20
|
2.6.13
|
2
21
|
===
|
3
22
|
e4ee794 (#10739) Provide default subjectAltNames while bootstrapping master
|
data/lib/puppet.rb
CHANGED
data/lib/puppet/daemon.rb
CHANGED
@@ -33,9 +33,9 @@ class Puppet::Daemon
|
|
33
33
|
Puppet::Util::Log.reopen
|
34
34
|
rescue => detail
|
35
35
|
Puppet.err "Could not start #{Puppet[:name]}: #{detail}"
|
36
|
-
Puppet::Util::
|
36
|
+
Puppet::Util::replace_file("/tmp/daemonout", 0644) do |f|
|
37
37
|
f.puts "Could not start #{Puppet[:name]}: #{detail}"
|
38
|
-
|
38
|
+
end
|
39
39
|
exit(12)
|
40
40
|
end
|
41
41
|
end
|
@@ -22,7 +22,7 @@ class Puppet::Network::Server
|
|
22
22
|
$stderr.reopen $stdout
|
23
23
|
Puppet::Util::Log.reopen
|
24
24
|
rescue => detail
|
25
|
-
Puppet::Util.
|
25
|
+
Puppet::Util.replace_file("/tmp/daemonout", 0644) { |f|
|
26
26
|
f.puts "Could not start #{Puppet[:name]}: #{detail}"
|
27
27
|
}
|
28
28
|
raise "Could not start #{Puppet[:name]}: #{detail}"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'puppet/util'
|
1
2
|
require 'puppet/util/user_attr'
|
2
3
|
|
3
4
|
Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do
|
@@ -145,11 +146,22 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source =>
|
|
145
146
|
run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
|
146
147
|
end
|
147
148
|
|
149
|
+
|
150
|
+
# This helper makes it possible to test this on stub data without having to
|
151
|
+
# do too many crazy things!
|
152
|
+
def target_file_path
|
153
|
+
"/etc/shadow"
|
154
|
+
end
|
155
|
+
private :target_file_path
|
156
|
+
|
148
157
|
#Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it
|
149
158
|
#No abstraction, all esoteric knowledge of file formats, yay
|
150
159
|
def shadow_entry
|
151
160
|
return @shadow_entry if defined? @shadow_entry
|
152
|
-
@shadow_entry = File.readlines(
|
161
|
+
@shadow_entry = File.readlines(target_file_path).
|
162
|
+
reject { |r| r =~ /^[^\w]/ }.
|
163
|
+
collect { |l| l.chomp.split(':') }.
|
164
|
+
find { |user, _| user == @resource[:name] }
|
153
165
|
end
|
154
166
|
|
155
167
|
def password
|
@@ -164,28 +176,31 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source =>
|
|
164
176
|
shadow_entry ? shadow_entry[4] : :absent
|
165
177
|
end
|
166
178
|
|
167
|
-
#Read in /etc/shadow, find the line for our used and rewrite it with the
|
168
|
-
#Smooth like 80 grit
|
179
|
+
# Read in /etc/shadow, find the line for our used and rewrite it with the
|
180
|
+
# new pw. Smooth like 80 grit sandpaper.
|
181
|
+
#
|
182
|
+
# Now uses the `replace_file` mechanism to minimize the chance that we lose
|
183
|
+
# data, but it is still terrible. We still skip platform locking, so a
|
184
|
+
# concurrent `vipw -s` session will have no idea we risk data loss.
|
169
185
|
def password=(cryptopw)
|
170
186
|
begin
|
171
|
-
File.
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
187
|
+
shadow = File.read(target_file_path)
|
188
|
+
|
189
|
+
# Go Mifune loves the race here where we can lose data because
|
190
|
+
# /etc/shadow changed between reading it and writing it.
|
191
|
+
# --daniel 2012-02-05
|
192
|
+
Puppet::Util.replace_file(target_file_path, 0640) do |fh|
|
193
|
+
shadow.each_line do |line|
|
194
|
+
line_arr = line.split(':')
|
195
|
+
if line_arr[0] == @resource[:name]
|
196
|
+
line_arr[1] = cryptopw
|
197
|
+
line = line_arr.join(':')
|
180
198
|
end
|
199
|
+
fh.print line
|
181
200
|
end
|
182
201
|
end
|
183
|
-
File.rename("/etc/shadow_tmp", "/etc/shadow")
|
184
202
|
rescue => detail
|
185
|
-
fail "Could not write
|
186
|
-
ensure
|
187
|
-
# Make sure this *always* gets deleted
|
188
|
-
File.unlink("/etc/shadow_tmp") if File.exist?("/etc/shadow_tmp")
|
203
|
+
fail "Could not write replace #{target_file_path}: #{detail}"
|
189
204
|
end
|
190
205
|
end
|
191
206
|
end
|
data/lib/puppet/type/k5login.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# Plug-in type for handling k5login files
|
2
|
+
require 'puppet/util'
|
2
3
|
|
3
4
|
Puppet::Type.newtype(:k5login) do
|
4
5
|
@doc = "Manage the `.k5login` file for a user. Specify the full path to
|
@@ -79,8 +80,8 @@ Puppet::Type.newtype(:k5login) do
|
|
79
80
|
|
80
81
|
private
|
81
82
|
def write(value)
|
82
|
-
Puppet::Util.
|
83
|
-
f.puts value
|
83
|
+
Puppet::Util.replace_file(@resource[:name], 0644) do |f|
|
84
|
+
f.puts value
|
84
85
|
end
|
85
86
|
end
|
86
87
|
end
|
data/lib/puppet/util.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# A module to collect utility functions.
|
2
|
-
|
3
2
|
require 'puppet/util/monkey_patches'
|
4
|
-
require 'sync'
|
5
3
|
require 'puppet/external/lock'
|
6
|
-
require 'monitor'
|
7
4
|
require 'puppet/util/execution_stub'
|
5
|
+
require 'sync'
|
6
|
+
require 'monitor'
|
7
|
+
require 'tempfile'
|
8
|
+
require 'pathname'
|
8
9
|
|
9
10
|
module Puppet
|
10
11
|
# A command failed to execute.
|
@@ -261,7 +262,6 @@ module Util
|
|
261
262
|
output_file="/dev/null"
|
262
263
|
error_file="/dev/null"
|
263
264
|
if ! arguments[:squelch]
|
264
|
-
require "tempfile"
|
265
265
|
output_file = Tempfile.new("puppet")
|
266
266
|
error_file=output_file if arguments[:combine]
|
267
267
|
end
|
@@ -287,8 +287,7 @@ module Util
|
|
287
287
|
$stderr.reopen(error_file)
|
288
288
|
|
289
289
|
3.upto(256){|fd| IO::new(fd).close rescue nil}
|
290
|
-
Puppet::Util::SUIDManager.
|
291
|
-
Puppet::Util::SUIDManager.change_user(arguments[:uid], true) if arguments[:uid]
|
290
|
+
Puppet::Util::SUIDManager.change_privileges(arguments[:uid], arguments[:gid], true)
|
292
291
|
ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C'
|
293
292
|
if command.is_a?(Array)
|
294
293
|
Kernel.exec(*command)
|
@@ -409,27 +408,82 @@ module Util
|
|
409
408
|
|
410
409
|
module_function :memory, :thinmark
|
411
410
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
411
|
+
# Replace a file, securely. This takes a block, and passes it the file
|
412
|
+
# handle of a file open for writing. Write the replacement content inside
|
413
|
+
# the block and it will safely replace the target file.
|
414
|
+
#
|
415
|
+
# This method will make no changes to the target file until the content is
|
416
|
+
# successfully written and the block returns without raising an error.
|
417
|
+
#
|
418
|
+
# As far as possible the state of the existing file, such as mode, is
|
419
|
+
# preserved. This works hard to avoid loss of any metadata, but will result
|
420
|
+
# in an inode change for the file.
|
421
|
+
#
|
422
|
+
# Arguments: `filename`, `default_mode`
|
423
|
+
#
|
424
|
+
# The filename is the file we are going to replace.
|
425
|
+
#
|
426
|
+
# The default_mode is the mode to use when the target file doesn't already
|
427
|
+
# exist; if the file is present we copy the existing mode/owner/group values
|
428
|
+
# across.
|
429
|
+
def replace_file(file, default_mode, &block)
|
430
|
+
raise Puppet::DevError, "replace_file requires a block" unless block_given?
|
431
|
+
|
432
|
+
file = Pathname(file)
|
433
|
+
tempfile = Tempfile.new(file.basename.to_s, file.dirname.to_s)
|
434
|
+
|
435
|
+
file_exists = file.exist?
|
436
|
+
|
437
|
+
# If the file exists, use its current mode/owner/group. If it doesn't, use
|
438
|
+
# the supplied mode, and default to current user/group.
|
439
|
+
if file_exists
|
440
|
+
stat = file.lstat
|
441
|
+
|
442
|
+
# We only care about the four lowest-order octets. Higher octets are
|
443
|
+
# filesystem-specific.
|
444
|
+
mode = stat.mode & 07777
|
445
|
+
uid = stat.uid
|
446
|
+
gid = stat.gid
|
447
|
+
else
|
448
|
+
mode = default_mode
|
449
|
+
uid = Process.euid
|
450
|
+
gid = Process.egid
|
420
451
|
end
|
452
|
+
|
453
|
+
# Set properties of the temporary file before we write the content, because
|
454
|
+
# Tempfile doesn't promise to be safe from reading by other people, just
|
455
|
+
# that it avoids races around creating the file.
|
456
|
+
tempfile.chmod(mode)
|
457
|
+
tempfile.chown(uid, gid)
|
458
|
+
|
459
|
+
# OK, now allow the caller to write the content of the file.
|
460
|
+
yield tempfile
|
461
|
+
|
462
|
+
# Now, make sure the data (which includes the mode) is safe on disk.
|
463
|
+
tempfile.flush
|
421
464
|
begin
|
422
|
-
|
423
|
-
rescue
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
465
|
+
tempfile.fsync
|
466
|
+
rescue NotImplementedError
|
467
|
+
# fsync may not be implemented by Ruby on all platforms, but
|
468
|
+
# there is absolutely no recovery path if we detect that. So, we just
|
469
|
+
# ignore the return code.
|
470
|
+
#
|
471
|
+
# However, don't be fooled: that is accepting that we are running in
|
472
|
+
# an unsafe fashion. If you are porting to a new platform don't stub
|
473
|
+
# that out.
|
430
474
|
end
|
475
|
+
|
476
|
+
tempfile.close
|
477
|
+
|
478
|
+
File.rename(tempfile.path, file)
|
479
|
+
|
480
|
+
# Ideally, we would now fsync the directory as well, but Ruby doesn't
|
481
|
+
# have support for that, and it doesn't matter /that/ much...
|
482
|
+
|
483
|
+
# Return something true, and possibly useful.
|
484
|
+
file
|
431
485
|
end
|
432
|
-
module_function :
|
486
|
+
module_function :replace_file
|
433
487
|
end
|
434
488
|
end
|
435
489
|
|
@@ -36,14 +36,15 @@ class Puppet::Util::Reference
|
|
36
36
|
|
37
37
|
def self.pdf(text)
|
38
38
|
puts "creating pdf"
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
rst2latex = which('rst2latex') || which('rst2latex.py') || raise("Could not find rst2latex")
|
39
|
+
rst2latex = which('rst2latex') || which('rst2latex.py') ||
|
40
|
+
raise("Could not find rst2latex")
|
41
|
+
|
43
42
|
cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
|
44
|
-
Puppet::Util.
|
45
|
-
|
46
|
-
|
43
|
+
Puppet::Util.replace_file("/tmp/puppetdoc.txt") {|f| f.puts text }
|
44
|
+
# There used to be an attempt to use secure_open / replace_file to secure
|
45
|
+
# the target, too, but that did nothing: the race was still here. We can
|
46
|
+
# get exactly the same benefit from running this effort:
|
47
|
+
File.unlink('/tmp/puppetdoc.tex') rescue nil
|
47
48
|
output = %x{#{cmd}}
|
48
49
|
unless $CHILD_STATUS == 0
|
49
50
|
$stderr.puts "rst2latex failed"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'puppet/util/warnings'
|
2
2
|
require 'forwardable'
|
3
|
+
require 'etc'
|
3
4
|
|
4
5
|
module Puppet::Util::SUIDManager
|
5
6
|
include Puppet::Util::Warnings
|
@@ -40,55 +41,76 @@ module Puppet::Util::SUIDManager
|
|
40
41
|
Process.uid == 0
|
41
42
|
end
|
42
43
|
|
43
|
-
#
|
44
|
+
# Methods to handle changing uid/gid of the running process. In general,
|
45
|
+
# these will noop or fail on Windows, and require root to change to anything
|
46
|
+
# but the current uid/gid (which is a noop).
|
47
|
+
|
48
|
+
# Runs block setting euid and egid if provided then restoring original ids.
|
49
|
+
# If running on Windows or without root, the block will be run with the
|
50
|
+
# current euid/egid.
|
44
51
|
def asuser(new_uid=nil, new_gid=nil)
|
45
|
-
return yield if Puppet.features.microsoft_windows?
|
52
|
+
return yield if Puppet.features.microsoft_windows?
|
53
|
+
return yield unless root?
|
54
|
+
return yield unless new_uid or new_gid
|
46
55
|
|
47
56
|
old_euid, old_egid = self.euid, self.egid
|
48
57
|
begin
|
49
|
-
|
50
|
-
change_user(new_uid) if new_uid
|
58
|
+
change_privileges(new_uid, new_gid, false)
|
51
59
|
|
52
60
|
yield
|
53
61
|
ensure
|
54
|
-
|
55
|
-
change_user(old_euid)
|
62
|
+
change_privileges(new_uid ? old_euid : nil, old_egid, false)
|
56
63
|
end
|
57
64
|
end
|
58
65
|
module_function :asuser
|
59
66
|
|
67
|
+
# If `permanently` is set, will permanently change the uid/gid of the
|
68
|
+
# process. If not, it will only set the euid/egid. If only uid is supplied,
|
69
|
+
# the primary group of the supplied gid will be used. If only gid is
|
70
|
+
# supplied, only gid will be changed. This method will fail if used on
|
71
|
+
# Windows.
|
72
|
+
def change_privileges(uid=nil, gid=nil, permanently=false)
|
73
|
+
return unless uid or gid
|
74
|
+
|
75
|
+
unless gid
|
76
|
+
uid = convert_xid(:uid, uid)
|
77
|
+
gid = Etc.getpwuid(uid).gid
|
78
|
+
end
|
79
|
+
|
80
|
+
change_group(gid, permanently)
|
81
|
+
change_user(uid, permanently) if uid
|
82
|
+
end
|
83
|
+
module_function :change_privileges
|
84
|
+
|
85
|
+
# Changes the egid of the process if `permanently` is not set, otherwise
|
86
|
+
# changes gid. This method will fail if used on Windows, or attempting to
|
87
|
+
# change to a different gid without root.
|
60
88
|
def change_group(group, permanently=false)
|
61
89
|
gid = convert_xid(:gid, group)
|
62
90
|
raise Puppet::Error, "No such group #{group}" unless gid
|
63
91
|
|
64
92
|
if permanently
|
65
|
-
|
66
|
-
Process::GID.change_privilege(gid)
|
67
|
-
rescue NotImplementedError
|
68
|
-
Process.egid = gid
|
69
|
-
Process.gid = gid
|
70
|
-
end
|
93
|
+
Process::GID.change_privilege(gid)
|
71
94
|
else
|
72
95
|
Process.egid = gid
|
73
96
|
end
|
74
97
|
end
|
75
98
|
module_function :change_group
|
76
99
|
|
100
|
+
# As change_group, but operates on uids. If changing user permanently,
|
101
|
+
# supplementary groups will be set the to default groups for the new uid.
|
77
102
|
def change_user(user, permanently=false)
|
78
103
|
uid = convert_xid(:uid, user)
|
79
104
|
raise Puppet::Error, "No such user #{user}" unless uid
|
80
105
|
|
81
106
|
if permanently
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
initgroups(uid)
|
87
|
-
Process.euid = uid
|
88
|
-
Process.uid = uid
|
89
|
-
end
|
107
|
+
# If changing uid, we must be root. So initgroups first here.
|
108
|
+
initgroups(uid)
|
109
|
+
|
110
|
+
Process::UID.change_privilege(uid)
|
90
111
|
else
|
91
|
-
#
|
112
|
+
# We must be root to initgroups, so initgroups before dropping euid if
|
113
|
+
# we're root, otherwise elevate euid before initgroups.
|
92
114
|
# change euid (to root) first.
|
93
115
|
if Process.euid == 0
|
94
116
|
initgroups(uid)
|
@@ -113,10 +135,13 @@ module Puppet::Util::SUIDManager
|
|
113
135
|
end
|
114
136
|
module_function :convert_xid
|
115
137
|
|
116
|
-
# Initialize
|
117
|
-
|
118
|
-
|
119
|
-
|
138
|
+
# Initialize primary and supplemental groups to those of the target user. We
|
139
|
+
# take the UID and manually look up their details in the system database,
|
140
|
+
# including username and primary group. This method will fail on Windows, or
|
141
|
+
# if used without root to initgroups of another user.
|
142
|
+
def initgroups(uid)
|
143
|
+
pwent = Etc.getpwuid(uid)
|
144
|
+
Process.initgroups(pwent.name, pwent.gid)
|
120
145
|
end
|
121
146
|
|
122
147
|
module_function :initgroups
|
@@ -126,15 +151,5 @@ module Puppet::Util::SUIDManager
|
|
126
151
|
[output, $CHILD_STATUS.dup]
|
127
152
|
end
|
128
153
|
module_function :run_and_capture
|
129
|
-
|
130
|
-
def system(command, new_uid=nil, new_gid=nil)
|
131
|
-
status = nil
|
132
|
-
asuser(new_uid, new_gid) do
|
133
|
-
Kernel.system(command)
|
134
|
-
status = $CHILD_STATUS.dup
|
135
|
-
end
|
136
|
-
status
|
137
|
-
end
|
138
|
-
module_function :system
|
139
154
|
end
|
140
155
|
|
@@ -92,7 +92,6 @@ describe Puppet::Parser::AST::ASTHash do
|
|
92
92
|
|
93
93
|
it "should return a valid string with to_s" do
|
94
94
|
hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b", "c" => "d" })
|
95
|
-
|
96
|
-
hash.to_s.should == '{a => b, c => d}'
|
95
|
+
["{a => b, c => d}", "{c => d, a => b}"].should be_include hash.to_s
|
97
96
|
end
|
98
97
|
end
|
@@ -36,8 +36,11 @@ describe klass do
|
|
36
36
|
@property.should_to_s({:foo => "baz", :bar => "boo"}) == "foo=baz;bar=boo"
|
37
37
|
end
|
38
38
|
|
39
|
-
it "should return the passed in
|
40
|
-
@property.is_to_s({"foo" => "baz" , "bar" => "boo"})
|
39
|
+
it "should return the passed in hash values joined with the delimiter from is_to_s" do
|
40
|
+
s = @property.is_to_s({"foo" => "baz" , "bar" => "boo"})
|
41
|
+
|
42
|
+
# We can't predict the order the hash is processed in...
|
43
|
+
["foo=baz;bar=boo", "bar=boo;foo=baz"].should be_include s
|
41
44
|
end
|
42
45
|
|
43
46
|
describe "when calling inclusive?" do
|
@@ -1,10 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/../../../spec_helper'
|
4
|
+
require 'tempfile'
|
4
5
|
|
5
6
|
provider_class = Puppet::Type.type(:user).provider(:user_role_add)
|
6
7
|
|
7
8
|
describe provider_class do
|
9
|
+
include PuppetSpec::Files
|
10
|
+
|
8
11
|
before do
|
9
12
|
@resource = stub("resource", :name => "myuser", :managehome? => nil)
|
10
13
|
@resource.stubs(:should).returns "fakeval"
|
@@ -244,17 +247,51 @@ describe provider_class do
|
|
244
247
|
end
|
245
248
|
|
246
249
|
describe "when setting the password" do
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
250
|
+
let(:path) { tmpfile('etc-shadow') }
|
251
|
+
|
252
|
+
before :each do
|
253
|
+
@provider.stubs(:target_file_path).returns(path)
|
254
|
+
end
|
255
|
+
|
256
|
+
def write_fixture(content)
|
257
|
+
File.open(path, 'w') { |f| f.print(content) }
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should update the target user" do
|
261
|
+
write_fixture <<FIXTURE
|
262
|
+
fakeval:seriously:15315:0:99999:7:::
|
263
|
+
FIXTURE
|
264
|
+
@provider.password = "totally"
|
265
|
+
File.read(path).should =~ /^fakeval:totally:/
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should only update the target user" do
|
269
|
+
write_fixture <<FIXTURE
|
270
|
+
before:seriously:15315:0:99999:7:::
|
271
|
+
fakeval:seriously:15315:0:99999:7:::
|
272
|
+
fakevalish:seriously:15315:0:99999:7:::
|
273
|
+
after:seriously:15315:0:99999:7:::
|
274
|
+
FIXTURE
|
275
|
+
@provider.password = "totally"
|
276
|
+
File.read(path).should == <<EOT
|
277
|
+
before:seriously:15315:0:99999:7:::
|
278
|
+
fakeval:totally:15315:0:99999:7:::
|
279
|
+
fakevalish:seriously:15315:0:99999:7:::
|
280
|
+
after:seriously:15315:0:99999:7:::
|
281
|
+
EOT
|
282
|
+
end
|
283
|
+
|
284
|
+
# This preserves the current semantics, but is it right? --daniel 2012-02-05
|
285
|
+
it "should do nothing if the target user is missing" do
|
286
|
+
fixture = <<FIXTURE
|
287
|
+
before:seriously:15315:0:99999:7:::
|
288
|
+
fakevalish:seriously:15315:0:99999:7:::
|
289
|
+
after:seriously:15315:0:99999:7:::
|
290
|
+
FIXTURE
|
291
|
+
|
292
|
+
write_fixture fixture
|
293
|
+
@provider.password = "totally"
|
294
|
+
File.read(path).should == fixture
|
258
295
|
end
|
259
296
|
end
|
260
297
|
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'puppet/type'
|
5
|
+
|
6
|
+
describe Puppet::Type.type(:k5login) do
|
7
|
+
include PuppetSpec::Files
|
8
|
+
|
9
|
+
context "the type class" do
|
10
|
+
subject { described_class }
|
11
|
+
it { should be_validattr :ensure }
|
12
|
+
it { should be_validattr :path }
|
13
|
+
it { should be_validattr :principals }
|
14
|
+
it { should be_validattr :mode }
|
15
|
+
# We have one, inline provider implemented.
|
16
|
+
it { should be_validattr :provider }
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:path) { tmpfile('k5login') }
|
20
|
+
|
21
|
+
def resource(attrs = {})
|
22
|
+
attrs = {
|
23
|
+
:ensure => 'present',
|
24
|
+
:path => path,
|
25
|
+
:principals => 'fred@EXAMPLE.COM'
|
26
|
+
}.merge(attrs)
|
27
|
+
|
28
|
+
if content = attrs.delete(:content)
|
29
|
+
File.open(path, 'w') { |f| f.print(content) }
|
30
|
+
end
|
31
|
+
|
32
|
+
resource = described_class.new(attrs)
|
33
|
+
resource
|
34
|
+
end
|
35
|
+
|
36
|
+
before :each do
|
37
|
+
FileUtils.touch(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
context "the provider" do
|
41
|
+
context "when the file is missing" do
|
42
|
+
it "should initially be absent" do
|
43
|
+
File.delete(path)
|
44
|
+
resource.retrieve[:ensure].must == :absent
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should create the file when synced" do
|
48
|
+
resource(:ensure => 'present').parameter(:ensure).sync
|
49
|
+
File.should be_exist path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the file is present" do
|
54
|
+
context "retrieved initial state" do
|
55
|
+
subject { resource.retrieve }
|
56
|
+
|
57
|
+
it "should retrieve its properties correctly with zero principals" do
|
58
|
+
subject[:ensure].should == :present
|
59
|
+
subject[:principals].should == []
|
60
|
+
# We don't really care what the mode is, just that it got it
|
61
|
+
subject[:mode].should_not be_nil
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with one principal" do
|
65
|
+
subject { resource(:content => "daniel@EXAMPLE.COM\n").retrieve }
|
66
|
+
|
67
|
+
it "should retrieve its principals correctly" do
|
68
|
+
subject[:principals].should == ["daniel@EXAMPLE.COM"]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with two principals" do
|
73
|
+
subject do
|
74
|
+
content = ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"].join("\n")
|
75
|
+
resource(:content => content).retrieve
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should retrieve its principals correctly" do
|
79
|
+
subject[:principals].should == ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should remove the file ensure is absent" do
|
85
|
+
resource(:ensure => 'absent').property(:ensure).sync
|
86
|
+
File.should_not be_exist path
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should write one principal to the file" do
|
90
|
+
File.read(path).should == ""
|
91
|
+
resource(:principals => ["daniel@EXAMPLE.COM"]).property(:principals).sync
|
92
|
+
File.read(path).should == "daniel@EXAMPLE.COM\n"
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should write multiple principals to the file" do
|
96
|
+
content = ["daniel@EXAMPLE.COM", "george@EXAMPLE.COM"]
|
97
|
+
|
98
|
+
File.read(path).should == ""
|
99
|
+
resource(:principals => content).property(:principals).sync
|
100
|
+
File.read(path).should == content.join("\n") + "\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "when setting the mode", :unless => Puppet.features.microsoft_windows? do
|
104
|
+
# The defined input type is "mode, as an octal string"
|
105
|
+
["400", "600", "700", "644", "664"].each do |mode|
|
106
|
+
it "should update the mode to #{mode}" do
|
107
|
+
resource(:mode => mode).property(:mode).sync
|
108
|
+
|
109
|
+
(File.stat(path).mode & 07777).to_s(8).should == mode
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -13,10 +13,18 @@ describe Puppet::Util::SUIDManager do
|
|
13
13
|
|
14
14
|
before :each do
|
15
15
|
Puppet::Util::SUIDManager.stubs(:convert_xid).returns(42)
|
16
|
-
|
16
|
+
pwent = stub('pwent', :name => 'fred', :uid => 42, :gid => 42)
|
17
|
+
Etc.stubs(:getpwuid).with(42).returns(pwent)
|
17
18
|
|
18
19
|
[:euid, :egid, :uid, :gid, :groups].each do |id|
|
19
|
-
Process.stubs("#{id}=").with {|value| xids[id] = value}
|
20
|
+
Process.stubs("#{id}=").with {|value| xids[id] = value }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#initgroups" do
|
25
|
+
it "should use the primary group of the user as the 'basegid'" do
|
26
|
+
Process.expects(:initgroups).with('fred', 42)
|
27
|
+
described_class.initgroups(42)
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
@@ -31,45 +39,93 @@ describe Puppet::Util::SUIDManager do
|
|
31
39
|
end
|
32
40
|
|
33
41
|
describe "#asuser" do
|
34
|
-
it "should set euid/egid when root" do
|
35
|
-
Process.stubs(:uid).returns(
|
42
|
+
it "should not get or set euid/egid when not root" do
|
43
|
+
Process.stubs(:uid).returns(1)
|
36
44
|
|
37
45
|
Process.stubs(:egid).returns(51)
|
38
46
|
Process.stubs(:euid).returns(50)
|
39
47
|
|
40
|
-
Puppet::Util::SUIDManager.
|
41
|
-
|
48
|
+
Puppet::Util::SUIDManager.asuser(user[:uid], user[:gid]) {}
|
49
|
+
|
50
|
+
xids.should be_empty
|
51
|
+
end
|
42
52
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
yielded = true
|
53
|
+
context "when root and not windows" do
|
54
|
+
before :each do
|
55
|
+
Process.stubs(:uid).returns(0)
|
56
|
+
Puppet.features.stubs(:microsoft_windows?).returns(false)
|
48
57
|
end
|
49
58
|
|
50
|
-
|
51
|
-
|
59
|
+
it "should set euid/egid when root" do
|
60
|
+
Process.stubs(:uid).returns(0)
|
52
61
|
|
53
|
-
|
54
|
-
|
55
|
-
yielded.should be_true
|
56
|
-
end
|
62
|
+
Process.stubs(:egid).returns(51)
|
63
|
+
Process.stubs(:euid).returns(50)
|
57
64
|
|
58
|
-
|
59
|
-
|
65
|
+
Puppet::Util::SUIDManager.stubs(:convert_xid).with(:gid, 51).returns(51)
|
66
|
+
Puppet::Util::SUIDManager.stubs(:convert_xid).with(:uid, 50).returns(50)
|
67
|
+
Puppet::Util::SUIDManager.stubs(:initgroups).returns([])
|
60
68
|
|
61
|
-
|
62
|
-
|
69
|
+
yielded = false
|
70
|
+
Puppet::Util::SUIDManager.asuser(user[:uid], user[:gid]) do
|
71
|
+
xids[:egid].should == user[:gid]
|
72
|
+
xids[:euid].should == user[:uid]
|
73
|
+
yielded = true
|
74
|
+
end
|
63
75
|
|
64
|
-
|
76
|
+
xids[:egid].should == 51
|
77
|
+
xids[:euid].should == 50
|
65
78
|
|
66
|
-
|
79
|
+
# It's possible asuser could simply not yield, so the assertions in the
|
80
|
+
# block wouldn't fail. So verify those actually got checked.
|
81
|
+
yielded.should be_true
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should just yield if user and group are nil" do
|
85
|
+
yielded = false
|
86
|
+
Puppet::Util::SUIDManager.asuser(nil, nil) { yielded = true }
|
87
|
+
yielded.should be_true
|
88
|
+
xids.should == {}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should just change group if only group is given" do
|
92
|
+
yielded = false
|
93
|
+
Puppet::Util::SUIDManager.asuser(nil, 42) { yielded = true }
|
94
|
+
yielded.should be_true
|
95
|
+
xids.should == { :egid => 42 }
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should change gid to the primary group of uid by default" do
|
99
|
+
Process.stubs(:initgroups)
|
100
|
+
|
101
|
+
yielded = false
|
102
|
+
Puppet::Util::SUIDManager.asuser(42) { yielded = true }
|
103
|
+
yielded.should be_true
|
104
|
+
xids.should == { :euid => 42, :egid => 42 }
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should change both uid and gid if given" do
|
108
|
+
# I don't like the sequence, but it is the only way to assert on the
|
109
|
+
# internal behaviour in a reliable fashion, given we need multiple
|
110
|
+
# sequenced calls to the same methods. --daniel 2012-02-05
|
111
|
+
horror = sequence('of user and group changes')
|
112
|
+
Puppet::Util::SUIDManager.expects(:change_group).with(43, false).in_sequence(horror)
|
113
|
+
Puppet::Util::SUIDManager.expects(:change_user).with(42, false).in_sequence(horror)
|
114
|
+
Puppet::Util::SUIDManager.expects(:change_group).
|
115
|
+
with(Puppet::Util::SUIDManager.egid, false).in_sequence(horror)
|
116
|
+
Puppet::Util::SUIDManager.expects(:change_user).
|
117
|
+
with(Puppet::Util::SUIDManager.euid, false).in_sequence(horror)
|
118
|
+
|
119
|
+
yielded = false
|
120
|
+
Puppet::Util::SUIDManager.asuser(42, 43) { yielded = true }
|
121
|
+
yielded.should be_true
|
122
|
+
end
|
67
123
|
end
|
68
124
|
end
|
69
125
|
|
70
126
|
describe "#change_group" do
|
71
127
|
describe "when changing permanently" do
|
72
|
-
it "should
|
128
|
+
it "should change_privilege" do
|
73
129
|
Process::GID.expects(:change_privilege).with do |gid|
|
74
130
|
Process.gid = gid
|
75
131
|
Process.egid = gid
|
@@ -80,15 +136,6 @@ describe Puppet::Util::SUIDManager do
|
|
80
136
|
xids[:egid].should == 42
|
81
137
|
xids[:gid].should == 42
|
82
138
|
end
|
83
|
-
|
84
|
-
it "should change both egid and gid if change_privilege isn't supported" do
|
85
|
-
Process::GID.stubs(:change_privilege).raises(NotImplementedError)
|
86
|
-
|
87
|
-
Puppet::Util::SUIDManager.change_group(42, true)
|
88
|
-
|
89
|
-
xids[:egid].should == 42
|
90
|
-
xids[:gid].should == 42
|
91
|
-
end
|
92
139
|
end
|
93
140
|
|
94
141
|
describe "when changing temporarily" do
|
@@ -103,21 +150,12 @@ describe Puppet::Util::SUIDManager do
|
|
103
150
|
|
104
151
|
describe "#change_user" do
|
105
152
|
describe "when changing permanently" do
|
106
|
-
it "should
|
153
|
+
it "should change_privilege" do
|
107
154
|
Process::UID.expects(:change_privilege).with do |uid|
|
108
155
|
Process.uid = uid
|
109
156
|
Process.euid = uid
|
110
157
|
end
|
111
158
|
|
112
|
-
Puppet::Util::SUIDManager.change_user(42, true)
|
113
|
-
|
114
|
-
xids[:euid].should == 42
|
115
|
-
xids[:uid].should == 42
|
116
|
-
end
|
117
|
-
|
118
|
-
it "should change euid and uid and groups if change_privilege isn't supported" do
|
119
|
-
Process::UID.stubs(:change_privilege).raises(NotImplementedError)
|
120
|
-
|
121
159
|
Puppet::Util::SUIDManager.expects(:initgroups).with(42)
|
122
160
|
|
123
161
|
Puppet::Util::SUIDManager.change_user(42, true)
|
@@ -129,6 +167,7 @@ describe Puppet::Util::SUIDManager do
|
|
129
167
|
|
130
168
|
describe "when changing temporarily" do
|
131
169
|
it "should change only euid and groups" do
|
170
|
+
Puppet::Util::SUIDManager.stubs(:initgroups).returns([])
|
132
171
|
Puppet::Util::SUIDManager.change_user(42, false)
|
133
172
|
|
134
173
|
xids[:euid].should == 42
|
@@ -165,35 +204,6 @@ describe Puppet::Util::SUIDManager do
|
|
165
204
|
Kernel.system '' if $CHILD_STATUS.nil?
|
166
205
|
end
|
167
206
|
|
168
|
-
describe "with #system" do
|
169
|
-
it "should set euid/egid when root" do
|
170
|
-
Process.stubs(:uid).returns(0)
|
171
|
-
Process.stubs(:egid).returns(51)
|
172
|
-
Process.stubs(:euid).returns(50)
|
173
|
-
|
174
|
-
Puppet::Util::SUIDManager.stubs(:convert_xid).with(:gid, 51).returns(51)
|
175
|
-
Puppet::Util::SUIDManager.stubs(:convert_xid).with(:uid, 50).returns(50)
|
176
|
-
|
177
|
-
Puppet::Util::SUIDManager.expects(:change_group).with(user[:uid])
|
178
|
-
Puppet::Util::SUIDManager.expects(:change_user).with(user[:uid])
|
179
|
-
|
180
|
-
Puppet::Util::SUIDManager.expects(:change_group).with(51)
|
181
|
-
Puppet::Util::SUIDManager.expects(:change_user).with(50)
|
182
|
-
|
183
|
-
Kernel.expects(:system).with('blah')
|
184
|
-
Puppet::Util::SUIDManager.system('blah', user[:uid], user[:gid])
|
185
|
-
end
|
186
|
-
|
187
|
-
it "should not get or set euid/egid when not root" do
|
188
|
-
Process.stubs(:uid).returns(1)
|
189
|
-
Kernel.expects(:system).with('blah')
|
190
|
-
|
191
|
-
Puppet::Util::SUIDManager.system('blah', user[:uid], user[:gid])
|
192
|
-
|
193
|
-
xids.should be_empty
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
207
|
describe "with #run_and_capture" do
|
198
208
|
it "should capture the output and return process status" do
|
199
209
|
Puppet::Util.
|
data/spec/unit/util/zaml_spec.rb
CHANGED
@@ -36,29 +36,31 @@ describe "Pure ruby yaml implementation" do
|
|
36
36
|
end
|
37
37
|
}
|
38
38
|
|
39
|
-
def set_of_lines(l)
|
40
|
-
l.split("\n").sort
|
41
|
-
end
|
42
|
-
|
43
39
|
it "should handle references to Array in Hash values correctly" do
|
44
40
|
list = [1]
|
45
41
|
data = { "one" => list, "two" => list }
|
46
|
-
data.to_yaml.should
|
42
|
+
data.to_yaml.should =~ / two: [&*]id001/
|
43
|
+
data.to_yaml.should =~ / one: [&*]id001/
|
47
44
|
expect { YAML.load(data.to_yaml).should == data }.should_not raise_error
|
48
45
|
end
|
49
46
|
|
50
47
|
it "should handle references to Hash in Hash values correctly" do
|
51
48
|
hash = { 1 => 1 }
|
52
49
|
data = { "one" => hash, "two" => hash }
|
53
|
-
|
54
|
-
|
50
|
+
lines = data.to_yaml.split("\n")
|
51
|
+
lines.should be_any {|x| x =~ /--- / }
|
52
|
+
lines.should be_any {|x| x =~ / one: [*&]id001/ }
|
53
|
+
lines.should be_any {|x| x =~ / two: [*&]id001/ }
|
55
54
|
expect { YAML.load(data.to_yaml).should == data }.should_not raise_error
|
56
55
|
end
|
57
56
|
|
58
57
|
it "should handle references to Scalar in Hash" do
|
59
58
|
str = "hello"
|
60
59
|
data = { "one" => str, "two" => str }
|
61
|
-
|
60
|
+
lines = data.to_yaml.split("\n")
|
61
|
+
lines.should be_any {|x| x =~ /--- / }
|
62
|
+
lines.should be_any {|x| x =~ / one: hello/ }
|
63
|
+
lines.should be_any {|x| x =~ / two: hello/ }
|
62
64
|
expect { YAML.load(data.to_yaml).should == data }.should_not raise_error
|
63
65
|
end
|
64
66
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Puppet::Util do
|
5
|
+
subject { Puppet::Util }
|
6
|
+
include PuppetSpec::Files
|
7
|
+
|
8
|
+
context "#replace_file" do
|
9
|
+
it { should respond_to :replace_file }
|
10
|
+
|
11
|
+
let :target do
|
12
|
+
target = Tempfile.new("puppet-util-replace-file")
|
13
|
+
target.puts("hello, world")
|
14
|
+
target.flush # make sure content is on disk.
|
15
|
+
target.fsync rescue nil
|
16
|
+
target.close
|
17
|
+
target
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should fail if no block is given" do
|
21
|
+
expect { subject.replace_file(target.path, 0600) }.to raise_error /block/
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should replace a file when invoked" do
|
25
|
+
# Check that our file has the expected content.
|
26
|
+
File.read(target.path).should == "hello, world\n"
|
27
|
+
|
28
|
+
# Replace the file.
|
29
|
+
subject.replace_file(target.path, 0600) do |fh|
|
30
|
+
fh.puts "I am the passenger..."
|
31
|
+
end
|
32
|
+
|
33
|
+
# ...and check the replacement was complete.
|
34
|
+
File.read(target.path).should == "I am the passenger...\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
[0555, 0600, 0660, 0700, 0770].each do |mode|
|
38
|
+
it "should copy 0#{mode.to_s(8)} permissions from the target file by default" do
|
39
|
+
File.chmod(mode, target.path)
|
40
|
+
|
41
|
+
(File.stat(target.path).mode & 07777).should == mode
|
42
|
+
|
43
|
+
subject.replace_file(target.path, 0000) {|fh| fh.puts "bazam" }
|
44
|
+
|
45
|
+
(File.stat(target.path).mode & 07777).should == mode
|
46
|
+
File.read(target.path).should == "bazam\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should copy the permissions of the source file before yielding" do
|
51
|
+
File.chmod(0555, target.path)
|
52
|
+
inode = File.stat(target.path).ino
|
53
|
+
|
54
|
+
yielded = false
|
55
|
+
subject.replace_file(target.path, 0600) do |fh|
|
56
|
+
(File.stat(fh.path).mode & 07777).should == 0555
|
57
|
+
yielded = true
|
58
|
+
end
|
59
|
+
yielded.should be_true
|
60
|
+
|
61
|
+
# We can't check inode on Windows
|
62
|
+
File.stat(target.path).ino.should_not == inode
|
63
|
+
|
64
|
+
(File.stat(target.path).mode & 07777).should == 0555
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should use the default permissions if the source file doesn't exist" do
|
68
|
+
new_target = target.path + '.foo'
|
69
|
+
File.should_not be_exist(new_target)
|
70
|
+
|
71
|
+
begin
|
72
|
+
subject.replace_file(new_target, 0555) {|fh| fh.puts "foo" }
|
73
|
+
(File.stat(new_target).mode & 07777).should == 0555
|
74
|
+
ensure
|
75
|
+
File.unlink(new_target) if File.exists?(new_target)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should not replace the file if an exception is thrown in the block" do
|
80
|
+
yielded = false
|
81
|
+
threw = false
|
82
|
+
|
83
|
+
begin
|
84
|
+
subject.replace_file(target.path, 0600) do |fh|
|
85
|
+
yielded = true
|
86
|
+
fh.puts "different content written, then..."
|
87
|
+
raise "...throw some random failure"
|
88
|
+
end
|
89
|
+
rescue Exception => e
|
90
|
+
if e.to_s =~ /some random failure/
|
91
|
+
threw = true
|
92
|
+
else
|
93
|
+
raise
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
yielded.should be_true
|
98
|
+
threw.should be_true
|
99
|
+
|
100
|
+
# ...and check the replacement was complete.
|
101
|
+
File.read(target.path).should == "hello, world\n"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 2.6.
|
9
|
+
- 14
|
10
|
+
version: 2.6.14
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Puppet Labs
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2012-02-22 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: facter
|
@@ -1296,6 +1296,7 @@ files:
|
|
1296
1296
|
- spec/unit/type/file_spec.rb
|
1297
1297
|
- spec/unit/type/filebucket_spec.rb
|
1298
1298
|
- spec/unit/type/group_spec.rb
|
1299
|
+
- spec/unit/type/k5login_spec.rb
|
1299
1300
|
- spec/unit/type/macauthorization_spec.rb
|
1300
1301
|
- spec/unit/type/maillist_spec.rb
|
1301
1302
|
- spec/unit/type/mcx_spec.rb
|
@@ -1361,6 +1362,7 @@ files:
|
|
1361
1362
|
- spec/unit/util/user_attr_spec.rb
|
1362
1363
|
- spec/unit/util/warnings_spec.rb
|
1363
1364
|
- spec/unit/util/zaml_spec.rb
|
1365
|
+
- spec/unit/util_spec.rb
|
1364
1366
|
- bin/puppetca
|
1365
1367
|
- bin/puppetd
|
1366
1368
|
- bin/puppetmasterd
|