foodcritic 10.0.0 → 10.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/Gemfile +2 -2
- data/features/031_check_for_metadata_existence.feature +2 -2
- data/features/choose_rules_to_apply.feature +27 -27
- data/features/continuous_integration_support.feature +2 -2
- data/features/support/command_helpers.rb +2 -2
- data/lib/foodcritic/api.rb +29 -3
- data/lib/foodcritic/linter.rb +1 -1
- data/lib/foodcritic/rules/fc001.rb +7 -0
- data/lib/foodcritic/rules/fc002.rb +8 -0
- data/lib/foodcritic/rules/fc004.rb +12 -0
- data/lib/foodcritic/rules/fc005.rb +29 -0
- data/lib/foodcritic/rules/fc006.rb +11 -0
- data/lib/foodcritic/rules/fc007.rb +19 -0
- data/lib/foodcritic/rules/fc008.rb +12 -0
- data/lib/foodcritic/rules/fc009.rb +18 -0
- data/lib/foodcritic/rules/fc010.rb +7 -0
- data/lib/foodcritic/rules/fc011.rb +8 -0
- data/lib/foodcritic/rules/fc012.rb +8 -0
- data/lib/foodcritic/rules/fc013.rb +10 -0
- data/lib/foodcritic/rules/fc014.rb +10 -0
- data/lib/foodcritic/rules/fc015.rb +8 -0
- data/lib/foodcritic/rules/fc016.rb +10 -0
- data/lib/foodcritic/rules/fc017.rb +29 -0
- data/lib/foodcritic/rules/fc018.rb +9 -0
- data/lib/foodcritic/rules/fc019.rb +34 -0
- data/lib/foodcritic/rules/fc021.rb +13 -0
- data/lib/foodcritic/rules/fc022.rb +33 -0
- data/lib/foodcritic/rules/fc024.rb +31 -0
- data/lib/foodcritic/rules/fc025.rb +17 -0
- data/lib/foodcritic/rules/fc026.rb +14 -0
- data/lib/foodcritic/rules/fc027.rb +9 -0
- data/lib/foodcritic/rules/fc028.rb +8 -0
- data/lib/foodcritic/rules/fc029.rb +14 -0
- data/lib/foodcritic/rules/fc030.rb +11 -0
- data/lib/foodcritic/rules/fc031.rb +8 -0
- data/lib/foodcritic/rules/fc032.rb +15 -0
- data/lib/foodcritic/rules/fc033.rb +26 -0
- data/lib/foodcritic/rules/fc034.rb +31 -0
- data/lib/foodcritic/rules/fc037.rb +14 -0
- data/lib/foodcritic/rules/fc038.rb +17 -0
- data/lib/foodcritic/rules/fc039.rb +19 -0
- data/lib/foodcritic/rules/fc040.rb +12 -0
- data/lib/foodcritic/rules/fc041.rb +9 -0
- data/lib/foodcritic/rules/fc042.rb +6 -0
- data/lib/foodcritic/rules/fc043.rb +8 -0
- data/lib/foodcritic/rules/fc044.rb +22 -0
- data/lib/foodcritic/rules/fc045.rb +13 -0
- data/lib/foodcritic/rules/fc046.rb +8 -0
- data/lib/foodcritic/rules/fc047.rb +16 -0
- data/lib/foodcritic/rules/fc048.rb +13 -0
- data/lib/foodcritic/rules/fc049.rb +10 -0
- data/lib/foodcritic/rules/fc050.rb +8 -0
- data/lib/foodcritic/rules/fc051.rb +15 -0
- data/lib/foodcritic/rules/fc052.rb +6 -0
- data/lib/foodcritic/rules/fc053.rb +6 -0
- data/lib/foodcritic/rules/fc055.rb +6 -0
- data/lib/foodcritic/rules/fc056.rb +6 -0
- data/lib/foodcritic/rules/fc057.rb +8 -0
- data/lib/foodcritic/rules/fc058.rb +9 -0
- data/lib/foodcritic/rules/fc059.rb +10 -0
- data/lib/foodcritic/rules/fc060.rb +10 -0
- data/lib/foodcritic/rules/fc061.rb +10 -0
- data/lib/foodcritic/rules/fc062.rb +6 -0
- data/lib/foodcritic/rules/fc063.rb +8 -0
- data/lib/foodcritic/rules/fc064.rb +6 -0
- data/lib/foodcritic/rules/fc065.rb +6 -0
- data/lib/foodcritic/version.rb +1 -1
- data/spec/foodcritic/api_spec.rb +62 -0
- data/spec/foodcritic/coverage/assets/0.10.0/application.css +799 -0
- data/spec/foodcritic/coverage/assets/0.10.0/application.js +1707 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/loading.gif +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/magnify.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/foodcritic/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/foodcritic/coverage/index.html +72 -0
- data/spec/foodcritic/linter_spec.rb +7 -6
- data/spec/regression/expected-output.txt +0 -12
- data/spec/spec_helper.rb +3 -1
- metadata +88 -6
- data/features/023_check_for_condition_around_resource.feature +0 -52
- 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,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,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,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
|