chef-rewind 0.0.5 → 0.0.6

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.
Files changed (53) hide show
  1. data/CHANGELOG +17 -0
  2. data/Gemfile +42 -2
  3. data/README.md +2 -0
  4. data/chef-rewind.gemspec +1 -1
  5. data/lib/chef/rewind.rb +7 -0
  6. data/spec/data/cookbooks/angrybash/recipes/default.rb +8 -0
  7. data/spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl +2 -0
  8. data/spec/data/cookbooks/apache2/recipes/default.rb +3 -0
  9. data/spec/data/cookbooks/borken/recipes/default.rb +2 -0
  10. data/spec/data/cookbooks/borken/templates/default/borken.erb +2 -0
  11. data/spec/data/cookbooks/chefignore +6 -0
  12. data/spec/data/cookbooks/java/files/default/java.response +2 -0
  13. data/spec/data/cookbooks/openldap/attributes/default.rb +16 -0
  14. data/spec/data/cookbooks/openldap/attributes/smokey.rb +1 -0
  15. data/spec/data/cookbooks/openldap/definitions/client.rb +5 -0
  16. data/spec/data/cookbooks/openldap/definitions/server.rb +5 -0
  17. data/spec/data/cookbooks/openldap/files/default/.dotfile +1 -0
  18. data/spec/data/cookbooks/openldap/files/default/.ssh/id_rsa +1 -0
  19. data/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir +1 -0
  20. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt +3 -0
  21. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt +3 -0
  22. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile +1 -0
  23. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt +3 -0
  24. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt +3 -0
  25. data/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt +3 -0
  26. data/spec/data/cookbooks/openldap/recipes/default.rb +3 -0
  27. data/spec/data/cookbooks/openldap/recipes/gigantor.rb +3 -0
  28. data/spec/data/cookbooks/openldap/recipes/one.rb +15 -0
  29. data/spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb +1 -0
  30. data/spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb +1 -0
  31. data/spec/data/cookbooks/openldap/templates/default/test.erb +1 -0
  32. data/spec/rewind_recipe_spec.rb +62 -0
  33. data/spec/rewind_resource_spec.rb +34 -0
  34. data/spec/spec_helper.rb +81 -0
  35. data/spec/support/chef_helpers.rb +52 -0
  36. data/spec/support/lib/chef/provider/easy.rb +35 -0
  37. data/spec/support/lib/chef/provider/snakeoil.rb +40 -0
  38. data/spec/support/lib/chef/resource/cat.rb +41 -0
  39. data/spec/support/lib/chef/resource/one_two_three_four.rb +43 -0
  40. data/spec/support/lib/chef/resource/zen_master.rb +46 -0
  41. data/spec/support/matchers/leak.rb +96 -0
  42. data/spec/support/mock/constant.rb +52 -0
  43. data/spec/support/mock/platform.rb +18 -0
  44. data/spec/support/platform_helpers.rb +31 -0
  45. data/spec/support/platforms/prof/gc.rb +54 -0
  46. data/spec/support/platforms/prof/win32.rb +46 -0
  47. data/spec/support/shared/functional/directory_resource.rb +85 -0
  48. data/spec/support/shared/functional/file_resource.rb +173 -0
  49. data/spec/support/shared/functional/knife.rb +37 -0
  50. data/spec/support/shared/functional/securable_resource.rb +394 -0
  51. data/spec/support/shared/unit/api_error_inspector.rb +192 -0
  52. data/spec/support/shared/unit/platform_introspector.rb +162 -0
  53. metadata +99 -4
@@ -0,0 +1,46 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/win32/process'
20
+
21
+ module RSpec
22
+ module Prof
23
+ module Win32
24
+ class Profiler
25
+
26
+ def start
27
+ GC.start
28
+ end
29
+
30
+ def stop
31
+ GC.start
32
+ end
33
+
34
+ def working_set_size
35
+ Chef::ReservedNames::Win32::Process.get_current_process.memory_info[:WorkingSetSize]
36
+ end
37
+
38
+ def handle_count
39
+ Chef::ReservedNames::Win32::Process.get_current_process.handle_count
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,85 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ shared_examples_for "a directory resource" do
20
+ context "when the target directory does not exist" do
21
+ it "creates the directory when the :create action is run" do
22
+ resource.run_action(:create)
23
+ File.should exist(path)
24
+ end
25
+
26
+ it "recursively creates required directories if requested" do
27
+ resource.recursive(true)
28
+ recursive_path = File.join(path, 'red-headed-stepchild')
29
+ resource.path(recursive_path)
30
+ resource.run_action(:create)
31
+ File.should exist(path)
32
+ File.should exist(recursive_path)
33
+ end
34
+ end
35
+
36
+ context "when the target directory exists" do
37
+ before(:each) do
38
+ FileUtils.mkdir(path)
39
+ end
40
+
41
+ it "does not re-create the directory" do
42
+ resource.run_action(:create)
43
+ File.should exist(path)
44
+ end
45
+
46
+ it "deletes the directory when the :delete action is run" do
47
+ resource.run_action(:delete)
48
+ File.should_not exist(path)
49
+ end
50
+
51
+ it "recursively deletes directories if requested" do
52
+ FileUtils.mkdir(File.join(path, 'red-headed-stepchild'))
53
+ resource.recursive(true)
54
+ resource.run_action(:delete)
55
+ File.should_not exist(path)
56
+ end
57
+ end
58
+
59
+ # Set up the context for security tests
60
+ def allowed_acl(sid, expected_perms)
61
+ [
62
+ ACE.access_allowed(sid, expected_perms[:specific]),
63
+ ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
64
+ ]
65
+ end
66
+
67
+ def denied_acl(sid, expected_perms)
68
+ [
69
+ ACE.access_denied(sid, expected_perms[:specific]),
70
+ ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE))
71
+ ]
72
+ end
73
+
74
+ it_behaves_like "a securable resource"
75
+ end
76
+
77
+ shared_context Chef::Resource::Directory do
78
+ let(:path) do
79
+ File.join(Dir.tmpdir, make_tmpname(directory_base, nil))
80
+ end
81
+
82
+ after(:each) do
83
+ FileUtils.rm_r(path) if File.exists?(path)
84
+ end
85
+ end
@@ -0,0 +1,173 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ shared_examples_for "a file with the wrong content" do
20
+ it "overwrites the file with the updated content when the :create action is run" do
21
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
22
+ sleep 1
23
+ resource.run_action(:create)
24
+ File.stat(path).mtime.should > @expected_mtime
25
+ sha256_checksum(path).should_not == @expected_checksum
26
+ end
27
+
28
+ it "doesn't overwrite the file when the :create_if_missing action is run" do
29
+ sleep 1
30
+ resource.run_action(:create_if_missing)
31
+ File.stat(path).mtime.should == @expected_mtime
32
+ sha256_checksum(path).should == @expected_checksum
33
+ end
34
+
35
+ it "should backup the existing file" do
36
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
37
+ resource.run_action(:create)
38
+ Dir.glob(backup_glob).size.should equal(1)
39
+ end
40
+
41
+ it "should not attempt to backup the existing file if :backup == 0" do
42
+ Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH
43
+ resource.backup(0)
44
+ resource.run_action(:create)
45
+ Dir.glob(backup_glob).size.should equal(0)
46
+ end
47
+
48
+ it "deletes the file when the :delete action is run" do
49
+ resource.run_action(:delete)
50
+ File.should_not exist(path)
51
+ end
52
+ end
53
+
54
+ shared_examples_for "a file with the correct content" do
55
+ it "does not overwrite the original when the :create action is run" do
56
+ resource.run_action(:create)
57
+ sha256_checksum(path).should == @expected_checksum
58
+ end
59
+
60
+ it "does not update the mtime/atime of the file when the :create action is run" do
61
+ sleep 1
62
+ File.stat(path).mtime.should == @expected_mtime
63
+ File.stat(path).atime.should be_within(2).of(@expected_atime)
64
+ end
65
+
66
+ it "doesn't overwrite the file when the :create_if_missing action is run" do
67
+ resource.run_action(:create_if_missing)
68
+ sha256_checksum(path).should == @expected_checksum
69
+ end
70
+
71
+ it "deletes the file when the :delete action is run" do
72
+ resource.run_action(:delete)
73
+ File.should_not exist(path)
74
+ end
75
+ end
76
+
77
+ shared_examples_for "a file resource" do
78
+ # note the stripping of the drive letter from the tmpdir on windows
79
+ let(:backup_glob) { File.join(CHEF_SPEC_BACKUP_PATH, Dir.tmpdir.sub(/^([A-Za-z]:)/, ""), "#{file_base}*") }
80
+
81
+ context "when the target file does not exist" do
82
+ it "creates the file when the :create action is run" do
83
+ resource.run_action(:create)
84
+ File.should exist(path)
85
+ end
86
+
87
+ it "creates the file with the correct content when the :create action is run" do
88
+ resource.run_action(:create)
89
+ IO.read(path).should == expected_content
90
+ end
91
+
92
+ it "creates the file with the correct content when the :create_if_missing action is run" do
93
+ resource.run_action(:create_if_missing)
94
+ IO.read(path).should == expected_content
95
+ end
96
+
97
+ it "deletes the file when the :delete action is run" do
98
+ resource.run_action(:delete)
99
+ File.should_not exist(path)
100
+ end
101
+ end
102
+
103
+ # Set up the context for security tests
104
+ def allowed_acl(sid, expected_perms)
105
+ [ ACE.access_allowed(sid, expected_perms[:specific]) ]
106
+ end
107
+
108
+ def denied_acl(sid, expected_perms)
109
+ [ ACE.access_denied(sid, expected_perms[:specific]) ]
110
+ end
111
+
112
+
113
+ context "when the target file has the wrong content" do
114
+ before(:each) do
115
+ File.open(path, "w") { |f| f.print "This is so wrong!!!" }
116
+ @expected_mtime = File.stat(path).mtime
117
+ @expected_checksum = sha256_checksum(path)
118
+ end
119
+
120
+ describe "and the target file has the correct permissions" do
121
+ include_context "setup correct permissions"
122
+
123
+ it_behaves_like "a file with the wrong content"
124
+
125
+ it_behaves_like "a securable resource"
126
+ end
127
+
128
+ context "and the target file has incorrect permissions" do
129
+ include_context "setup broken permissions"
130
+
131
+ it_behaves_like "a file with the wrong content"
132
+
133
+ it_behaves_like "a securable resource"
134
+ end
135
+ end
136
+
137
+ context "when the target file has the correct content" do
138
+ before(:each) do
139
+ File.open(path, "w") { |f| f.print expected_content }
140
+ @expected_mtime = File.stat(path).mtime
141
+ @expected_atime = File.stat(path).atime
142
+ @expected_checksum = sha256_checksum(path)
143
+ end
144
+
145
+ describe "and the target file has the correct permissions" do
146
+ include_context "setup correct permissions"
147
+
148
+ it_behaves_like "a file with the correct content"
149
+
150
+ it_behaves_like "a securable resource"
151
+ end
152
+
153
+ context "and the target file has incorrect permissions" do
154
+ include_context "setup broken permissions"
155
+
156
+ it_behaves_like "a file with the correct content"
157
+
158
+ it_behaves_like "a securable resource"
159
+ end
160
+ end
161
+
162
+ end
163
+
164
+ shared_context Chef::Resource::File do
165
+ let(:path) do
166
+ File.join(Dir.tmpdir, make_tmpname(file_base, nil))
167
+ end
168
+
169
+ after(:each) do
170
+ FileUtils.rm_r(path) if File.exists?(path)
171
+ FileUtils.rm_r(CHEF_SPEC_BACKUP_PATH) if File.exists?(CHEF_SPEC_BACKUP_PATH)
172
+ end
173
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: AJ Christensen (<aj@junglist.gen.nz>)
4
+ # Author:: Ho-Sheng Hsiao (<hosh@opscode.com>)
5
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ module SpecHelpers
21
+ module Knife
22
+ def redefine_argv(value)
23
+ Object.send(:remove_const, :ARGV)
24
+ Object.send(:const_set, :ARGV, value)
25
+ end
26
+
27
+ def with_argv(*argv)
28
+ original_argv = ARGV
29
+ redefine_argv(argv.flatten)
30
+ begin
31
+ yield
32
+ ensure
33
+ redefine_argv(original_argv)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,394 @@
1
+ #
2
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
3
+ # Author:: Mark Mzyk (<mmzyk@opscode.com>)
4
+ # Author:: John Keiser (<jkeiser@opscode.com>)
5
+ # Copyright:: Copyright (c) 2011 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ # TODO test that these work when you are logged on as a user joined to a domain (rather than local computer)
22
+ # TODO test that you can set users from other domains
23
+
24
+ require 'etc'
25
+
26
+ shared_context "setup correct permissions" do
27
+ context "on unix", :unix_only do
28
+ context "with root", :requires_root do
29
+ before :each do
30
+ File.chown(Etc.getpwnam('nobody').uid, 1337, path)
31
+ File.chmod(0776, path)
32
+ end
33
+ end
34
+
35
+ context "without root", :requires_unprivileged_user do
36
+ before :each do
37
+ File.chmod(0776, path)
38
+ end
39
+ end
40
+ end
41
+
42
+ # FIXME: windows
43
+ end
44
+
45
+ shared_context "setup broken permissions" do
46
+ context "on unix", :unix_only do
47
+ context "with root", :requires_root do
48
+ before :each do
49
+ File.chown(0, 0, path)
50
+ File.chmod(0644, path)
51
+ end
52
+ end
53
+
54
+ context "without root", :requires_unprivileged_user do
55
+ before :each do
56
+ File.chmod(0644, path)
57
+ end
58
+ end
59
+ end
60
+
61
+ # FIXME: windows
62
+ end
63
+
64
+ shared_examples_for "a securable resource" do
65
+ context "on Unix", :unix_only do
66
+ let(:expected_user_name) { 'nobody' }
67
+ let(:expected_uid) { Etc.getpwnam(expected_user_name).uid }
68
+ let(:desired_gid) { 1337 }
69
+ let(:expected_gid) { 1337 }
70
+
71
+ pending "should set an owner (Rerun specs under root)", :requires_unprivileged_user => true
72
+ pending "should set a group (Rerun specs under root)", :requires_unprivileged_user => true
73
+
74
+ it "should set an owner", :requires_root do
75
+ resource.owner expected_user_name
76
+ resource.run_action(:create)
77
+ File.lstat(path).uid.should == expected_uid
78
+ end
79
+
80
+ it "should set a group", :requires_root do
81
+ resource.group desired_gid
82
+ resource.run_action(:create)
83
+ File.lstat(path).gid.should == expected_gid
84
+ end
85
+
86
+ it "should set permissions in string form as an octal number" do
87
+ mode_string = '776'
88
+ resource.mode mode_string
89
+ resource.run_action(:create)
90
+ pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do
91
+ (File.lstat(path).mode & 007777).should == (mode_string.oct & 007777)
92
+ end
93
+ end
94
+
95
+ it "should set permissions in numeric form as a ruby-interpreted octal" do
96
+ mode_integer = 0776
97
+ resource.mode mode_integer
98
+ resource.run_action(:create)
99
+ pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do
100
+ (File.lstat(path).mode & 007777).should == (mode_integer & 007777)
101
+ end
102
+ end
103
+ end
104
+
105
+ context "on Windows", :windows_only do
106
+
107
+ if windows?
108
+ SID = Chef::ReservedNames::Win32::Security::SID
109
+ ACE = Chef::ReservedNames::Win32::Security::ACE
110
+ end
111
+
112
+ def get_security_descriptor(path)
113
+ Chef::ReservedNames::Win32::Security.get_named_security_info(path)
114
+ end
115
+
116
+ def explicit_aces
117
+ descriptor.dacl.select { |ace| ace.explicit? }
118
+ end
119
+
120
+ def extract_ace_properties(aces)
121
+ hashes = []
122
+ aces.each do |ace|
123
+ hashes << { :mask => ace.mask, :type => ace.type, :flags => ace.flags }
124
+ end
125
+ hashes
126
+ end
127
+
128
+ # Standard expected rights
129
+ let(:expected_read_perms) do
130
+ {
131
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ,
132
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ,
133
+ }
134
+ end
135
+
136
+ let(:expected_read_execute_perms) do
137
+ {
138
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE,
139
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE
140
+ }
141
+ end
142
+
143
+ let(:expected_write_perms) do
144
+ {
145
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
146
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE
147
+ }
148
+ end
149
+
150
+ let(:expected_modify_perms) do
151
+ {
152
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE,
153
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE
154
+ }
155
+ end
156
+
157
+ let(:expected_full_control_perms) do
158
+ {
159
+ :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_ALL,
160
+ :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS
161
+ }
162
+ end
163
+
164
+ RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
165
+ match do |ace|
166
+ ace.mask == mask
167
+ ace.type == type
168
+ ace.flags == flags
169
+ end
170
+ end
171
+
172
+ def descriptor
173
+ get_security_descriptor(path)
174
+ end
175
+
176
+ before(:each) do
177
+ resource.run_action(:delete)
178
+ end
179
+
180
+ it "sets owner to Administrators on create if owner is not specified" do
181
+ File.exist?(path).should == false
182
+ resource.run_action(:create)
183
+ descriptor.owner.should == SID.Administrators
184
+ end
185
+
186
+ it "sets owner when owner is specified" do
187
+ resource.owner 'Guest'
188
+ resource.run_action(:create)
189
+ descriptor.owner.should == SID.Guest
190
+ end
191
+
192
+ it "fails to set owner when owner has invalid characters" do
193
+ lambda { resource.owner 'Lance "The Nose" Glindenberry III' }.should raise_error#(Chef::Exceptions::ValidationFailed)
194
+ end
195
+
196
+ it "sets owner when owner is specified with a \\" do
197
+ resource.owner "#{ENV['USERDOMAIN']}\\Guest"
198
+ resource.run_action(:create)
199
+ descriptor.owner.should == SID.Guest
200
+ end
201
+
202
+ it "leaves owner alone if owner is not specified and resource already exists" do
203
+ # Set owner to Guest so it's not the same as the current user (which is the default on create)
204
+ resource.owner 'Guest'
205
+ resource.run_action(:create)
206
+ descriptor.owner.should == SID.Guest
207
+
208
+ new_resource = create_resource
209
+ new_resource.owner.should == nil
210
+ new_resource.run_action(:create)
211
+ descriptor.owner.should == SID.Guest
212
+ end
213
+
214
+ it "sets group to None on create if group is not specified" do
215
+ resource.group.should == nil
216
+ File.exist?(path).should == false
217
+ resource.run_action(:create)
218
+ descriptor.group.should == SID.None
219
+ end
220
+
221
+ it "sets group when group is specified" do
222
+ resource.group 'Everyone'
223
+ resource.run_action(:create)
224
+ descriptor.group.should == SID.Everyone
225
+ end
226
+
227
+ it "fails to set group when group has invalid characters" do
228
+ lambda { resource.group 'Lance "The Nose" Glindenberry III' }.should raise_error(Chef::Exceptions::ValidationFailed)
229
+ end
230
+
231
+ it "sets group when group is specified with a \\" do
232
+ pending "Need to find a group containing a backslash that is on most peoples' machines" do
233
+ resource.group "#{ENV['COMPUTERNAME']}\\Administrators"
234
+ resource.run_action(:create)
235
+ descriptor.group.should == SID.Everyone
236
+ end
237
+ end
238
+
239
+ it "leaves group alone if group is not specified and resource already exists" do
240
+ # Set group to Everyone so it's not the default (None)
241
+ resource.group 'Everyone'
242
+ resource.run_action(:create)
243
+ descriptor.group.should == SID.Everyone
244
+
245
+ new_resource = create_resource
246
+ new_resource.group.should == nil
247
+ new_resource.run_action(:create)
248
+ descriptor.group.should == SID.Everyone
249
+ end
250
+
251
+ describe "with rights and deny_rights attributes" do
252
+
253
+ it "correctly sets :read rights" do
254
+ resource.rights(:read, 'Guest')
255
+ resource.run_action(:create)
256
+ explicit_aces.should == allowed_acl(SID.Guest, expected_read_perms)
257
+ end
258
+
259
+ it "correctly sets :read_execute rights" do
260
+ resource.rights(:read_execute, 'Guest')
261
+ resource.run_action(:create)
262
+ explicit_aces.should == allowed_acl(SID.Guest, expected_read_execute_perms)
263
+ end
264
+
265
+ it "correctly sets :write rights" do
266
+ resource.rights(:write, 'Guest')
267
+ resource.run_action(:create)
268
+ explicit_aces.should == allowed_acl(SID.Guest, expected_write_perms)
269
+ end
270
+
271
+ it "correctly sets :modify rights" do
272
+ resource.rights(:modify, 'Guest')
273
+ resource.run_action(:create)
274
+ explicit_aces.should == allowed_acl(SID.Guest, expected_modify_perms)
275
+ end
276
+
277
+ it "correctly sets :full_control rights" do
278
+ resource.rights(:full_control, 'Guest')
279
+ resource.run_action(:create)
280
+ explicit_aces.should == allowed_acl(SID.Guest, expected_full_control_perms)
281
+ end
282
+
283
+ it "correctly sets deny_rights" do
284
+ # deny is an ACE with full rights, but is a deny type ace, not an allow type
285
+ resource.deny_rights(:full_control, 'Guest')
286
+ resource.run_action(:create)
287
+ explicit_aces.should == denied_acl(SID.Guest, expected_full_control_perms)
288
+ end
289
+
290
+ it "Sets multiple rights" do
291
+ resource.rights(:read, 'Everyone')
292
+ resource.rights(:modify, 'Guest')
293
+ resource.run_action(:create)
294
+
295
+ explicit_aces.should ==
296
+ allowed_acl(SID.Everyone, expected_read_perms) +
297
+ allowed_acl(SID.Guest, expected_modify_perms)
298
+ end
299
+
300
+ it "Sets deny_rights ahead of rights" do
301
+ resource.rights(:read, 'Everyone')
302
+ resource.deny_rights(:modify, 'Guest')
303
+ resource.run_action(:create)
304
+
305
+ explicit_aces.should ==
306
+ denied_acl(SID.Guest, expected_modify_perms) +
307
+ allowed_acl(SID.Everyone, expected_read_perms)
308
+ end
309
+
310
+ it "Sets deny_rights ahead of rights when specified in reverse order" do
311
+ resource.deny_rights(:modify, 'Guest')
312
+ resource.rights(:read, 'Everyone')
313
+ resource.run_action(:create)
314
+
315
+ explicit_aces.should ==
316
+ denied_acl(SID.Guest, expected_modify_perms) +
317
+ allowed_acl(SID.Everyone, expected_read_perms)
318
+ end
319
+
320
+ end
321
+
322
+ context "with a mode attribute" do
323
+ if windows?
324
+ Security = Chef::ReservedNames::Win32::API::Security
325
+ end
326
+
327
+ it "respects mode in string form as an octal number" do
328
+ #on windows, mode cannot modify owner and/or group permissons
329
+ #unless the owner and/or group as appropriate is specified
330
+ resource.mode '400'
331
+ resource.owner 'Guest'
332
+ resource.group 'Everyone'
333
+ resource.run_action(:create)
334
+
335
+ explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ) ]
336
+ end
337
+
338
+ it "respects mode in numeric form as a ruby-interpreted octal" do
339
+ resource.mode 0700
340
+ resource.owner 'Guest'
341
+ resource.run_action(:create)
342
+
343
+ explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE) ]
344
+ end
345
+
346
+ it "respects the owner, group and everyone bits of mode" do
347
+ resource.mode 0754
348
+ resource.owner 'Guest'
349
+ resource.group 'Administrators'
350
+ resource.run_action(:create)
351
+
352
+ explicit_aces.should == [
353
+ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE),
354
+ ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_EXECUTE),
355
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ)
356
+ ]
357
+ end
358
+
359
+ it "respects the individual read, write and execute bits of mode" do
360
+ resource.mode 0421
361
+ resource.owner 'Guest'
362
+ resource.group 'Administrators'
363
+ resource.run_action(:create)
364
+
365
+ explicit_aces.should == [
366
+ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ),
367
+ ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_WRITE | Security::DELETE),
368
+ ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE)
369
+ ]
370
+ end
371
+
372
+ it 'warns when mode tries to set owner bits but owner is not specified' do
373
+ @warn = []
374
+ Chef::Log.stub!(:warn) { |msg| @warn << msg }
375
+
376
+ resource.mode 0400
377
+ resource.run_action(:create)
378
+
379
+ @warn.include?("Mode 400 includes bits for the owner, but owner is not specified").should be_true
380
+ end
381
+
382
+ it 'warns when mode tries to set group bits but group is not specified' do
383
+ @warn = []
384
+ Chef::Log.stub!(:warn) { |msg| @warn << msg }
385
+
386
+ resource.mode 0040
387
+ resource.run_action(:create)
388
+
389
+ @warn.include?("Mode 040 includes bits for the group, but group is not specified").should be_true
390
+ end
391
+ end
392
+
393
+ end
394
+ end