Skip to content

Instantly share code, notes, and snippets.

@natewalck
Last active August 29, 2015 14:25
Show Gist options
  • Save natewalck/12ab83d8a69ec3ecb80d to your computer and use it in GitHub Desktop.
Save natewalck/12ab83d8a69ec3ecb80d to your computer and use it in GitHub Desktop.
def define_resource_requirements
requirements.assert(:create) do |a|
# Make sure the parent dir exists, or else fail.
# for why run, print a message explaining the potential error.
parent_directory = ::File.dirname(@new_resource.path)
a.assertion { @new_resource.recursive || ::File.directory?(parent_directory) }
a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist, cannot create #{@new_resource.path}")
a.whyrun("Assuming directory #{parent_directory} would have been created")
end
requirements.assert(:create) do |a|
parent_directory = ::File.dirname(@new_resource.path)
a.assertion do
if @new_resource.recursive
# find the lowest-level directory in @new_resource.path that already exists
# make sure we have write permissions to that directory
is_parent_writable = lambda do |base_dir|
base_dir = ::File.dirname(base_dir)
if ::File.exists?(base_dir)
Chef::FileAccessControl.writable?(base_dir)
else
is_parent_writable.call(base_dir)
end
end
is_parent_writable.call(@new_resource.path)
else
# 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)
if Chef::FileAccessControl.writable?(parent_directory)
true
elsif Gem::Version.new(node['platform_version']) >= Gem::Version.new('10.11') && Chef::Util::PathHelper.is_sip_path?(parent_directory)
Chef::Util::PathHelper.writable_sip_path?(@new_resource.path)
else
false
end
else
true
end
end
end
a.failure_message(Chef::Exceptions::InsufficientPermissions,
"Cannot create #{@new_resource} at #{@new_resource.path} due to insufficient permissions")
end
#
# Author:: Nate Walck <nwalck@fb.com>
# Copyright:: Copyright (c) 2015 Facebook, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Chef
class Util
class PathHelper
def self.is_sip_path?(path)
# todo: parse rootless.conf for this?
sip_paths= [
'/System', '/bin', '/sbin', '/usr',
]
sip_paths.each do |sip_path|
return true if path.start_with?(sip_path)
end
false
end
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
false
end
end
end
end
# Break a require loop when require chef/util/path_helper
require 'chef/platform'
require 'chef/exceptions'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment