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