Class: RuboCop::Cop::Chef::Correctness::ExecuteDeleteFile

Inherits:
Base
  • Object
show all
Includes:
RuboCop::Chef::CookbookHelpers
Defined in:
lib/rubocop/cop/chef/correctness/execute_delete_file.rb

Overview

Use the file or directory resources built into Chef Infra Client with the :delete action to remove files and directories instead of shelling out to rm. The resources are idempotent, report correctly on what they changed, and work without a shell.

The two resources are not interchangeable and the one you pick has to match what is on disk. directory asserts the path really is a directory before deleting, so it raises Cannot delete directory[...] on a file even with recursive true, and file calls File.delete, so it raises Errno::EISDIR on a directory. A directory delete also needs recursive true for anything that isn't empty, or it raises Errno::ENOTEMPTY.

Only a single rm of one path is flagged. A command containing a glob, a shell operator, or anything beyond the one deletion is left alone, since the file and directory resources can't express those.

Examples:


# bad -- rm without -r, which the shell will not let you point at a directory
execute 'rm /etc/foo.conf'

# good
file '/etc/foo.conf' do
  action :delete
end

# bad -- a recursive rm of a directory
execute 'delete the thing' do
  command 'rm -rf /opt/thing'
end

# good
directory '/opt/thing' do
  recursive true
  action :delete
end

Constant Summary collapse

FILE_MSG =

The two resources are not interchangeable, so the message has to name the right one. directory asserts the path really is a directory before deleting, and file calls File.delete, so pointing at the wrong one fails the converge rather than doing nothing.

'Use the `file` resource with the :delete action to remove a file instead of shelling out to rm'
DIRECTORY_MSG =
'Use the `directory` resource with `recursive true` and the :delete action to remove a directory instead of shelling out to rm. Use the `file` resource instead if the path is a file.'
RESTRICT_ON_SEND =
[:execute].freeze
DELETE_COMMAND =

a lone rm of a single path: optional flags, one target, nothing else on the line. the target excludes the shell metacharacters used for substitution and expansion, since a path the shell computes at runtime isn't something the file/directory resources can take

%r{\A\s*(?:/bin/|/usr/bin/)?rm\s+(?<flags>(?:-[a-zA-Z]+\s+)*)(?<path>[^\s;&|<>$`(){}]+)\s*\z}.freeze
SCRIPT_RESOURCES =

the shell resources whose script lives in a code property

%i(bash sh csh ksh zsh).freeze

Instance Method Summary collapse

Methods included from RuboCop::Chef::CookbookHelpers

#each_action_symbol, #match_property_in_resource?, #match_resource_type?, #method_arg_ast_to_string, #resource_block_name_if_string

Methods inherited from Base

#target_chef_version

Instance Method Details

#on_block(node) ⇒ Object



85
86
87
88
89
90
91
92
93
# File 'lib/rubocop/cop/chef/correctness/execute_delete_file.rb', line 85

def on_block(node)
  match_property_in_resource?(:execute, 'command', node) do |property|
    report_property(node, property)
  end

  match_property_in_resource?(SCRIPT_RESOURCES, 'code', node) do |property|
    report_property(node, property)
  end
end

#on_send(node) ⇒ Object



78
79
80
81
82
83
# File 'lib/rubocop/cop/chef/correctness/execute_delete_file.rb', line 78

def on_send(node)
  execute_with_command_name?(node) do |command|
    message = message_for(command)
    add_offense(node, message: message, severity: :refactor) if message
  end
end