diff options
author | Nate Walck <nwalck@fb.com> | 2015-07-20 15:48:07 -0700 |
---|---|---|
committer | Nate Walck <nwalck@fb.com> | 2015-08-11 09:38:12 -0700 |
commit | 55b584bd808ffce4e9fd54e4a65a9964a75e7c07 (patch) | |
tree | a0f01db1bd3ba19cfac6cc1455813645e3feb5c4 | |
parent | 3a5e1819c4439836767a001182c1e19de1cfb7e9 (diff) | |
download | chef-55b584bd808ffce4e9fd54e4a65a9964a75e7c07.tar.gz |
Added support for OS X 10.11 SIP paths
-rw-r--r-- | chef-config/lib/chef-config/path_helper.rb | 31 | ||||
-rw-r--r-- | lib/chef/provider/directory.rb | 16 | ||||
-rw-r--r-- | spec/unit/provider/directory_spec.rb | 34 |
3 files changed, 79 insertions, 2 deletions
diff --git a/chef-config/lib/chef-config/path_helper.rb b/chef-config/lib/chef-config/path_helper.rb index acc6b76377..45f451479a 100644 --- a/chef-config/lib/chef-config/path_helper.rb +++ b/chef-config/lib/chef-config/path_helper.rb @@ -228,6 +228,37 @@ module ChefConfig joined_paths end end + + # Determine if the given path is protected by OS X System Integrity Protection. + def self.is_sip_path?(path, node) + if node['platform'] == 'mac_os_x' and Gem::Version.new(node['platform_version']) >= Gem::Version.new('10.11') + # todo: parse rootless.conf for this? + sip_paths= [ + '/System', '/bin', '/sbin', '/usr', + ] + sip_paths.each do |sip_path| + ChefConfig.logger.info("This is a SIP path, checking if it in exceptions list.") + return true if path.start_with?(sip_path) + end + false + else + false + end + end + # Determine if the given path is on the exception list for OS X System Integrity Protection. + def self.writable_sip_path?(path) + # todo: parse rootless.conf for this? + sip_exceptions = [ + '/System/Library/Caches', '/System/Library/Extensions', + '/System/Library/Speech', '/System/Library/User Template', + '/usr/libexec/cups', '/usr/local', '/usr/share/man' + ] + sip_exceptions.each do |exception_path| + return true if path.start_with?(exception_path) + end + ChefConfig.logger.error("Cannot write to a SIP Path on OS X 10.11+") + false + end end end diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb index 4d5423d0e8..8892d3a73d 100644 --- a/lib/chef/provider/directory.rb +++ b/lib/chef/provider/directory.rb @@ -64,7 +64,13 @@ class Chef is_parent_writable = lambda do |base_dir| base_dir = ::File.dirname(base_dir) if ::File.exists?(base_dir) - Chef::FileAccessControl.writable?(base_dir) + if Chef::FileAccessControl.writable?(base_dir) + true + elsif Chef::Util::PathHelper.is_sip_path?(base_dir, node) + Chef::Util::PathHelper.writable_sip_path?(base_dir) + else + false + end else is_parent_writable.call(base_dir) end @@ -74,7 +80,13 @@ class Chef # in why run mode & parent directory does not exist no permissions check is required # If not in why run, permissions must be valid and we rely on prior assertion that dir exists if !whyrun_mode? || ::File.exists?(parent_directory) - Chef::FileAccessControl.writable?(parent_directory) + if Chef::FileAccessControl.writable?(parent_directory) + true + elsif Chef::Util::PathHelper.is_sip_path?(parent_directory, node) + Chef::Util::PathHelper.writable_sip_path?(@new_resource.path) + else + false + end else true end diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb index 38d6db8320..e79f41d9f4 100644 --- a/spec/unit/provider/directory_spec.rb +++ b/spec/unit/provider/directory_spec.rb @@ -197,6 +197,40 @@ describe Chef::Provider::Directory do expect { directory.run_action(:create) }.to raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) end end + + describe "on OS X" do + before do + allow(node).to receive(:[]).with("platform").and_return('mac_os_x') + new_resource.path "/usr/bin/chef_test" + new_resource.recursive false + end + + it "os x 10.10 can write to sip locations" do + allow(node).to receive(:[]).with("platform_version").and_return('10.10') + allow(Dir).to receive(:mkdir).and_return([true], []) + allow(::File).to receive(:directory?).and_return(true) + allow(Chef::FileAccessControl).to receive(:writable?).and_return(true) + directory.run_action(:create) + expect(new_resource).to be_updated + end + + it "os x 10.11 cannot write to sip locations" do + allow(node).to receive(:[]).with("platform_version").and_return('10.11') + allow(::File).to receive(:directory?).and_return(true) + allow(Chef::FileAccessControl).to receive(:writable?).and_return(false) + expect {directory.run_action(:create) }.to raise_error(Chef::Exceptions::InsufficientPermissions) + end + + it "os x 10.11 can write to sip exlcusions" do + new_resource.path "/usr/local/chef_test" + allow(node).to receive(:[]).with("platform_version").and_return('10.11') + allow(::File).to receive(:directory?).and_return(true) + allow(Dir).to receive(:mkdir).and_return([true], []) + allow(Chef::FileAccessControl).to receive(:writable?).and_return(false) + directory.run_action(:create) + expect(new_resource).to be_updated + end + end end describe "#run_action(:create)" do |