foodcritic 10.0.0 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/Gemfile +2 -2
  4. data/features/031_check_for_metadata_existence.feature +2 -2
  5. data/features/choose_rules_to_apply.feature +27 -27
  6. data/features/continuous_integration_support.feature +2 -2
  7. data/features/support/command_helpers.rb +2 -2
  8. data/lib/foodcritic/api.rb +29 -3
  9. data/lib/foodcritic/linter.rb +1 -1
  10. data/lib/foodcritic/rules/fc001.rb +7 -0
  11. data/lib/foodcritic/rules/fc002.rb +8 -0
  12. data/lib/foodcritic/rules/fc004.rb +12 -0
  13. data/lib/foodcritic/rules/fc005.rb +29 -0
  14. data/lib/foodcritic/rules/fc006.rb +11 -0
  15. data/lib/foodcritic/rules/fc007.rb +19 -0
  16. data/lib/foodcritic/rules/fc008.rb +12 -0
  17. data/lib/foodcritic/rules/fc009.rb +18 -0
  18. data/lib/foodcritic/rules/fc010.rb +7 -0
  19. data/lib/foodcritic/rules/fc011.rb +8 -0
  20. data/lib/foodcritic/rules/fc012.rb +8 -0
  21. data/lib/foodcritic/rules/fc013.rb +10 -0
  22. data/lib/foodcritic/rules/fc014.rb +10 -0
  23. data/lib/foodcritic/rules/fc015.rb +8 -0
  24. data/lib/foodcritic/rules/fc016.rb +10 -0
  25. data/lib/foodcritic/rules/fc017.rb +29 -0
  26. data/lib/foodcritic/rules/fc018.rb +9 -0
  27. data/lib/foodcritic/rules/fc019.rb +34 -0
  28. data/lib/foodcritic/rules/fc021.rb +13 -0
  29. data/lib/foodcritic/rules/fc022.rb +33 -0
  30. data/lib/foodcritic/rules/fc024.rb +31 -0
  31. data/lib/foodcritic/rules/fc025.rb +17 -0
  32. data/lib/foodcritic/rules/fc026.rb +14 -0
  33. data/lib/foodcritic/rules/fc027.rb +9 -0
  34. data/lib/foodcritic/rules/fc028.rb +8 -0
  35. data/lib/foodcritic/rules/fc029.rb +14 -0
  36. data/lib/foodcritic/rules/fc030.rb +11 -0
  37. data/lib/foodcritic/rules/fc031.rb +8 -0
  38. data/lib/foodcritic/rules/fc032.rb +15 -0
  39. data/lib/foodcritic/rules/fc033.rb +26 -0
  40. data/lib/foodcritic/rules/fc034.rb +31 -0
  41. data/lib/foodcritic/rules/fc037.rb +14 -0
  42. data/lib/foodcritic/rules/fc038.rb +17 -0
  43. data/lib/foodcritic/rules/fc039.rb +19 -0
  44. data/lib/foodcritic/rules/fc040.rb +12 -0
  45. data/lib/foodcritic/rules/fc041.rb +9 -0
  46. data/lib/foodcritic/rules/fc042.rb +6 -0
  47. data/lib/foodcritic/rules/fc043.rb +8 -0
  48. data/lib/foodcritic/rules/fc044.rb +22 -0
  49. data/lib/foodcritic/rules/fc045.rb +13 -0
  50. data/lib/foodcritic/rules/fc046.rb +8 -0
  51. data/lib/foodcritic/rules/fc047.rb +16 -0
  52. data/lib/foodcritic/rules/fc048.rb +13 -0
  53. data/lib/foodcritic/rules/fc049.rb +10 -0
  54. data/lib/foodcritic/rules/fc050.rb +8 -0
  55. data/lib/foodcritic/rules/fc051.rb +15 -0
  56. data/lib/foodcritic/rules/fc052.rb +6 -0
  57. data/lib/foodcritic/rules/fc053.rb +6 -0
  58. data/lib/foodcritic/rules/fc055.rb +6 -0
  59. data/lib/foodcritic/rules/fc056.rb +6 -0
  60. data/lib/foodcritic/rules/fc057.rb +8 -0
  61. data/lib/foodcritic/rules/fc058.rb +9 -0
  62. data/lib/foodcritic/rules/fc059.rb +10 -0
  63. data/lib/foodcritic/rules/fc060.rb +10 -0
  64. data/lib/foodcritic/rules/fc061.rb +10 -0
  65. data/lib/foodcritic/rules/fc062.rb +6 -0
  66. data/lib/foodcritic/rules/fc063.rb +8 -0
  67. data/lib/foodcritic/rules/fc064.rb +6 -0
  68. data/lib/foodcritic/rules/fc065.rb +6 -0
  69. data/lib/foodcritic/version.rb +1 -1
  70. data/spec/foodcritic/api_spec.rb +62 -0
  71. data/spec/foodcritic/coverage/assets/0.10.0/application.css +799 -0
  72. data/spec/foodcritic/coverage/assets/0.10.0/application.js +1707 -0
  73. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/border.png +0 -0
  74. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  75. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  76. data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  77. data/spec/foodcritic/coverage/assets/0.10.0/favicon_green.png +0 -0
  78. data/spec/foodcritic/coverage/assets/0.10.0/favicon_red.png +0 -0
  79. data/spec/foodcritic/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  80. data/spec/foodcritic/coverage/assets/0.10.0/loading.gif +0 -0
  81. data/spec/foodcritic/coverage/assets/0.10.0/magnify.png +0 -0
  82. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  83. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  84. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  85. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  86. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  87. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  88. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  89. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  90. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  91. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  92. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  93. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  94. data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  95. data/spec/foodcritic/coverage/index.html +72 -0
  96. data/spec/foodcritic/linter_spec.rb +7 -6
  97. data/spec/regression/expected-output.txt +0 -12
  98. data/spec/spec_helper.rb +3 -1
  99. metadata +88 -6
  100. data/features/023_check_for_condition_around_resource.feature +0 -52
  101. data/lib/foodcritic/rules.rb +0 -852
@@ -0,0 +1,9 @@
1
+ rule "FC018", "LWRP uses deprecated notification syntax" do
2
+ tags %w{correctness lwrp deprecated}
3
+ provider do |ast|
4
+ ast.xpath("//assign/var_field/ivar[@value='@updated']").map do |class_var|
5
+ match(class_var)
6
+ end + ast.xpath(%q{//assign/field/*[self::vcall or self::var_ref/ident/
7
+ @value='new_resource']/../ident[@value='updated']})
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ rule "FC019", "Access node attributes in a consistent manner" do
2
+ tags %w{style attributes}
3
+ cookbook do |cookbook_dir|
4
+ asts = {}; files = Dir["#{cookbook_dir}/*/*.rb"].reject do |file|
5
+ relative_path = Pathname.new(file).relative_path_from(
6
+ Pathname.new(cookbook_dir))
7
+ relative_path.to_s.split(File::SEPARATOR).include?("spec")
8
+ end.map do |file|
9
+ { path: file, ast: read_ast(file) }
10
+ end
11
+ types = [:string, :symbol, :vivified].map do |type|
12
+ {
13
+ access_type: type, count: files.map do |file|
14
+ attribute_access(file[:ast], type: type, ignore_calls: true,
15
+ cookbook_dir: cookbook_dir, ignore: "run_state").tap do |ast|
16
+ unless ast.empty?
17
+ (asts[type] ||= []) << { ast: ast, path: file[:path] }
18
+ end
19
+ end.size
20
+ end.inject(:+)
21
+ }
22
+ end.reject { |type| type[:count] == 0 }
23
+ if asts.size > 1
24
+ least_used = asts[types.min do |a, b|
25
+ a[:count] <=> b[:count]
26
+ end[:access_type]]
27
+ least_used.map do |file|
28
+ file[:ast].map do |ast|
29
+ match(ast).merge(filename: file[:path])
30
+ end.flatten
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ rule "FC021", "Resource condition in provider may not behave as expected" do
2
+ tags %w{correctness lwrp}
3
+ provider do |ast|
4
+ find_resources(ast).map do |resource|
5
+ condition = resource.xpath(%q{//method_add_block/
6
+ descendant::ident[@value='not_if' or @value='only_if']/
7
+ ancestor::*[self::method_add_block or self::command][1][descendant::
8
+ ident/@value='new_resource']/ancestor::stmts_add[2]/method_add_block/
9
+ command[count(descendant::string_embexpr) = 0]})
10
+ condition
11
+ end.compact
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ rule "FC022", "Resource condition within loop may not behave as expected" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ ast.xpath("//call[ident/@value='each']/../do_block[count(ancestor::
5
+ method_add_block/method_add_arg/fcall/ident[@value='only_if' or
6
+ @value = 'not_if']) = 0]").map do |lp|
7
+ block_vars = lp.xpath("block_var/params/child::*").map do |n|
8
+ n.name.sub(/^ident/, "")
9
+ end + lp.xpath("block_var/params/child::*/descendant::ident").map do |v|
10
+ v["value"]
11
+ end
12
+ find_resources(lp).map do |resource|
13
+ # if any of the parameters to the block are used in a condition then we
14
+ # have a match
15
+ unless (block_vars &
16
+ (resource.xpath(%q{descendant::ident[@value='not_if' or
17
+ @value='only_if']/ancestor::*[self::method_add_block or
18
+ self::command][1]/descendant::ident/@value}).map do |a|
19
+ a.value
20
+ end)).empty?
21
+ c = resource.xpath("command[count(descendant::string_embexpr) = 0]")
22
+ if resource.xpath("command/ident/@value").first.value == "define"
23
+ next
24
+ end
25
+ resource unless c.empty? || block_vars.any? do |var|
26
+ !resource.xpath(%Q{command/args_add_block/args_add/
27
+ var_ref/ident[@value='#{var}']}).empty?
28
+ end
29
+ end
30
+ end
31
+ end.flatten.compact
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ rule "FC024", "Consider adding platform equivalents" do
2
+ tags %w{portability}
3
+ RHEL = %w{amazon centos redhat scientific oracle}
4
+ recipe do |ast, filename|
5
+ next if Pathname.new(filename).basename.to_s == "metadata.rb"
6
+ metadata_path = Pathname.new(
7
+ File.join(File.dirname(filename), "..", "metadata.rb")).cleanpath
8
+ md_platforms = if File.exist?(metadata_path)
9
+ supported_platforms(read_ast(
10
+ metadata_path)).map { |p| p[:platform] }
11
+ else
12
+ []
13
+ end
14
+ md_platforms = RHEL if md_platforms.empty?
15
+
16
+ ['//method_add_arg[fcall/ident/@value="platform?"]/
17
+ arg_paren/args_add_block',
18
+ "//when"].map do |expr|
19
+ ast.xpath(expr).map do |whn|
20
+ platforms = whn.xpath('args_add/
21
+ descendant::tstring_content').map do |p|
22
+ p["value"]
23
+ end.sort
24
+ unless platforms.size == 1 || (md_platforms & platforms).empty?
25
+ whn unless (platforms & RHEL).empty? ||
26
+ ((md_platforms & RHEL) - (platforms & RHEL)).empty?
27
+ end
28
+ end.compact
29
+ end.flatten
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ rule "FC025", "Prefer chef_gem to compile-time gem install" do
2
+ tags %w{correctness deprecated}
3
+ recipe do |ast|
4
+ gem_install = ast.xpath("//stmts_add/assign[method_add_block[command/ident/
5
+ @value='gem_package'][do_block/stmts_add/command[ident/@value='action']
6
+ [descendant::ident/@value='nothing']]]")
7
+ gem_install.map do |install|
8
+ gem_var = install.xpath("var_field/ident/@value")
9
+ unless ast.xpath("//method_add_arg[call/
10
+ var_ref/ident/@value='#{gem_var}']
11
+ [arg_paren/descendant::ident/@value='install' or
12
+ arg_paren/descendant::ident/@value='upgrade']").empty?
13
+ gem_install
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ rule "FC026", "Conditional execution block attribute contains only string" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ find_resources(ast).map { |r| resource_attributes(r) }.map do |resource|
5
+ [resource["not_if"], resource["only_if"]]
6
+ end.flatten.compact.select do |condition|
7
+ condition.respond_to?(:xpath) &&
8
+ !condition.xpath("descendant::string_literal").empty? &&
9
+ !condition.xpath("stmts_add/string_literal").empty? &&
10
+ condition.xpath('descendant::stmts_add[count(ancestor::
11
+ string_literal) = 0]').size == 1
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ rule "FC027", "Resource sets internal attribute" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ find_resources(ast, type: :service).map do |service|
5
+ service unless (resource_attributes(service).keys &
6
+ %w{enabled running}).empty?
7
+ end.compact
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC028", "Incorrect #platform? usage" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ ast.xpath(%q{//*[self::call | self::command_call]
5
+ [(var_ref|vcall)/ident/@value='node']
6
+ [ident/@value="platform?"]})
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ rule "FC029", "No leading cookbook name in recipe metadata" do
2
+ tags %w{correctness metadata}
3
+ metadata do |ast, filename|
4
+ ast.xpath('//command[ident/@value="recipe"]').map do |declared_recipe|
5
+ next unless declared_recipe.xpath("count(//vcall|//var_ref)").to_i == 0
6
+ recipe_name = declared_recipe.xpath('args_add_block/
7
+ descendant::tstring_content[1]/@value').to_s
8
+ unless recipe_name.empty? ||
9
+ recipe_name.split("::").first == cookbook_name(filename.to_s)
10
+ declared_recipe
11
+ end
12
+ end.compact
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ rule "FC030", "Cookbook contains debugger breakpoints" do
2
+ tags %w{correctness}
3
+ def pry_bindings(ast)
4
+ ast.xpath('//call[(vcall|var_ref)/ident/@value="binding"]
5
+ [ident/@value="pry"]')
6
+ end
7
+ recipe { |ast| pry_bindings(ast) }
8
+ library { |ast| pry_bindings(ast) }
9
+ metadata { |ast| pry_bindings(ast) }
10
+ template { |ast| pry_bindings(ast) }
11
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC031", "Cookbook without metadata.rb file" do
2
+ tags %w{correctness metadata}
3
+ cookbook do |filename|
4
+ if !File.exist?(File.join(filename, "metadata.rb"))
5
+ [file_match(File.join(filename, "metadata.rb"))]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ rule "FC032", "Invalid notification timing" do
2
+ tags %w{correctness notifications}
3
+ recipe do |ast|
4
+ valid_timings = if resource_attribute?("file", "notifies_before")
5
+ [:delayed, :immediate, :before]
6
+ else
7
+ [:delayed, :immediate]
8
+ end
9
+ find_resources(ast).select do |resource|
10
+ notifications(resource).any? do |notification|
11
+ ! valid_timings.include? notification[:timing]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ rule "FC033", "Missing template" do
2
+ tags %w{correctness templates}
3
+ recipe do |ast, filename|
4
+ find_resources(ast, type: :template).reject do |resource|
5
+ resource_attributes(resource)["local"] ||
6
+ resource_attributes(resource)["cookbook"]
7
+ end.map do |resource|
8
+ file = template_file(resource_attributes(resource,
9
+ return_expressions: true))
10
+ { resource: resource, file: file }
11
+ end.reject do |resource|
12
+ resource[:file].respond_to?(:xpath)
13
+ end.select do |resource|
14
+ template_paths(filename).none? do |path|
15
+ relative_path = []
16
+ Pathname.new(path).ascend do |template_path|
17
+ relative_path << template_path.basename
18
+ break if gem_version(chef_version) >= gem_version("12.0.0") &&
19
+ template_path.dirname.basename.to_s == "templates"
20
+ break if template_path.dirname.dirname.basename.to_s == "templates"
21
+ end
22
+ File.join(relative_path.reverse) == resource[:file]
23
+ end
24
+ end.map { |resource| resource[:resource] }
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ rule "FC034", "Unused template variables" do
2
+ tags %w{correctness templates}
3
+ recipe do |ast, filename|
4
+ Array(resource_attributes_by_type(ast)["template"]).select do |t|
5
+ t["variables"] && t["variables"].respond_to?(:xpath)
6
+ end.map do |resource|
7
+ all_templates = template_paths(filename)
8
+ template_paths = all_templates.select do |path|
9
+ File.basename(path) == template_file(resource)
10
+ end
11
+ next unless template_paths.any?
12
+ passed_vars = resource["variables"].xpath(
13
+ "symbol/ident/@value").map { |tv| tv.to_s }
14
+
15
+ unused_vars_exist = template_paths.all? do |template_path|
16
+ begin
17
+ template_vars = templates_included(
18
+ all_templates, template_path).map do |template|
19
+ read_ast(template).xpath("//var_ref/ivar/@value").map do |v|
20
+ v.to_s.sub(/^@/, "")
21
+ end
22
+ end.flatten
23
+ ! (passed_vars - template_vars).empty?
24
+ rescue RecursedTooFarError
25
+ false
26
+ end
27
+ end
28
+ file_match(template_paths.first) if unused_vars_exist
29
+ end.compact
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ rule "FC037", "Invalid notification action" do
2
+ tags %w{correctness notifications}
3
+ recipe do |ast|
4
+ find_resources(ast).select do |resource|
5
+ notifications(resource).any? do |n|
6
+ type = case n[:type]
7
+ when :notifies then n[:resource_type]
8
+ when :subscribes then resource_type(resource).to_sym
9
+ end
10
+ n[:action].size > 0 && !resource_action?(type, n[:action])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ rule "FC038", "Invalid resource action" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ find_resources(ast).select do |resource|
5
+ actions = resource_attributes(resource)["action"]
6
+ if actions.respond_to?(:xpath)
7
+ actions = actions.xpath('descendant::array/
8
+ descendant::symbol/ident/@value')
9
+ else
10
+ actions = Array(actions)
11
+ end
12
+ actions.reject { |a| a.to_s.empty? }.any? do |action|
13
+ !resource_action?(resource_type(resource), action)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ rule "FC039", "Node method cannot be accessed with key" do
2
+ tags %w{correctness}
3
+ recipe do |ast|
4
+ [{ type: :string, path: "@value" },
5
+ { type: :symbol, path: "ident/@value" }].map do |access_type|
6
+ attribute_access(ast, type: access_type[:type]).select do |att|
7
+ att_name = att.xpath(access_type[:path]).to_s.to_sym
8
+ att_name != :tags && chef_node_methods.include?(att_name)
9
+ end.select do |att|
10
+ !att.xpath('ancestor::args_add_block[position() = 1]
11
+ [preceding-sibling::vcall | preceding-sibling::var_ref]').empty?
12
+ end.select do |att|
13
+ att_type = att.xpath('ancestor::args_add_block[position() = 1]
14
+ /../var_ref/ident/@value').to_s
15
+ ast.xpath("//assign/var_field/ident[@value='#{att_type}']").empty?
16
+ end
17
+ end.flatten
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ rule "FC040", "Execute resource used to run git commands" do
2
+ tags %w{style}
3
+ recipe do |ast|
4
+ possible_git_commands = %w{ clone fetch pull checkout reset }
5
+ find_resources(ast, type: "execute").select do |cmd|
6
+ cmd_str = (resource_attribute(cmd, "command") || resource_name(cmd)).to_s
7
+
8
+ actual_git_commands = cmd_str.scan(/git ([a-z]+)/).map { |c| c.first }
9
+ (possible_git_commands & actual_git_commands).any?
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ rule "FC041", "Execute resource used to run curl or wget commands" do
2
+ tags %w{style portability}
3
+ recipe do |ast|
4
+ find_resources(ast, type: "execute").select do |cmd|
5
+ cmd_str = (resource_attribute(cmd, "command") || resource_name(cmd)).to_s
6
+ (cmd_str.match(/^curl.*(-o|>|--output).*$/) || cmd_str.include?("wget "))
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ rule "FC042", "Prefer include_recipe to require_recipe" do
2
+ tags %w{correctness deprecated}
3
+ recipe do |ast|
4
+ ast.xpath('//command[ident/@value="require_recipe"]')
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC043", "Prefer new notification syntax" do
2
+ tags %w{correctness notifications deprecated}
3
+ recipe do |ast|
4
+ find_resources(ast).select do |resource|
5
+ notifications(resource).any? { |notify| notify[:style] == :old }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ rule "FC044", "Avoid bare attribute keys" do
2
+ tags %w{style}
3
+ attributes do |ast|
4
+ declared = ast.xpath("//descendant::var_field/ident/@value").map do |v|
5
+ v.to_s
6
+ end
7
+
8
+ ast.xpath('//assign/*[self::vcall or self::var_ref]
9
+ [count(child::kw) = 0]/ident').select do |v|
10
+
11
+ local_declared = v.xpath("ancestor::*[self::brace_block or self::do_block]
12
+ /block_var/descendant::ident/@value").map do |v|
13
+ v.to_s
14
+ end
15
+
16
+ (v["value"] != "secure_password") &&
17
+ !(declared + local_declared).uniq.include?(v["value"]) &&
18
+ !v.xpath("ancestor::*[self::brace_block or self::do_block]/block_var/
19
+ descendant::ident/@value='#{v['value']}'")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ rule "FC045", "Metadata does not contain cookbook name" do
2
+ tags %w{correctness metadata chef12}
3
+ metadata do |ast, filename|
4
+ unless ast.xpath('descendant::stmts_add/command/ident/@value="name"')
5
+ [file_match(filename)]
6
+ end
7
+ end
8
+ cookbook do |filename|
9
+ if !File.exist?(File.join(filename, "metadata.rb"))
10
+ [file_match(File.join(filename, "metadata.rb"))]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ rule "FC046", "Attribute assignment uses assign unless nil" do
2
+ tags %w{attributes correctness}
3
+ attributes do |ast|
4
+ attribute_access(ast).map do |a|
5
+ a.xpath('ancestor::opassign/op[@value="||="]')
6
+ end
7
+ end
8
+ end