Merge pull request #2755 from GauthamGoli/audit_checksum_rubocop
audit: Port audit_checksum method to rubocop and add tests
This commit is contained in:
		
						commit
						e83e394a73
					
				@ -12,6 +12,9 @@ FormulaAudit/Text:
 | 
			
		||||
FormulaAudit/Caveats:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
FormulaAudit/Checksum:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
FormulaAuditStrict/BottleBlock:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								Library/Homebrew/rubocops/checksum_cop.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								Library/Homebrew/rubocops/checksum_cop.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										78
									
								
								Library/Homebrew/test/rubocops/checksum_cop_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								Library/Homebrew/test/rubocops/checksum_cop_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user