cookstyle 8.7.6 → 9.0.0

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/config/chefstyle.yml +2 -0
  3. data/config/cookstyle.yml +145 -6
  4. data/lib/cookstyle/version.rb +2 -2
  5. data/lib/rubocop/chef/cookbook_helpers.rb +23 -0
  6. data/lib/rubocop/chef.rb +1 -1
  7. data/lib/rubocop/cop/chef/correctness/chef_application_fatal.rb +16 -4
  8. data/lib/rubocop/cop/chef/correctness/conditional_unified_mode_true.rb +91 -0
  9. data/lib/rubocop/cop/chef/correctness/empty_resource_guard.rb +18 -2
  10. data/lib/rubocop/cop/chef/correctness/execute_delete_file.rb +127 -0
  11. data/lib/rubocop/cop/chef/correctness/invalid_checksum.rb +79 -0
  12. data/lib/rubocop/cop/chef/correctness/invalid_platform_family_helper.rb +1 -1
  13. data/lib/rubocop/cop/chef/correctness/invalid_platform_family_values_in_case.rb +10 -0
  14. data/lib/rubocop/cop/chef/correctness/invalid_platform_values_in_case.rb +10 -0
  15. data/lib/rubocop/cop/chef/correctness/invalid_value_for_platform_helper.rb +1 -0
  16. data/lib/rubocop/cop/chef/correctness/openssl_password_helpers.rb +1 -1
  17. data/lib/rubocop/cop/chef/correctness/platform_version_string_comparison.rb +66 -0
  18. data/lib/rubocop/cop/chef/correctness/powershell_delete_file.rb +5 -5
  19. data/lib/rubocop/cop/chef/correctness/powershell_file_exists.rb +1 -1
  20. data/lib/rubocop/cop/chef/correctness/resource_with_none_action.rb +3 -3
  21. data/lib/rubocop/cop/chef/correctness/ruby_guard_without_block.rb +91 -0
  22. data/lib/rubocop/cop/chef/correctness/service_resource.rb +71 -20
  23. data/lib/rubocop/cop/chef/deprecation/chef_handler_recipe.rb +8 -1
  24. data/lib/rubocop/cop/chef/deprecation/chef_rest.rb +4 -1
  25. data/lib/rubocop/cop/chef/deprecation/chef_shellout.rb +2 -2
  26. data/lib/rubocop/cop/chef/deprecation/chef_sugar_helpers.rb +6 -0
  27. data/lib/rubocop/cop/chef/deprecation/chef_windows_platform_helper.rb +1 -1
  28. data/lib/rubocop/cop/chef/deprecation/chocolatey_package_uninstall_action.rb +3 -3
  29. data/lib/rubocop/cop/chef/deprecation/depends_partial_search.rb +4 -0
  30. data/lib/rubocop/cop/chef/deprecation/deprecated_mixins.rb +2 -2
  31. data/lib/rubocop/cop/chef/deprecation/hwrp_without_provides.rb +4 -4
  32. data/lib/rubocop/cop/chef/deprecation/hwrp_without_unified_mode_true.rb +2 -2
  33. data/lib/rubocop/cop/chef/deprecation/inherits_compat_resource.rb +3 -3
  34. data/lib/rubocop/cop/chef/deprecation/legacy_yum_cookbook_recipes.rb +9 -1
  35. data/lib/rubocop/cop/chef/deprecation/locale_lc_all_property.rb +5 -0
  36. data/lib/rubocop/cop/chef/deprecation/resource_uses_only_resource_name.rb +9 -1
  37. data/lib/rubocop/cop/chef/deprecation/resource_uses_provider_base_method.rb +4 -0
  38. data/lib/rubocop/cop/chef/deprecation/ruby_block_create_action.rb +42 -3
  39. data/lib/rubocop/cop/chef/deprecation/use_automatic_resource_name.rb +9 -0
  40. data/lib/rubocop/cop/chef/deprecation/use_yaml_dump.rb +5 -0
  41. data/lib/rubocop/cop/chef/deprecation/xml_ruby_recipe.rb +5 -1
  42. data/lib/rubocop/cop/chef/modernize/apt_default_recipe.rb +1 -1
  43. data/lib/rubocop/cop/chef/modernize/build_essential.rb +4 -1
  44. data/lib/rubocop/cop/chef/modernize/chef_14_resources.rb +8 -0
  45. data/lib/rubocop/cop/chef/modernize/chef_15_resources.rb +11 -0
  46. data/lib/rubocop/cop/chef/modernize/chef_gem_nokogiri.rb +4 -0
  47. data/lib/rubocop/cop/chef/modernize/conditional_using_test.rb +10 -3
  48. data/lib/rubocop/cop/chef/modernize/cron_d_file_or_template.rb +6 -4
  49. data/lib/rubocop/cop/chef/modernize/databag_helpers.rb +6 -3
  50. data/lib/rubocop/cop/chef/modernize/depends_chef_vault_cookbook.rb +4 -0
  51. data/lib/rubocop/cop/chef/modernize/depends_chocolatey_cookbooks.rb +7 -0
  52. data/lib/rubocop/cop/chef/modernize/depends_kernel_module_cookbook.rb +6 -0
  53. data/lib/rubocop/cop/chef/modernize/depends_locale_cookbook.rb +6 -0
  54. data/lib/rubocop/cop/chef/modernize/depends_openssl_cookbook.rb +9 -0
  55. data/lib/rubocop/cop/chef/modernize/depends_timezone_lwrp_cookbook.rb +4 -0
  56. data/lib/rubocop/cop/chef/modernize/depends_windows_firewall_cookbook.rb +8 -0
  57. data/lib/rubocop/cop/chef/modernize/depends_zypper_cookbook.rb +7 -0
  58. data/lib/rubocop/cop/chef/modernize/dsl_include_in_resource.rb +1 -1
  59. data/lib/rubocop/cop/chef/modernize/execute_apt_update.rb +3 -1
  60. data/lib/rubocop/cop/chef/modernize/execute_archive_extract.rb +121 -0
  61. data/lib/rubocop/cop/chef/modernize/execute_update_alternatives.rb +100 -0
  62. data/lib/rubocop/cop/chef/modernize/includes_mixin_shellout.rb +4 -0
  63. data/lib/rubocop/cop/chef/modernize/libarchive_file.rb +5 -3
  64. data/lib/rubocop/cop/chef/modernize/ohai_default_recipe.rb +6 -1
  65. data/lib/rubocop/cop/chef/modernize/powershell_download_file.rb +64 -0
  66. data/lib/rubocop/cop/chef/modernize/powershell_expand_archive.rb +8 -1
  67. data/lib/rubocop/cop/chef/modernize/powershell_guard_interpreter.rb +4 -4
  68. data/lib/rubocop/cop/chef/modernize/sc_windows_resource.rb +2 -2
  69. data/lib/rubocop/cop/chef/modernize/seven_zip_archive.rb +7 -1
  70. data/lib/rubocop/cop/chef/modernize/shellouts_to_chocolatey.rb +15 -4
  71. data/lib/rubocop/cop/chef/modernize/use_require_relative.rb +1 -1
  72. data/lib/rubocop/cop/chef/modernize/windows_default_recipe.rb +1 -1
  73. data/lib/rubocop/cop/chef/modernize/windows_zipfile.rb +8 -2
  74. data/lib/rubocop/cop/chef/modernize/zipfile_resource.rb +7 -1
  75. data/lib/rubocop/cop/chef/modernize/zypper_repo.rb +2 -2
  76. data/lib/rubocop/cop/chef/redundant/custom_resource_with_allowed_actions.rb +10 -0
  77. data/lib/rubocop/cop/chef/redundant/double_compile_time.rb +22 -8
  78. data/lib/rubocop/cop/chef/redundant/service_guard_on_stop_disable.rb +117 -0
  79. data/lib/rubocop/cop/chef/redundant/string_property_with_nil_default.rb +2 -2
  80. data/lib/rubocop/cop/chef/redundant/unnecessary_name_property.rb +1 -1
  81. data/lib/rubocop/cop/chef/security/insecure_remote_file_source.rb +82 -0
  82. data/lib/rubocop/cop/chef/security/ssh_private_key.rb +9 -0
  83. data/lib/rubocop/cop/chef/sharing/empty_property_description.rb +62 -0
  84. data/lib/rubocop/cop/chef/style/include_recipe_with_parentheses.rb +5 -2
  85. data/lib/rubocop/cop/chef/style/true_false_resource_properties.rb +1 -1
  86. data/lib/rubocop/monkey_patches/directive_comment.rb +21 -3
  87. metadata +15 -4
@@ -38,7 +38,7 @@ module RuboCop
38
38
  def_node_matcher :chef_platform_windows?, <<-PATTERN
39
39
  (send
40
40
  (const
41
- (const nil? :Chef) :Platform) :windows?)
41
+ (const {nil? cbase} :Chef) :Platform) :windows?)
42
42
  PATTERN
43
43
 
44
44
  def on_send(node)
@@ -41,10 +41,10 @@ module RuboCop
41
41
 
42
42
  def on_block(node)
43
43
  match_property_in_resource?(:chocolatey_package, 'action', node) do |choco_action|
44
- choco_action.arguments.each do |action|
45
- next unless action.source == ':uninstall'
44
+ each_action_symbol(choco_action) do |action, prefix|
45
+ next unless action.value == :uninstall
46
46
  add_offense(action, severity: :warning) do |corrector|
47
- corrector.replace(action, ':remove')
47
+ corrector.replace(action, "#{prefix}remove")
48
48
  end
49
49
  end
50
50
  end
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'partial_search'
28
28
  #
29
+ # # good
30
+ # # the built-in search helper takes a filter_result option
31
+ # search(:node, 'role:web', filter_result: { 'name' => ['name'], 'ip' => ['ipaddress'] })
32
+ #
29
33
  class CookbookDependsOnPartialSearch < Base
30
34
  extend TargetChefVersion
31
35
 
@@ -41,11 +41,11 @@ module RuboCop
41
41
  RESTRICT_ON_SEND = [:include, :require].freeze
42
42
 
43
43
  def_node_matcher :deprecated_mixin?, <<-PATTERN
44
- (send nil? :include (const (const (const nil? :Chef) :Mixin) { :Language :LanguageIncludeAttribute :RecipeDefinitionDSLCore :LanguageIncludeRecipe }))
44
+ (send nil? :include (const (const (const {nil? cbase} :Chef) :Mixin) { :Language :LanguageIncludeAttribute :RecipeDefinitionDSLCore :LanguageIncludeRecipe }))
45
45
  PATTERN
46
46
 
47
47
  def_node_matcher :deprecated_dsl?, <<-PATTERN
48
- (send nil? :include (const (const (const (const nil? :Chef) :DSL) :Recipe) :FullDSL))
48
+ (send nil? :include (const (const (const (const {nil? cbase} :Chef) :DSL) :Recipe) :FullDSL))
49
49
  PATTERN
50
50
 
51
51
  def_node_matcher :dsl_mixin_require?, <<-PATTERN
@@ -78,8 +78,8 @@ module RuboCop
78
78
  # end
79
79
  # end
80
80
  #
81
- # # better
82
- # Convert your legacy HWRPs to custom resources
81
+ # # better
82
+ # # Convert your legacy HWRPs to custom resources
83
83
  #
84
84
  class HWRPWithoutProvides < Base
85
85
  extend AutoCorrector
@@ -94,8 +94,8 @@ module RuboCop
94
94
  $(class
95
95
  (const nil? ... )
96
96
  (const
97
- (const nil? :Chef) :Resource)
98
- (begin ... ))))
97
+ (const {nil? cbase} :Chef) :Resource)
98
+ ...)))
99
99
  PATTERN
100
100
 
101
101
  def_node_search :provides, '(send nil? :provides (sym $_) ...)'
@@ -67,8 +67,8 @@ module RuboCop
67
67
  $(class
68
68
  (const nil? ... )
69
69
  (const
70
- (const nil? :Chef) :Resource)
71
- (begin ... ))))
70
+ (const {nil? cbase} :Chef) :Resource)
71
+ ...)))
72
72
  PATTERN
73
73
 
74
74
  def_node_search :unified_mode?, '(send nil? :unified_mode ...)'
@@ -33,8 +33,8 @@ module RuboCop
33
33
  # # some resource code
34
34
  # end
35
35
  #
36
- # # better
37
- # Write a custom resource using the custom resource DSL and avoid class based HWRPs entirely
36
+ # # better
37
+ # # Write a custom resource using the custom resource DSL and avoid class based HWRPs entirely
38
38
  #
39
39
  class ResourceInheritsFromCompatResource < Base
40
40
  extend AutoCorrector
@@ -42,7 +42,7 @@ module RuboCop
42
42
  MSG = "HWRP style resource should inherit from the 'Chef::Resource' class and not the 'ChefCompat::Resource' class from the deprecated compat_resource cookbook."
43
43
 
44
44
  def_node_matcher :inherits_from_compat_resource?, <<-PATTERN
45
- (class (const nil? _ ) (const (const nil? :ChefCompat) :Resource) ... )
45
+ (class (const nil? _ ) (const (const {nil? cbase} :ChefCompat) :Resource) ... )
46
46
  PATTERN
47
47
 
48
48
  def on_class(node)
@@ -33,12 +33,20 @@ module RuboCop
33
33
  # include_recipe 'yum::repoforge'
34
34
  # include_recipe 'yum::yum'
35
35
  #
36
+ # # good
37
+ # include_recipe 'yum-elrepo'
38
+ # include_recipe 'yum-epel'
39
+ # include_recipe 'yum-ius'
40
+ # include_recipe 'yum-remi'
41
+ # include_recipe 'yum-repoforge'
42
+ # include_recipe 'yum'
43
+ #
36
44
  class LegacyYumCookbookRecipes < Base
37
45
  MSG = 'The elrepo, epel, ius, remi, and repoforge recipes were split into their own cookbooks and the yum recipe was renamed to be default with the release of yum cookbook 3.0 (Dec 2013).'
38
46
  RESTRICT_ON_SEND = [:include_recipe].freeze
39
47
 
40
48
  def_node_matcher :old_yum_recipe?, <<-PATTERN
41
- (send nil? :include_recipe (str {"yum::elrepo" "yum::epel" "yum::ius" "yum::remi" "yum::repoforge" "yum::yum"}))
49
+ (send {nil? (send nil? :run_context)} :include_recipe (str {"yum::elrepo" "yum::epel" "yum::ius" "yum::remi" "yum::repoforge" "yum::yum"}))
42
50
  PATTERN
43
51
 
44
52
  def on_send(node)
@@ -29,6 +29,11 @@ module RuboCop
29
29
  # lc_all 'en_gb.utf-8'
30
30
  # end
31
31
  #
32
+ # # good
33
+ # locale 'set locale' do
34
+ # lang 'en_gb.utf-8'
35
+ # end
36
+ #
32
37
  class LocaleDeprecatedLcAllProperty < Base
33
38
  include RuboCop::Chef::CookbookHelpers
34
39
 
@@ -24,9 +24,17 @@ module RuboCop
24
24
  # @example
25
25
  #
26
26
  # # bad
27
- # mycookbook/resources/myresource.rb:
27
+ # # mycookbook/resources/myresource.rb
28
28
  # resource_name :mycookbook_myresource
29
29
  #
30
+ # # good
31
+ # # mycookbook/resources/myresource.rb
32
+ # provides :mycookbook_myresource
33
+ #
34
+ # # or, to also support Chef Infra Client < 16
35
+ # resource_name :mycookbook_myresource
36
+ # provides :mycookbook_myresource
37
+ #
30
38
  class ResourceUsesOnlyResourceName < Base
31
39
  include RuboCop::Chef::CookbookHelpers
32
40
  include RangeHelp
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # provider_base ::Chef::Provider::SomethingSomething
28
28
  #
29
+ # # good
30
+ # # in the provider, register itself for the resource
31
+ # provides :something_something
32
+ #
29
33
  class ResourceUsesProviderBaseMethod < Base
30
34
  MSG = "Don't use the deprecated provider_base method in a resource to specify the provider module to use. Instead, the provider should call provides to register itself, or the resource should call provider to specify the provider to use. This will cause failures in Chef Infra Client 13 and later."
31
35
  RESTRICT_ON_SEND = [:provider_base].freeze
@@ -31,6 +31,11 @@ module RuboCop
31
31
  # action :create
32
32
  # end
33
33
  #
34
+ # # bad
35
+ # template '/etc/foo.conf' do
36
+ # notifies :create, 'ruby_block[my special ruby block]', :immediately
37
+ # end
38
+ #
34
39
  # # good
35
40
  # ruby_block 'my special ruby block' do
36
41
  # block do
@@ -39,22 +44,56 @@ module RuboCop
39
44
  # action :run
40
45
  # end
41
46
  #
47
+ # # good
48
+ # template '/etc/foo.conf' do
49
+ # notifies :run, 'ruby_block[my special ruby block]', :immediately
50
+ # end
51
+ #
42
52
  class RubyBlockCreateAction < Base
43
53
  include RuboCop::Chef::CookbookHelpers
44
54
  extend AutoCorrector
45
55
 
46
56
  MSG = 'Use the :run action in the ruby_block resource instead of the deprecated :create action'
57
+ RESTRICT_ON_SEND = [:notifies, :subscribes].freeze
58
+
59
+ def_node_matcher :notification?, <<-PATTERN
60
+ (send nil? {:notifies :subscribes} $(sym :create) ${str dstr} ...)
61
+ PATTERN
47
62
 
48
63
  def on_block(node)
49
64
  match_property_in_resource?(:ruby_block, 'action', node) do |ruby_action|
50
- ruby_action.arguments.each do |action|
51
- next unless action.source == ':create'
65
+ each_action_symbol(ruby_action) do |action, prefix|
66
+ next unless action.value == :create
52
67
  add_offense(action, severity: :warning) do |corrector|
53
- corrector.replace(action, ':run')
68
+ corrector.replace(action, "#{prefix}run")
54
69
  end
55
70
  end
56
71
  end
57
72
  end
73
+
74
+ def on_send(node)
75
+ notification?(node) do |action, notified_resource|
76
+ next unless ruby_block?(notified_resource)
77
+
78
+ add_offense(action, severity: :warning) do |corrector|
79
+ corrector.replace(action, ':run')
80
+ end
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ # Does the notified resource string address a ruby_block? An interpolated name
87
+ # ("ruby_block[#{foo}]") still starts with a literal segment we can key off of, but a
88
+ # string whose resource type is itself interpolated tells us nothing, so we skip it.
89
+ #
90
+ # @param [RuboCop::AST::Node] node the str or dstr the notification points at
91
+ #
92
+ # @return [Boolean]
93
+ def ruby_block?(node)
94
+ literal = node.str_type? ? node : node.children.first
95
+ literal&.str_type? && literal.value.start_with?('ruby_block[')
96
+ end
58
97
  end
59
98
  end
60
99
  end
@@ -33,6 +33,15 @@ module RuboCop
33
33
  # end
34
34
  # end
35
35
  #
36
+ # # good
37
+ # module MyCookbook
38
+ # class MyCookbookService < Chef::Resource
39
+ # provides :mycookbook_service
40
+ #
41
+ # # some additional code
42
+ # end
43
+ # end
44
+ #
36
45
  class UseAutomaticResourceName < Base
37
46
  extend RuboCop::Cop::AutoCorrector
38
47
  include RangeHelp
@@ -36,6 +36,11 @@ module RuboCop
36
36
  RESTRICT_ON_SEND = [:to_yaml].freeze
37
37
 
38
38
  def on_send(node)
39
+ # A receiverless to_yaml is a call to a locally defined method rather than
40
+ # the Ruby stdlib conversion this cop is about, and there's nothing to pass
41
+ # to YAML.dump. Bail out rather than dereferencing a nil receiver.
42
+ return unless node.receiver
43
+
39
44
  add_offense(node, severity: :warning) do |corrector|
40
45
  corrector.replace(node, "YAML.dump(#{node.receiver.source})")
41
46
  end
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # include_recipe 'xml::ruby'
28
28
  #
29
+ # # good
30
+ # # nokogiri ships with Chef Infra Client, so just require it
31
+ # require 'nokogiri'
32
+ #
29
33
  class IncludingXMLRubyRecipe < Base
30
34
  extend AutoCorrector
31
35
 
@@ -33,7 +37,7 @@ module RuboCop
33
37
  RESTRICT_ON_SEND = [:include_recipe].freeze
34
38
 
35
39
  def_node_matcher :xml_ruby_recipe?, <<-PATTERN
36
- (send nil? :include_recipe (str "xml::ruby"))
40
+ (send {nil? (send nil? :run_context)} :include_recipe (str "xml::ruby"))
37
41
  PATTERN
38
42
 
39
43
  def on_send(node)
@@ -39,7 +39,7 @@ module RuboCop
39
39
  RESTRICT_ON_SEND = [:include_recipe].freeze
40
40
 
41
41
  def_node_matcher :apt_recipe_usage?, <<-PATTERN
42
- (send nil? :include_recipe (str {"apt" "apt::default"}))
42
+ (send {nil? (send nil? :run_context)} :include_recipe (str {"apt" "apt::default"}))
43
43
  PATTERN
44
44
 
45
45
  def on_send(node)
@@ -27,6 +27,7 @@ module RuboCop
27
27
  # depends 'build-essential'
28
28
  # include_recipe 'build-essential::default'
29
29
  # include_recipe 'build-essential'
30
+ # run_context.include_recipe 'build-essential::default'
30
31
  #
31
32
  # # good
32
33
  # build_essential 'install compilation tools'
@@ -37,8 +38,10 @@ module RuboCop
37
38
  MSG = 'Use the build_essential resource instead of the legacy build-essential recipe. This resource ships in the build-essential cookbook v5.0+ and is built into Chef Infra Client 14+'
38
39
  RESTRICT_ON_SEND = [:include_recipe].freeze
39
40
 
41
+ # matches a bare include_recipe as well as the run_context.include_recipe form used from
42
+ # libraries and custom resources
40
43
  def_node_matcher :build_essential_recipe_usage?, <<-PATTERN
41
- (send nil? :include_recipe (str {"build-essential" "build-essential::default"}))
44
+ (send {nil? (send nil? :run_context)} :include_recipe (str {"build-essential" "build-essential::default"}))
42
45
  PATTERN
43
46
 
44
47
  def on_send(node)
@@ -32,6 +32,14 @@ module RuboCop
32
32
  # depends 'swap'
33
33
  # depends 'sysctl'
34
34
  #
35
+ # # good
36
+ # # the resources ship in Chef Infra Client 14+, so use them without a depends
37
+ # build_essential 'install compilation tools'
38
+ #
39
+ # sysctl 'vm.swappiness' do
40
+ # value 10
41
+ # end
42
+ #
35
43
  class UnnecessaryDependsChef14 < Base
36
44
  extend AutoCorrector
37
45
  extend TargetChefVersion
@@ -29,6 +29,17 @@ module RuboCop
29
29
  # depends 'windows_uac'
30
30
  # depends 'windows_dfs'
31
31
  #
32
+ # # good
33
+ # # the resources ship in Chef Infra Client 15+, so use them without a depends
34
+ # archive_file 'expand website' do
35
+ # path '/tmp/site.zip'
36
+ # destination '/var/www/html'
37
+ # end
38
+ #
39
+ # windows_uac 'set uac' do
40
+ # enable_uac true
41
+ # end
42
+ #
32
43
  class UnnecessaryDependsChef15 < Base
33
44
  extend AutoCorrector
34
45
  extend TargetChefVersion
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # chef_gem 'nokogiri'
28
28
  #
29
+ # # good
30
+ # # nokogiri ships with Chef Infra Client, so just require it
31
+ # require 'nokogiri'
32
+ #
29
33
  class ChefGemNokogiri < Base
30
34
  extend AutoCorrector
31
35
  include RangeHelp
@@ -19,20 +19,27 @@ module RuboCop
19
19
  module Cop
20
20
  module Chef
21
21
  module Modernize
22
- # Use ::File.exist?('/foo/bar') instead of the slower 'test -f /foo/bar' which requires shelling out
22
+ # Use `::File.exist?('/foo/bar')` in an `only_if` or `not_if` guard instead of the slower `'test -f /foo/bar'`, which requires shelling out. The Ruby check has to be passed as a block. Passing it directly, as `not_if ::File.exist?('/foo/bar')`, raises `ArgumentError: Invalid only_if/not_if command, expected a string`.
23
23
  #
24
24
  # @example
25
25
  #
26
26
  # # bad
27
27
  # only_if 'test -f /bin/foo'
28
+ # not_if 'test -f /bin/foo'
29
+ #
30
+ # # bad - a Ruby guard has to be a block, this raises at converge time
31
+ # only_if ::File.exist?('/bin/foo')
28
32
  #
29
33
  # # good
30
34
  # only_if { ::File.exist?('/bin/foo') }
35
+ # not_if { ::File.exist?('/bin/foo') }
31
36
  #
32
37
  class ConditionalUsingTest < Base
33
38
  extend AutoCorrector
34
39
 
35
- MSG = "Use ::File.exist?('/foo/bar') instead of the slower 'test -f /foo/bar' which requires shelling out"
40
+ # %{guard} is the guard the offense was found on, so that a not_if offense isn't told to
41
+ # use an only_if, which would invert the condition
42
+ MSG = "Use %{guard} { ::File.exist?('/foo/bar') } instead of the slower %{guard} 'test -f /foo/bar' which requires shelling out"
36
43
  RESTRICT_ON_SEND = [:not_if, :only_if].freeze
37
44
 
38
45
  def_node_matcher :resource_conditional?, <<~PATTERN
@@ -42,7 +49,7 @@ module RuboCop
42
49
  def on_send(node)
43
50
  resource_conditional?(node) do |conditional|
44
51
  return unless conditional.value.match?(/^test -[ef] \S*$/)
45
- add_offense(node, severity: :refactor) do |corrector|
52
+ add_offense(node, message: format(MSG, guard: node.method_name), severity: :refactor) do |corrector|
46
53
  new_string = "{ ::File.exist?('#{conditional.value.match(/^test -[ef] (\S*)$/)[1]}') }"
47
54
  corrector.replace(conditional, new_string)
48
55
  end
@@ -106,11 +106,13 @@ module RuboCop
106
106
  end
107
107
 
108
108
  match_property_in_resource?(%i(template file cookbook_file), 'path', node) do |code_property|
109
- # instead of using CookbookHelpers#method_arg_ast_to_string, walk the property's descendants
110
- # and check if their value contains '/etc/cron.d'
109
+ # instead of using CookbookHelpers#method_arg_ast_to_string, walk the property's string
110
+ # descendants and check if their value contains '/etc/cron.d'
111
111
  # covers the case where the argument to the path property is provided via a method like File.join
112
- code_property.each_descendant do |d|
113
- add_offense(node, severity: :refactor) if d.respond_to?(:value) && d.value.match?(%r{/etc/cron\.d\b}i)
112
+ # only string nodes are walked: other literals respond to #value too, but return types
113
+ # like Integer that have no #match?, which raised inside the cop (issue #957)
114
+ code_property.each_descendant(:str) do |d|
115
+ add_offense(node, severity: :refactor) if d.value.match?(%r{/etc/cron\.d\b}i)
114
116
  end
115
117
  end
116
118
  end
@@ -40,15 +40,18 @@ module RuboCop
40
40
  def_node_matcher :data_bag_class_load?, <<-PATTERN
41
41
  (send
42
42
  (const
43
- (const nil? :Chef) {:DataBagItem :EncryptedDataBagItem}) :load
43
+ (const {nil? cbase} :Chef) {:DataBagItem :EncryptedDataBagItem}) :load
44
44
  ...)
45
45
  PATTERN
46
46
 
47
47
  def on_send(node)
48
48
  data_bag_class_load?(node) do
49
49
  add_offense(node, severity: :refactor) do |corrector|
50
- corrector.replace(node,
51
- node.source.gsub(/Chef::(EncryptedDataBagItem|DataBagItem).load/, 'data_bag_item'))
50
+ # replace only the receiver and the .load selector, so that the arguments are left
51
+ # exactly as written. rewriting node.source would also hit any argument that
52
+ # happened to contain the class name, and would leave the leading :: of a scope
53
+ # resolved ::Chef::DataBagItem.load behind
54
+ corrector.replace(node.receiver.source_range.join(node.loc.selector), 'data_bag_item')
52
55
  end
53
56
  end
54
57
  end
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'chef-vault'
28
28
  #
29
+ # # good
30
+ # # the chef-vault helpers ship in Chef Infra Client 16+, so use them without a depends
31
+ # chef_vault_item('secrets', 'my_secret')
32
+ #
29
33
  class DependsOnChefVaultCookbook < Base
30
34
  extend AutoCorrector
31
35
  extend TargetChefVersion
@@ -27,6 +27,13 @@ module RuboCop
27
27
  # depends 'chocolatey_source'
28
28
  # depends 'chocolatey_config'
29
29
  #
30
+ # # good
31
+ # # the resources ship in Chef Infra Client 14.3+, so use them without a depends
32
+ # chocolatey_source 'internal' do
33
+ # source 'https://mycorp.example/nuget'
34
+ # action :add
35
+ # end
36
+ #
30
37
  class DependsOnChocolateyCookbooks < Base
31
38
  extend AutoCorrector
32
39
  extend TargetChefVersion
@@ -26,6 +26,12 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'kernel_module'
28
28
  #
29
+ # # good
30
+ # # the resource ships in Chef Infra Client 14.3+, so use it without a depends
31
+ # kernel_module 'loop' do
32
+ # action :install
33
+ # end
34
+ #
29
35
  class DependsOnKernelModuleCookbook < Base
30
36
  extend AutoCorrector
31
37
  extend TargetChefVersion
@@ -26,6 +26,12 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'locale'
28
28
  #
29
+ # # good
30
+ # # the resource ships in Chef Infra Client 14.5+, so use it without a depends
31
+ # locale 'set locale' do
32
+ # lang 'en_us.UTF-8'
33
+ # end
34
+ #
29
35
  class DependsOnLocaleCookbook < Base
30
36
  extend AutoCorrector
31
37
  extend TargetChefVersion
@@ -26,6 +26,15 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'openssl'
28
28
  #
29
+ # # good
30
+ # # the openssl_* resources ship in Chef Infra Client 14.4+, so use them without a depends
31
+ # openssl_x509_certificate '/etc/httpd/ssl/mycert.pem' do
32
+ # common_name 'www.example.com'
33
+ # org 'Example Inc'
34
+ # org_unit 'IT'
35
+ # country 'US'
36
+ # end
37
+ #
29
38
  class DependsOnOpensslCookbook < Base
30
39
  extend AutoCorrector
31
40
  extend TargetChefVersion
@@ -26,6 +26,10 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'timezone_lwrp'
28
28
  #
29
+ # # good
30
+ # # the resource ships in Chef Infra Client 14.6+, so use it without a depends
31
+ # timezone 'UTC'
32
+ #
29
33
  class DependsOnTimezoneLwrpCookbook < Base
30
34
  extend AutoCorrector
31
35
  extend TargetChefVersion
@@ -26,6 +26,14 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'windows_firewall'
28
28
  #
29
+ # # good
30
+ # # the resource ships in Chef Infra Client 14.7+, so use it without a depends
31
+ # windows_firewall_rule 'permit ssh' do
32
+ # local_port '22'
33
+ # protocol 'TCP'
34
+ # firewall_action :allow
35
+ # end
36
+ #
29
37
  class DependsOnWindowsFirewallCookbook < Base
30
38
  extend AutoCorrector
31
39
  extend TargetChefVersion
@@ -26,6 +26,13 @@ module RuboCop
26
26
  # # bad
27
27
  # depends 'zypper'
28
28
  #
29
+ # # good
30
+ # # the resource ships in Chef Infra Client 13.3+, so use it without a depends
31
+ # zypper_repository 'apache' do
32
+ # baseurl 'https://download.opensuse.org/repositories/Apache'
33
+ # action :add
34
+ # end
35
+ #
29
36
  class DependsOnZypperCookbook < Base
30
37
  extend AutoCorrector
31
38
  extend TargetChefVersion
@@ -38,7 +38,7 @@ module RuboCop
38
38
  (send nil? :include
39
39
  (const
40
40
  (const
41
- (const nil? :Chef) :DSL) {:Recipe :IncludeRecipe}))
41
+ (const {nil? cbase} :Chef) :DSL) {:Recipe :IncludeRecipe}))
42
42
  PATTERN
43
43
 
44
44
  def on_send(node)
@@ -53,8 +53,10 @@ module RuboCop
53
53
  (send nil? :execute (str { "apt-get update" "apt-get update -y" "apt-get -y update" }))
54
54
  PATTERN
55
55
 
56
+ # the notification timing is optional and defaults to :delayed, so the trailing
57
+ # argument is matched with ... rather than being required
56
58
  def_node_matcher :notification_property?, <<-PATTERN
57
- (send nil? {:notifies :subscribes} (sym _) $(...) (sym _))
59
+ (send nil? {:notifies :subscribes} (sym _) $(...) ...)
58
60
  PATTERN
59
61
 
60
62
  def_node_matcher :execute_command?, <<-PATTERN