Add cask URL location to audit problems.
This commit is contained in:
parent
106a61c0a6
commit
813e639678
@ -5,6 +5,7 @@ require "cask/denylist"
|
||||
require "cask/download"
|
||||
require "digest"
|
||||
require "livecheck/livecheck"
|
||||
require "source_location"
|
||||
require "utils/curl"
|
||||
require "utils/git"
|
||||
require "utils/shared_audits"
|
||||
@ -79,7 +80,13 @@ module Cask
|
||||
!errors?
|
||||
end
|
||||
|
||||
sig { params(message: T.nilable(String), location: T.nilable(String), strict_only: T::Boolean).void }
|
||||
sig {
|
||||
params(
|
||||
message: T.nilable(String),
|
||||
location: T.nilable(Homebrew::SourceLocation),
|
||||
strict_only: T::Boolean,
|
||||
).void
|
||||
}
|
||||
def add_error(message, location: nil, strict_only: false)
|
||||
# Only raise non-critical audits if the user specified `--strict`.
|
||||
return if strict_only && !@strict
|
||||
@ -231,7 +238,9 @@ module Cask
|
||||
return unless cask.sha256
|
||||
return if cask.sha256 == :no_check
|
||||
|
||||
add_error "Use `sha256 :no_check` when URL is unversioned." if cask.url&.unversioned?
|
||||
return unless cask.url&.unversioned?
|
||||
|
||||
add_error "Use `sha256 :no_check` when URL is unversioned."
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -296,11 +305,11 @@ module Cask
|
||||
when %r{sourceforge.net/(\S+)}
|
||||
return unless online?
|
||||
|
||||
add_error "Download is hosted on SourceForge, #{add_livecheck}"
|
||||
add_error "Download is hosted on SourceForge, #{add_livecheck}", location: cask.url.location
|
||||
when %r{dl.devmate.com/(\S+)}
|
||||
add_error "Download is hosted on DevMate, #{add_livecheck}"
|
||||
add_error "Download is hosted on DevMate, #{add_livecheck}", location: cask.url.location
|
||||
when %r{rink.hockeyapp.net/(\S+)}
|
||||
add_error "Download is hosted on HockeyApp, #{add_livecheck}"
|
||||
add_error "Download is hosted on HockeyApp, #{add_livecheck}", location: cask.url.location
|
||||
end
|
||||
end
|
||||
|
||||
@ -312,9 +321,11 @@ module Cask
|
||||
|
||||
odebug "Auditing URL format"
|
||||
if bad_sourceforge_url?
|
||||
add_error "SourceForge URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}"
|
||||
add_error "SourceForge URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}",
|
||||
location: cask.url.location
|
||||
elsif bad_osdn_url?
|
||||
add_error "OSDN URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}"
|
||||
add_error "OSDN URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}",
|
||||
location: cask.url.location
|
||||
end
|
||||
end
|
||||
|
||||
@ -352,7 +363,8 @@ module Cask
|
||||
|
||||
add_error "Verified URL #{Formatter.url(url_from_verified)} does not match URL " \
|
||||
"#{Formatter.url(strip_url_scheme(cask.url.to_s))}. " \
|
||||
"See #{Formatter.url(VERIFIED_URL_REFERENCE_URL)}"
|
||||
"See #{Formatter.url(VERIFIED_URL_REFERENCE_URL)}",
|
||||
location: cask.url.location
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -434,10 +446,11 @@ module Cask
|
||||
def audit_download
|
||||
return if download.blank? || cask.url.blank?
|
||||
|
||||
odebug "Auditing download"
|
||||
download.fetch
|
||||
rescue => e
|
||||
add_error "download not possible: #{e}"
|
||||
begin
|
||||
download.fetch
|
||||
rescue => e
|
||||
add_error "download not possible: #{e}", location: cask.url.location
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -447,10 +460,9 @@ module Cask
|
||||
return if cask.url.to_s.include? cask.version.csv.second
|
||||
return if cask.version.csv.third.present? && cask.url.to_s.include?(cask.version.csv.third)
|
||||
|
||||
add_error(
|
||||
"Download does not require additional version components. Use `&:short_version` in the livecheck",
|
||||
strict_only: true,
|
||||
)
|
||||
add_error "Download does not require additional version components. Use `&:short_version` in the livecheck",
|
||||
location: cask.url.location,
|
||||
strict_only: true
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -483,7 +495,7 @@ module Cask
|
||||
|
||||
next if result.success?
|
||||
|
||||
add_error(<<~EOS, strict_only: true)
|
||||
add_error <<~EOS, location: cask.url.location, strict_only: true
|
||||
Signature verification failed:
|
||||
#{result.merged_output}
|
||||
macOS on ARM requires software to be signed.
|
||||
@ -580,7 +592,7 @@ module Cask
|
||||
tag = SharedAudits.github_tag_from_url(cask.url)
|
||||
tag ||= cask.version
|
||||
error = SharedAudits.github_release(user, repo, tag, cask: cask)
|
||||
add_error error if error
|
||||
add_error error, location: cask.url.location if error
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -595,7 +607,7 @@ module Cask
|
||||
tag = SharedAudits.gitlab_tag_from_url(cask.url)
|
||||
tag ||= cask.version
|
||||
error = SharedAudits.gitlab_release(user, repo, tag, cask: cask)
|
||||
add_error error if error
|
||||
add_error error, location: cask.url.location if error
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -606,12 +618,10 @@ module Cask
|
||||
user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if online?
|
||||
return if user.nil?
|
||||
|
||||
odebug "Auditing GitHub repo archived"
|
||||
|
||||
metadata = SharedAudits.github_repo_data(user, repo)
|
||||
return if metadata.nil?
|
||||
|
||||
add_error "GitHub repo is archived" if metadata["archived"]
|
||||
add_error "GitHub repo is archived", location: cask.url.location if metadata["archived"]
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -627,7 +637,7 @@ module Cask
|
||||
metadata = SharedAudits.gitlab_repo_data(user, repo)
|
||||
return if metadata.nil?
|
||||
|
||||
add_error "GitLab repo is archived" if metadata["archived"]
|
||||
add_error "GitLab repo is archived", location: cask.url.location if metadata["archived"]
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -640,7 +650,7 @@ module Cask
|
||||
odebug "Auditing GitHub repo"
|
||||
|
||||
error = SharedAudits.github(user, repo)
|
||||
add_error error if error
|
||||
add_error error, location: cask.url.location if error
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -653,7 +663,7 @@ module Cask
|
||||
odebug "Auditing GitLab repo"
|
||||
|
||||
error = SharedAudits.gitlab(user, repo)
|
||||
add_error error if error
|
||||
add_error error, location: cask.url.location if error
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -666,7 +676,7 @@ module Cask
|
||||
odebug "Auditing Bitbucket repo"
|
||||
|
||||
error = SharedAudits.bitbucket(user, repo)
|
||||
add_error error if error
|
||||
add_error error, location: cask.url.location if error
|
||||
end
|
||||
|
||||
sig { void }
|
||||
@ -694,6 +704,7 @@ module Cask
|
||||
|
||||
if cask.url && !cask.url.using
|
||||
validate_url_for_https_availability(cask.url, "binary URL", cask.token, cask.tap,
|
||||
location: cask.url.location,
|
||||
user_agents: [cask.url.user_agent], referer: cask.url&.referer)
|
||||
end
|
||||
|
||||
@ -714,14 +725,15 @@ module Cask
|
||||
# params(url_to_check: T.any(String, URL), url_type: String, cask_token: String, tap: Tap,
|
||||
# options: T.untyped).void
|
||||
# }
|
||||
def validate_url_for_https_availability(url_to_check, url_type, cask_token, tap, **options)
|
||||
def validate_url_for_https_availability(url_to_check, url_type, cask_token, tap, location: nil, **options)
|
||||
problem = curl_check_http_content(url_to_check.to_s, url_type, **options)
|
||||
exception = tap&.audit_exception(:secure_connection_audit_skiplist, cask_token, url_to_check.to_s)
|
||||
|
||||
if problem
|
||||
add_error problem unless exception
|
||||
add_error problem, location: location unless exception
|
||||
elsif exception
|
||||
add_error "#{url_to_check} is in the secure connection audit skiplist but does not need to be skipped"
|
||||
add_error "#{url_to_check} is in the secure connection audit skiplist but does not need to be skipped",
|
||||
location: location
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "source_location"
|
||||
|
||||
module Cask
|
||||
# Class corresponding to the `url` stanza.
|
||||
#
|
||||
@ -222,20 +224,25 @@ module Cask
|
||||
@dsl = dsl
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def raw_interpolated_url
|
||||
return @raw_interpolated_url if defined?(@raw_interpolated_url)
|
||||
|
||||
@raw_interpolated_url =
|
||||
Pathname(@caller_location.path)
|
||||
.each_line.drop(@caller_location.lineno - 1)
|
||||
.first&.then { |line| line[/url\s+"([^"]+)"/, 1] }
|
||||
sig { returns(Homebrew::SourceLocation) }
|
||||
def location
|
||||
Homebrew::SourceLocation.new(@caller_location.lineno, raw_url_line&.index("url"))
|
||||
end
|
||||
private :raw_interpolated_url
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
def raw_url_line
|
||||
return @raw_url_line if defined?(@raw_url_line)
|
||||
|
||||
@raw_url_line = Pathname(@caller_location.path)
|
||||
.each_line
|
||||
.drop(@caller_location.lineno - 1)
|
||||
.first
|
||||
end
|
||||
private :raw_url_line
|
||||
|
||||
sig { params(ignore_major_version: T::Boolean).returns(T::Boolean) }
|
||||
def unversioned?(ignore_major_version: false)
|
||||
interpolated_url = raw_interpolated_url
|
||||
interpolated_url = raw_url_line&.then { |line| line[/url\s+"([^"]+)"/, 1] }
|
||||
|
||||
return false unless interpolated_url
|
||||
|
||||
|
||||
26
Library/Homebrew/source_location.rb
Normal file
26
Library/Homebrew/source_location.rb
Normal file
@ -0,0 +1,26 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Homebrew
|
||||
# A location in source code.
|
||||
#
|
||||
# @api private
|
||||
class SourceLocation
|
||||
sig { returns(Integer) }
|
||||
attr_reader :line
|
||||
|
||||
sig { returns(T.nilable(Integer)) }
|
||||
attr_reader :column
|
||||
|
||||
sig { params(line: Integer, column: T.nilable(Integer)).void }
|
||||
def initialize(line, column = T.unsafe(nil))
|
||||
@line = line
|
||||
@column = column
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"#{line}#{column&.to_s&.prepend(":")}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -2,6 +2,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "shellwords"
|
||||
require "source_location"
|
||||
|
||||
module Homebrew
|
||||
# Helper module for running RuboCop.
|
||||
@ -311,7 +312,8 @@ module Homebrew
|
||||
@message = json["message"]
|
||||
@cop_name = json["cop_name"]
|
||||
@corrected = json["corrected"]
|
||||
@location = LineLocation.new(json["location"])
|
||||
location = json["location"]
|
||||
@location = SourceLocation.new(location.fetch("line"), location["column"])
|
||||
end
|
||||
|
||||
def severity_code
|
||||
@ -322,20 +324,5 @@ module Homebrew
|
||||
@corrected
|
||||
end
|
||||
end
|
||||
|
||||
# Source location of a style offense.
|
||||
class LineLocation
|
||||
attr_reader :line, :column
|
||||
|
||||
def initialize(json)
|
||||
@line = json["line"]
|
||||
@column = json["column"]
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
def to_s
|
||||
"#{line}: col #{column}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user