Merge pull request #2776 from GauthamGoli/audit_checksum_rubocop_fix
audit: Fix audit_checksum method's rubocop and add more tests
This commit is contained in:
commit
80ce43dff1
@ -12,6 +12,12 @@ FormulaAudit/Text:
|
||||
FormulaAudit/Caveats:
|
||||
Enabled: true
|
||||
|
||||
FormulaAudit/Checksum:
|
||||
Enabled: true
|
||||
|
||||
FormulaAudit/ChecksumCase:
|
||||
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 => :#{Regexp.last_match(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"
|
||||
|
||||
64
Library/Homebrew/rubocops/checksum_cop.rb
Normal file
64
Library/Homebrew/rubocops/checksum_cop.rb
Normal file
@ -0,0 +1,64 @@
|
||||
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)
|
||||
return if body_node.nil?
|
||||
if method_called_ever?(body_node, :md5)
|
||||
problem "MD5 checksums are deprecated, please use SHA256"
|
||||
end
|
||||
|
||||
if method_called_ever?(body_node, :sha1)
|
||||
problem "SHA1 checksums are deprecated, please use SHA256"
|
||||
end
|
||||
|
||||
sha256_calls = find_every_method_call_by_name(body_node, :sha256)
|
||||
sha256_calls.each do |sha256_call|
|
||||
sha256_node = get_checksum_node(sha256_call)
|
||||
audit_sha256(sha256_node)
|
||||
end
|
||||
end
|
||||
|
||||
def audit_sha256(checksum)
|
||||
return if checksum.nil?
|
||||
if regex_match_group(checksum, /^$/)
|
||||
problem "sha256 is empty"
|
||||
return
|
||||
end
|
||||
|
||||
if string_content(checksum).size != 64 && regex_match_group(checksum, /^\w*$/)
|
||||
problem "sha256 should be 64 characters"
|
||||
end
|
||||
|
||||
return unless regex_match_group(checksum, /[^a-f0-9]+/i)
|
||||
problem "sha256 contains invalid characters"
|
||||
end
|
||||
end
|
||||
|
||||
class ChecksumCase < FormulaCop
|
||||
def audit_formula(_node, _class_node, _parent_class_node, body_node)
|
||||
return if body_node.nil?
|
||||
sha256_calls = find_every_method_call_by_name(body_node, :sha256)
|
||||
sha256_calls.each do |sha256_call|
|
||||
checksum = get_checksum_node(sha256_call)
|
||||
next if checksum.nil?
|
||||
next unless regex_match_group(checksum, /[A-F]+/)
|
||||
problem "sha256 should be lowercase"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def autocorrect(node)
|
||||
lambda do |corrector|
|
||||
correction = node.source.downcase
|
||||
corrector.insert_before(node.source_range, correction)
|
||||
corrector.remove(node.source_range)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -173,6 +173,12 @@ module RuboCop
|
||||
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
|
||||
@ -272,6 +277,17 @@ module RuboCop
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the sha256 str node given a sha256 call node
|
||||
def get_checksum_node(call)
|
||||
return if parameters(call).empty? || parameters(call).nil?
|
||||
if parameters(call).first.str_type?
|
||||
parameters(call).first
|
||||
# sha256 is passed as a key-value pair in bottle blocks
|
||||
elsif parameters(call).first.hash_type?
|
||||
parameters(call).first.keys.first
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the begin position of the node's line in source code
|
||||
def line_start_column(node)
|
||||
node.source_range.source_buffer.line_range(node.loc.line).begin_pos
|
||||
|
||||
222
Library/Homebrew/test/rubocops/checksum_cop_spec.rb
Normal file
222
Library/Homebrew/test/rubocops/checksum_cop_spec.rb
Normal file
@ -0,0 +1,222 @@
|
||||
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: "sha256 is empty",
|
||||
severity: :convention,
|
||||
line: 5,
|
||||
column: 12,
|
||||
source: source },
|
||||
{ message: "sha256 is empty",
|
||||
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
|
||||
|
||||
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: "sha256 should be 64 characters",
|
||||
severity: :convention,
|
||||
line: 5,
|
||||
column: 12,
|
||||
source: source },
|
||||
{ message: "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
|
||||
|
||||
it "When the checksum has invalid chars" 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 "5cf6e1ae0a645b426c0k7cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9a"
|
||||
|
||||
resource "foo-package" do
|
||||
url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1ae0a645b426x047aa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea9"
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
|
||||
expected_offenses = [{ message: "sha256 contains invalid characters",
|
||||
severity: :convention,
|
||||
line: 5,
|
||||
column: 31,
|
||||
source: source },
|
||||
{ message: "sha256 contains invalid characters",
|
||||
severity: :convention,
|
||||
line: 9,
|
||||
column: 31,
|
||||
source: source }]
|
||||
|
||||
inspect_source(cop, source)
|
||||
|
||||
expected_offenses.zip(cop.offenses).each do |expected, actual|
|
||||
expect_offense(expected, actual)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe RuboCop::Cop::FormulaAudit::ChecksumCase do
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
context "When auditing spec checksums" do
|
||||
it "When the checksum has upper case 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 "5cf6e1ae0A645b426c0a7cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9a"
|
||||
|
||||
resource "foo-package" do
|
||||
url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1Ae0a645b426b047aa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea9"
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
|
||||
expected_offenses = [{ message: "sha256 should be lowercase",
|
||||
severity: :convention,
|
||||
line: 5,
|
||||
column: 21,
|
||||
source: source },
|
||||
{ message: "sha256 should be lowercase",
|
||||
severity: :convention,
|
||||
line: 9,
|
||||
column: 20,
|
||||
source: source }]
|
||||
|
||||
inspect_source(cop, source)
|
||||
|
||||
expected_offenses.zip(cop.offenses).each do |expected, actual|
|
||||
expect_offense(expected, actual)
|
||||
end
|
||||
end
|
||||
|
||||
it "When auditing stable blocks outside spec blocks" do
|
||||
source = <<-EOS.undent
|
||||
class Foo < Formula
|
||||
url 'http://example.com/foo-1.0.tgz'
|
||||
resource "foo-outside" do
|
||||
url "https://github.com/foo-lang/foo-outside/archive/0.18.0.tar.gz"
|
||||
sha256 "A4cc7cd3f7d1605ffa1ac5755cf6e1ae0a645b426b047a6a39a8b2268ddc7ea9"
|
||||
end
|
||||
stable do
|
||||
url "https://github.com/foo-lang/foo-compiler/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1ae0a645b426c0a7cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9a"
|
||||
|
||||
resource "foo-package" do
|
||||
url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1ae0a645b426b047aa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea9"
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
|
||||
expected_offenses = [{ message: "sha256 should be lowercase",
|
||||
severity: :convention,
|
||||
line: 5,
|
||||
column: 12,
|
||||
source: source }]
|
||||
|
||||
inspect_source(cop, source)
|
||||
|
||||
expected_offenses.zip(cop.offenses).each do |expected, actual|
|
||||
expect_offense(expected, actual)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "When auditing checksum with autocorrect" do
|
||||
it "When there is uppercase sha256" 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 "5cf6e1ae0A645b426c0a7cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9a"
|
||||
|
||||
resource "foo-package" do
|
||||
url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1Ae0a645b426b047aa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea9"
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
|
||||
corrected_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 "5cf6e1ae0a645b426c0a7cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea0e9a"
|
||||
|
||||
resource "foo-package" do
|
||||
url "https://github.com/foo-lang/foo-package/archive/0.18.0.tar.gz"
|
||||
sha256 "5cf6e1ae0a645b426b047aa4cc7cd3f7d1605ffa1ac5756a39a8b2268ddc7ea9"
|
||||
end
|
||||
end
|
||||
end
|
||||
EOS
|
||||
|
||||
new_source = autocorrect_source(cop, source)
|
||||
expect(new_source).to eq(corrected_source)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user