diff options
| author | Mike McQuaid | 2017-06-09 09:46:05 +0300 |
|---|---|---|
| committer | GitHub | 2017-06-09 09:46:05 +0300 |
| commit | e83e394a731f3317dc09a5eb1210ff6996e40ed2 (patch) | |
| tree | 73a9cc10ded84946bad2773b9fc848ec607b3315 | |
| parent | 0e2b043c125538dab0cee416bff908034ad37e84 (diff) | |
| parent | d09d5ecc559c4971fae77769cb1a203bb20c7a97 (diff) | |
| download | brew-e83e394a731f3317dc09a5eb1210ff6996e40ed2.tar.bz2 | |
Merge pull request #2755 from GauthamGoli/audit_checksum_rubocop
audit: Port audit_checksum method to rubocop and add tests
| -rw-r--r-- | Library/.rubocop.yml | 3 | ||||
| -rw-r--r-- | Library/Homebrew/dev-cmd/audit.rb | 23 | ||||
| -rw-r--r-- | Library/Homebrew/rubocops.rb | 1 | ||||
| -rw-r--r-- | Library/Homebrew/rubocops/checksum_cop.rb | 55 | ||||
| -rw-r--r-- | Library/Homebrew/rubocops/extend/formula_cop.rb | 11 | ||||
| -rw-r--r-- | Library/Homebrew/test/rubocops/checksum_cop_spec.rb | 78 |
6 files changed, 145 insertions, 26 deletions
diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 8099c7ad0..0e3f49fdf 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -12,6 +12,9 @@ FormulaAudit/Text: FormulaAudit/Caveats: Enabled: true +FormulaAudit/Checksum: + Enabled: true + FormulaAuditStrict/BottleBlock: Enabled: true diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index e069fef36..105bc0e86 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -1246,7 +1246,6 @@ class ResourceAuditor def audit audit_version - audit_checksum audit_download_strategy audit_urls self @@ -1273,28 +1272,6 @@ class ResourceAuditor problem "version #{version} should not end with an underline and a number" end - def audit_checksum - return unless checksum - - case checksum.hash_type - when :md5 - problem "MD5 checksums are deprecated, please use SHA256" - return - when :sha1 - problem "SHA1 checksums are deprecated, please use SHA256" - return - when :sha256 then len = 64 - end - - if checksum.empty? - problem "#{checksum.hash_type} is empty" - else - problem "#{checksum.hash_type} should be #{len} characters" unless checksum.hexdigest.length == len - problem "#{checksum.hash_type} contains invalid characters" unless checksum.hexdigest =~ /^[a-fA-F0-9]+$/ - problem "#{checksum.hash_type} should be lowercase" unless checksum.hexdigest == checksum.hexdigest.downcase - end - end - def audit_download_strategy if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://} problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{$1}` instead" diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb index c4a38cdb7..4710654fa 100644 --- a/Library/Homebrew/rubocops.rb +++ b/Library/Homebrew/rubocops.rb @@ -5,3 +5,4 @@ require_relative "./rubocops/components_redundancy_cop" require_relative "./rubocops/homepage_cop" require_relative "./rubocops/text_cop" require_relative "./rubocops/caveats_cop" +require_relative "./rubocops/checksum_cop" diff --git a/Library/Homebrew/rubocops/checksum_cop.rb b/Library/Homebrew/rubocops/checksum_cop.rb new file mode 100644 index 000000000..98e6a8bd3 --- /dev/null +++ b/Library/Homebrew/rubocops/checksum_cop.rb @@ -0,0 +1,55 @@ +require_relative "./extend/formula_cop" + +module RuboCop + module Cop + module FormulaAudit + class Checksum < FormulaCop + def audit_formula(_node, _class_node, _parent_class_node, body_node) + %w[Stable Devel HEAD].each do |name| + next unless spec_node = find_block(body_node, name.downcase.to_sym) + _, _, spec_body = *spec_node + audit_checksums(spec_body, name) + resource_blocks = find_all_blocks(spec_body, :resource) + resource_blocks.each do |rb| + _, _, resource_body = *rb + audit_checksums(resource_body, name, string_content(parameters(rb).first)) + end + end + end + + def audit_checksums(node, spec, resource_name = nil) + msg_prefix = if resource_name + "#{spec} resource \"#{resource_name}\": " + else + "#{spec}: " + end + if find_node_method_by_name(node, :md5) + problem "#{msg_prefix}MD5 checksums are deprecated, please use SHA256" + end + + if find_node_method_by_name(node, :sha1) + problem "#{msg_prefix}SHA1 checksums are deprecated, please use SHA256" + end + + checksum_node = find_node_method_by_name(node, :sha256) + checksum = parameters(checksum_node).first + if string_content(checksum).size.zero? + problem "#{msg_prefix}sha256 is empty" + return + end + + if string_content(checksum).size != 64 && regex_match_group(checksum, /^\w*$/) + problem "#{msg_prefix}sha256 should be 64 characters" + end + + unless regex_match_group(checksum, /^[a-f0-9]+$/i) + problem "#{msg_prefix}sha256 contains invalid characters" + end + + return unless regex_match_group(checksum, /^[a-f0-9]+$/) + problem "#{msg_prefix}sha256 should be lowercase" + end + end + end + end +end diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index 75a3e72d5..b6fa45d3f 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -167,12 +167,18 @@ module RuboCop nil end - # Returns an array of block nodes named block_name inside node + # Returns an array of block nodes of depth first order named block_name below node def find_blocks(node, block_name) return if node.nil? node.each_child_node(:block).select { |block_node| block_name == block_node.method_name } end + # Returns an array of block nodes of any depth below node in AST + def find_all_blocks(node, block_name) + return if node.nil? + node.each_descendant(:block).select { |block_node| block_name == block_node.method_name } + end + # Returns a method definition node with method_name def find_method_def(node, method_name) return if node.nil? @@ -250,8 +256,7 @@ module RuboCop # Returns the array of arguments of the method_node def parameters(method_node) - return unless method_node.send_type? - method_node.method_args + method_node.method_args if method_node.send_type? || method_node.block_type? end # Returns true if the given parameters are present in method call diff --git a/Library/Homebrew/test/rubocops/checksum_cop_spec.rb b/Library/Homebrew/test/rubocops/checksum_cop_spec.rb new file mode 100644 index 000000000..fb21771ff --- /dev/null +++ b/Library/Homebrew/test/rubocops/checksum_cop_spec.rb @@ -0,0 +1,78 @@ +require "rubocop" +require "rubocop/rspec/support" +require_relative "../../extend/string" +require_relative "../../rubocops/checksum_cop" + +describe RuboCop::Cop::FormulaAudit::Checksum do + subject(:cop) { described_class.new } + + context "When auditing spec checksums" do + it "When the checksum is empty" do + source = <<-EOS.undent + class Foo < Formula + url 'http://example.com/foo-1.0.tgz' + stable do + url "https://github.com/foo-lang/foo-compiler/archive/0.18.0.tar.gz" + sha256 "" + + resource "foo-package" do + url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz" + sha256 "" + end + end + end + EOS + + expected_offenses = [{ message: "Stable: sha256 is empty", + severity: :convention, + line: 5, + column: 4, + source: source }, + { message: "Stable resource \"foo-package\": sha256 is empty", + severity: :convention, + line: 9, + column: 6, + source: source }] + + inspect_source(cop, source) + + expected_offenses.zip(cop.offenses).each do |expected, actual| + expect_offense(expected, actual) + end + end + + it "When the checksum is not 64 characters" do + source = <<-EOS.undent + class Foo < Formula + url 'http://example.com/foo-1.0.tgz' + stable do + url "https://github.com/foo-lang/foo-compiler/archive/0.18.0.tar.gz" + sha256 "5cf6e1ae0a645b426c0474cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9ad" + + resource "foo-package" do + url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz" + sha256 "5cf6e1ae0a645b426c047aaa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9" + end + end + end + EOS + + expected_offenses = [{ message: "Stable: sha256 should be 64 characters", + severity: :convention, + line: 5, + column: 12, + source: source }, + { message: "Stable resource \"foo-package\": sha256 should be 64 characters", + severity: :convention, + line: 9, + column: 14, + source: source }] + + inspect_source(cop, source) + + expected_offenses.zip(cop.offenses).each do |expected, actual| + expect_offense(expected, actual) + end + end + end +end |
