From 16618374653dc5461dd971e8ed1992188cc3803d Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Tue, 6 Sep 2022 11:46:40 +0100 Subject: [PATCH] Revert "Cask: automatically add cask audits" --- Library/Homebrew/cask/audit.rb | 439 +++++++++++------------ Library/Homebrew/cask/auditor.rb | 1 + Library/Homebrew/test/cask/audit_spec.rb | 243 ++++++------- 3 files changed, 314 insertions(+), 369 deletions(-) diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 654d92fe13..7fd0c55d91 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -24,7 +24,7 @@ module Cask def initialize(cask, appcast: nil, download: nil, quarantine: nil, token_conflicts: nil, online: nil, strict: nil, signing: nil, - new_cask: nil, only: [], except: []) + new_cask: nil) # `new_cask` implies `online`, `token_conflicts`, `strict` and `signing` online = new_cask if online.nil? @@ -47,22 +47,44 @@ module Cask @signing = signing @new_cask = new_cask @token_conflicts = token_conflicts - @only = only - @except = except end def run! - only_audits = @only - except_audits = @except - - private_methods.map(&:to_s).grep(/^check_/).each do |audit_method_name| - name = audit_method_name.delete_prefix("check_") - next if !only_audits.empty? && only_audits&.exclude?(name) - next if except_audits&.include?(name) - - send(audit_method_name) - end - + check_denylist + check_reverse_migration + check_required_stanzas + check_version + check_sha256 + check_desc + check_url + check_unnecessary_verified + check_missing_verified + check_no_match + check_generic_artifacts + check_token_valid + check_token_bad_words + check_token_conflicts + check_languages + check_download + check_https_availability + check_single_pre_postflight + check_single_uninstall_zap + check_untrusted_pkg + livecheck_result = check_livecheck_version + check_hosting_with_livecheck(livecheck_result: livecheck_result) + check_appcast_and_livecheck + check_latest_with_appcast_or_livecheck + check_latest_with_auto_updates + check_stanza_requires_uninstall + check_appcast_contains_version + check_gitlab_repository + check_gitlab_repository_archived + check_gitlab_prerelease_version + check_github_repository + check_github_repository_archived + check_github_prerelease_version + check_bitbucket_repository + check_signing self rescue => e odebug e, e.backtrace @@ -78,27 +100,10 @@ module Cask @warnings ||= [] end - sig { returns(T::Boolean) } - def errors? - errors.any? - end - - sig { returns(T::Boolean) } - def warnings? - warnings.any? - end - - sig { returns(T::Boolean) } - def success? - !(errors? || warnings?) - end - - sig { params(message: String, location: T.nilable(String)).void } def add_error(message, location: nil) errors << ({ message: message, location: location }) end - sig { params(message: String, location: T.nilable(String)).void } def add_warning(message, location: nil) if strict? add_error message, location: location @@ -107,6 +112,14 @@ module Cask end end + def errors? + errors.any? + end + + def warnings? + warnings.any? + end + def result if errors? Formatter.error("failed") @@ -137,9 +150,12 @@ module Cask summary.join("\n") end + def success? + !(errors? || warnings?) + end + private - sig { void } def check_untrusted_pkg odebug "Auditing pkg stanza: allow_untrusted" @@ -154,7 +170,6 @@ module Cask add_error "allow_untrusted is not permitted in official Homebrew Cask taps" end - sig { void } def check_stanza_requires_uninstall odebug "Auditing stanzas which require an uninstall" @@ -164,7 +179,6 @@ module Cask add_error "installer and pkg stanzas require an uninstall stanza" end - sig { void } def check_single_pre_postflight odebug "Auditing preflight and postflight stanzas" @@ -181,7 +195,6 @@ module Cask add_error "only a single postflight stanza is allowed" end - sig { void } def check_single_uninstall_zap odebug "Auditing single uninstall_* and zap stanzas" @@ -208,7 +221,6 @@ module Cask add_error "only a single zap stanza is allowed" end - sig { void } def check_required_stanzas odebug "Auditing required stanzas" [:version, :sha256, :url, :homepage].each do |sym| @@ -221,66 +233,58 @@ module Cask add_error "at least one activatable artifact stanza is required" if installable_artifacts.empty? end - sig { void } - def check_description_present - # Fonts seldom benefit from descriptions and requiring them disproportionately increases the maintenance burden - return if cask.tap == "homebrew/cask-fonts" - - add_warning "Cask should have a description. Please add a `desc` stanza." if cask.desc.blank? - end - - sig { void } - def check_no_string_version_latest + def check_version return unless cask.version - odebug "Auditing version :latest does not appear as a string ('latest')" + check_no_string_version_latest + end + + def check_no_string_version_latest + odebug "Verifying version :latest does not appear as a string ('latest')" return unless cask.version.raw_version == "latest" add_error "you should use version :latest instead of version 'latest'" end - sig { void } - def check_sha256_no_check_if_latest + def check_sha256 return unless cask.sha256 - odebug "Auditing sha256 :no_check with version :latest" + check_sha256_no_check_if_latest + check_sha256_no_check_if_unversioned + check_sha256_actually_256 + check_sha256_invalid + end + + def check_sha256_no_check_if_latest + odebug "Verifying sha256 :no_check with version :latest" return unless cask.version.latest? return if cask.sha256 == :no_check add_error "you should use sha256 :no_check when version is :latest" end - sig { void } def check_sha256_no_check_if_unversioned - return unless cask.sha256 return if cask.sha256 == :no_check add_error "Use `sha256 :no_check` when URL is unversioned." if cask.url&.unversioned? end - sig { void } def check_sha256_actually_256 - return unless cask.sha256 - - odebug "Auditing sha256 string is a legal SHA-256 digest" + odebug "Verifying sha256 string is a legal SHA-256 digest" return unless cask.sha256.is_a?(Checksum) return if cask.sha256.length == 64 && cask.sha256[/^[0-9a-f]+$/i] add_error "sha256 string must be of 64 hexadecimal characters" end - sig { void } def check_sha256_invalid - return unless cask.sha256 - - odebug "Auditing sha256 is not a known invalid value" + odebug "Verifying sha256 is not a known invalid value" empty_sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" return unless cask.sha256 == empty_sha256 add_error "cannot use the sha256 for an empty string: #{empty_sha256}" end - sig { void } def check_appcast_and_livecheck return unless cask.appcast @@ -291,7 +295,6 @@ module Cask end end - sig { void } def check_latest_with_appcast_or_livecheck return unless cask.version.latest? @@ -299,7 +302,6 @@ module Cask add_error "Casks with a `livecheck` should not use `version :latest`." if cask.livecheckable? end - sig { void } def check_latest_with_auto_updates return unless cask.version.latest? return unless cask.auto_updates @@ -309,8 +311,7 @@ module Cask LIVECHECK_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#stanza-livecheck" - sig { params(livecheck_result: T::Boolean).void } - def check_hosting_with_livecheck(livecheck_result: check_livecheck_version) + def check_hosting_with_livecheck(livecheck_result:) return if cask.discontinued? || cask.version.latest? return if block_url_offline? || cask.appcast || cask.livecheckable? return if livecheck_result == :auto_detected @@ -329,12 +330,24 @@ module Cask end end - SOURCEFORGE_OSDN_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#sourceforgeosdn-urls" + def check_desc + return if cask.desc.present? - sig { void } - def check_download_url_format + # Fonts seldom benefit from descriptions and requiring them disproportionately increases the maintenance burden + return if cask.tap == "homebrew/cask-fonts" + + add_warning "Cask should have a description. Please add a `desc` stanza." + end + + def check_url return unless cask.url + check_download_url_format + end + + SOURCEFORGE_OSDN_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#sourceforgeosdn-urls" + + def check_download_url_format odebug "Auditing URL format" if bad_sourceforge_url? add_error "SourceForge URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}" @@ -343,9 +356,82 @@ module Cask end end + def bad_url_format?(regex, valid_formats_array) + return false unless cask.url.to_s.match?(regex) + + valid_formats_array.none? { |format| cask.url.to_s =~ format } + end + + def bad_sourceforge_url? + bad_url_format?(/sourceforge/, + [ + %r{\Ahttps://sourceforge\.net/projects/[^/]+/files/latest/download\Z}, + %r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)/)}, + ]) + end + + def bad_osdn_url? + bad_url_format?(/osd/, [%r{\Ahttps?://([^/]+.)?dl\.osdn\.jp/}]) + end + + def homepage + URI(cask.homepage.to_s).host + end + + def domain + URI(cask.url.to_s).host + end + + def url_match_homepage? + host = cask.url.to_s + host_uri = URI(host) + host = if host.match?(/:\d/) && host_uri.port != 80 + "#{host_uri.host}:#{host_uri.port}" + else + host_uri.host + end + home = homepage.downcase + if (split_host = host.split(".")).length >= 3 + host = split_host[-2..].join(".") + end + if (split_home = homepage.split(".")).length >= 3 + home = split_home[-2..].join(".") + end + host == home + end + + def strip_url_scheme(url) + url.sub(%r{^[^:/]+://(www\.)?}, "") + end + + def url_from_verified + strip_url_scheme(cask.url.verified) + end + + def verified_matches_url? + url_domain, url_path = strip_url_scheme(cask.url.to_s).split("/", 2) + verified_domain, verified_path = url_from_verified.split("/", 2) + + (url_domain == verified_domain || (verified_domain && url_domain&.end_with?(".#{verified_domain}"))) && + (!verified_path || url_path&.start_with?(verified_path)) + end + + def verified_present? + cask.url.verified.present? + end + + def file_url? + URI(cask.url.to_s).scheme == "file" + end + + def block_url_offline? + return false if online? + + cask.url.from_block? + end + VERIFIED_URL_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#when-url-and-homepage-domains-differ-add-verified" - sig { void } def check_unnecessary_verified return if block_url_offline? return unless verified_present? @@ -357,7 +443,6 @@ module Cask "See #{Formatter.url(VERIFIED_URL_REFERENCE_URL)}" end - sig { void } def check_missing_verified return if block_url_offline? return if file_url? @@ -369,7 +454,6 @@ module Cask "See #{Formatter.url(VERIFIED_URL_REFERENCE_URL)}" end - sig { void } def check_no_match return if block_url_offline? return unless verified_present? @@ -380,7 +464,6 @@ module Cask "See #{Formatter.url(VERIFIED_URL_REFERENCE_URL)}" end - sig { void } def check_generic_artifacts cask.artifacts.select { |a| a.is_a?(Artifact::Artifact) }.each do |artifact| unless artifact.target.absolute? @@ -389,7 +472,6 @@ module Cask end end - sig { void } def check_languages @cask.languages.each do |language| Locale.parse(language) @@ -398,7 +480,6 @@ module Cask end end - sig { void } def check_token_conflicts return unless token_conflicts? return unless core_formula_names.include?(cask.token) @@ -407,7 +488,6 @@ module Cask "#{Formatter.url(core_formula_url)}" end - sig { void } def check_token_valid add_error "cask token contains non-ascii characters" unless cask.token.ascii_only? add_error "cask token + should be replaced by -plus-" if cask.token.include? "+" @@ -425,7 +505,6 @@ module Cask add_error "cask token should not have leading or trailing hyphens" end - sig { void } def check_token_bad_words return unless new_cask? @@ -453,7 +532,19 @@ module Cask add_warning "cask token mentions framework" end - sig { void } + def core_tap + @core_tap ||= CoreTap.instance + end + + def core_formula_names + core_tap.formula_names + end + + sig { returns(String) } + def core_formula_url + "#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb" + end + def check_download return if download.blank? || cask.url.blank? @@ -463,11 +554,11 @@ module Cask add_error "download not possible: #{e}" end - sig { void } def check_signing return if !signing? || download.blank? || cask.url.blank? odebug "Auditing signing" + odebug cask.artifacts artifacts = cask.artifacts.select { |k| k.is_a?(Artifact::Pkg) || k.is_a?(Artifact::App) } return if artifacts.empty? @@ -507,7 +598,6 @@ module Cask end end - sig { returns(T.nilable(T.any(T::Boolean, Symbol))) } def check_livecheck_version return unless appcast? @@ -545,7 +635,6 @@ module Cask false end - sig { void } def check_appcast_contains_version return unless appcast? return if cask.appcast.to_s.empty? @@ -572,7 +661,6 @@ module Cask EOS end - sig { void } def check_github_prerelease_version return if cask.tap == "homebrew/cask-versions" @@ -586,7 +674,6 @@ module Cask add_error error if error end - sig { void } def check_gitlab_prerelease_version return if cask.tap == "homebrew/cask-versions" @@ -601,7 +688,6 @@ module Cask add_error error if error end - sig { void } def check_github_repository_archived user, repo = get_repo_data(%r{https?://github\.com/([^/]+)/([^/]+)/?.*}) if online? return if user.nil? @@ -622,7 +708,6 @@ module Cask end end - sig { void } def check_gitlab_repository_archived user, repo = get_repo_data(%r{https?://gitlab\.com/([^/]+)/([^/]+)/?.*}) if online? return if user.nil? @@ -643,7 +728,6 @@ module Cask end end - sig { void } def check_github_repository return unless new_cask? @@ -656,7 +740,6 @@ module Cask add_error error if error end - sig { void } def check_gitlab_repository return unless new_cask? @@ -669,7 +752,6 @@ module Cask add_error error if error end - sig { void } def check_bitbucket_repository return unless new_cask? @@ -682,62 +764,6 @@ module Cask add_error error if error end - sig { void } - def check_denylist - return unless cask.tap - return unless cask.tap.official? - return unless (reason = Denylist.reason(cask.token)) - - add_error "#{cask.token} is not allowed: #{reason}" - end - - sig { void } - def check_reverse_migration - return unless new_cask? - return unless cask.tap - return unless cask.tap.official? - return unless cask.tap.tap_migrations.key?(cask.token) - - add_error "#{cask.token} is listed in tap_migrations.json" - end - - sig { void } - def check_https_availability - return unless download - - if cask.url && !cask.url.using - validate_url_for_https_availability(cask.url, "binary URL", cask.token, cask.tap, - user_agents: [cask.url.user_agent]) - end - - if cask.appcast && appcast? - validate_url_for_https_availability(cask.appcast, "appcast URL", cask.token, cask.tap, check_content: true) - end - - return unless cask.homepage - - validate_url_for_https_availability(cask.homepage, "homepage URL", cask.token, cask.tap, - user_agents: [:browser, :default], - check_content: true, - strict: strict?) - end - - sig { - 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) - 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 - elsif exception - add_error "#{url_to_check} is in the secure connection audit skiplist but does not need to be skipped" - end - end - - sig { params(regex: String).returns(T.nilable(T::Array[String])) } def get_repo_data(regex) return unless online? @@ -751,105 +777,52 @@ module Cask [user, repo] end - sig { params(regex: T.any(String, Regexp), valid_formats_array: T::Array[String]).returns(T::Boolean) } - def bad_url_format?(regex, valid_formats_array) - return false unless cask.url.to_s.match?(regex) + def check_denylist + return unless cask.tap + return unless cask.tap.official? + return unless (reason = Denylist.reason(cask.token)) - valid_formats_array.none? { |format| cask.url.to_s =~ format } + add_error "#{cask.token} is not allowed: #{reason}" end - sig { returns(T::Boolean) } - def bad_sourceforge_url? - bad_url_format?(/sourceforge/, - [ - %r{\Ahttps://sourceforge\.net/projects/[^/]+/files/latest/download\Z}, - %r{\Ahttps://downloads\.sourceforge\.net/(?!(project|sourceforge)/)}, - ]) + def check_reverse_migration + return unless new_cask? + return unless cask.tap + return unless cask.tap.official? + return unless cask.tap.tap_migrations.key?(cask.token) + + add_error "#{cask.token} is listed in tap_migrations.json" end - sig { returns(T::Boolean) } - def bad_osdn_url? - bad_url_format?(/osd/, [%r{\Ahttps?://([^/]+.)?dl\.osdn\.jp/}]) - end + def check_https_availability + return unless download - sig { returns(String) } - def homepage - URI(cask.homepage.to_s).host - end - - sig { returns(String) } - def domain - URI(cask.url.to_s).host - end - - sig { returns(T::Boolean) } - def url_match_homepage? - host = cask.url.to_s - host_uri = URI(host) - host = if host.match?(/:\d/) && host_uri.port != 80 - "#{host_uri.host}:#{host_uri.port}" - else - host_uri.host + if cask.url && !cask.url.using + check_url_for_https_availability(cask.url, "binary URL", cask.token, cask.tap, + user_agents: [cask.url.user_agent]) end - home = homepage.downcase - if (split_host = host.split(".")).length >= 3 - host = split_host[-2..].join(".") + + if cask.appcast && appcast? + check_url_for_https_availability(cask.appcast, "appcast URL", cask.token, cask.tap, check_content: true) end - if (split_home = homepage.split(".")).length >= 3 - home = split_home[-2..].join(".") + + return unless cask.homepage + + check_url_for_https_availability(cask.homepage, "homepage URL", cask.token, cask.tap, + user_agents: [:browser, :default], + check_content: true, + strict: strict?) + end + + def check_url_for_https_availability(url_to_check, url_type, cask_token, tap, **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 + elsif exception + add_error "#{url_to_check} is in the secure connection audit skiplist but does not need to be skipped" end - host == home - end - - sig { params(url: String).returns(String) } - def strip_url_scheme(url) - url.sub(%r{^[^:/]+://(www\.)?}, "") - end - - sig { returns(String) } - def url_from_verified - strip_url_scheme(cask.url.verified) - end - - sig { returns(T::Boolean) } - def verified_matches_url? - url_domain, url_path = strip_url_scheme(cask.url.to_s).split("/", 2) - verified_domain, verified_path = url_from_verified.split("/", 2) - - (url_domain == verified_domain || (verified_domain && url_domain&.end_with?(".#{verified_domain}"))) && - (!verified_path || url_path&.start_with?(verified_path)) - end - - sig { returns(T::Boolean) } - def verified_present? - cask.url.verified.present? - end - - sig { returns(T::Boolean) } - def file_url? - URI(cask.url.to_s).scheme == "file" - end - - sig { returns(T::Boolean) } - def block_url_offline? - return false if online? - - cask.url.from_block? - end - - sig { returns(Tap) } - def core_tap - @core_tap ||= CoreTap.instance - end - - sig { returns(T::Array[String]) } - def core_formula_names - core_tap.formula_names - end - - sig { returns(String) } - def core_formula_url - "#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb" end end end diff --git a/Library/Homebrew/cask/auditor.rb b/Library/Homebrew/cask/auditor.rb index daae35b9b4..2b80340860 100644 --- a/Library/Homebrew/cask/auditor.rb +++ b/Library/Homebrew/cask/auditor.rb @@ -144,6 +144,7 @@ module Cask quarantine: @quarantine, ) audit.run! + audit end def language_blocks diff --git a/Library/Homebrew/test/cask/audit_spec.rb b/Library/Homebrew/test/cask/audit_spec.rb index 24ba2cef06..020b8dfe33 100644 --- a/Library/Homebrew/test/cask/audit_spec.rb +++ b/Library/Homebrew/test/cask/audit_spec.rb @@ -33,15 +33,13 @@ describe Cask::Audit, :cask do let(:cask) { instance_double(Cask::Cask) } let(:new_cask) { nil } let(:online) { nil } - let(:only) { [] } let(:strict) { nil } let(:token_conflicts) { nil } let(:audit) { described_class.new(cask, online: online, strict: strict, new_cask: new_cask, - token_conflicts: token_conflicts, - only: only) + token_conflicts: token_conflicts) } describe "#new" do @@ -134,7 +132,6 @@ describe Cask::Audit, :cask do describe "token validation" do let(:strict) { true } - let(:only) { ["token_valid"] } let(:cask) do tmp_cask cask_token.to_s, <<~RUBY cask '#{cask_token}' do @@ -231,7 +228,6 @@ describe Cask::Audit, :cask do describe "token bad words" do let(:new_cask) { true } - let(:only) { ["token_bad_words", "reverse_migration"] } let(:online) { false } let(:cask) do tmp_cask cask_token.to_s, <<~RUBY @@ -347,7 +343,6 @@ describe Cask::Audit, :cask do end describe "locale validation" do - let(:only) { ["languages"] } let(:cask) do tmp_cask "locale-cask-test", <<~RUBY cask 'locale-cask-test' do @@ -395,7 +390,6 @@ describe Cask::Audit, :cask do end describe "pkg allow_untrusted checks" do - let(:only) { ["untrusted_pkg"] } let(:message) { "allow_untrusted is not permitted in official Homebrew Cask taps" } context "when the Cask has no pkg stanza" do @@ -418,7 +412,6 @@ describe Cask::Audit, :cask do end describe "signing checks" do - let(:only) { ["signing"] } let(:download_double) { instance_double(Cask::Download) } let(:unpack_double) { instance_double(UnpackStrategy::Zip) } @@ -466,7 +459,6 @@ describe Cask::Audit, :cask do end describe "livecheck should be skipped" do - let(:only) { ["livecheck_version"] } let(:online) { true } let(:message) { /Version '[^']*' differs from '[^']*' retrieved by livecheck\./ } @@ -520,7 +512,6 @@ describe Cask::Audit, :cask do end describe "when the Cask stanza requires uninstall" do - let(:only) { ["stanza_requires_uninstall"] } let(:message) { "installer and pkg stanzas require an uninstall stanza" } context "when the Cask does not require an uninstall" do @@ -690,14 +681,12 @@ describe Cask::Audit, :cask do let(:message) { "you should use version :latest instead of version 'latest'" } context "when version is 'latest'" do - let(:only) { ["no_string_version_latest"] } let(:cask_token) { "version-latest-string" } it { is_expected.to fail_with(message) } end context "when version is :latest" do - let(:only) { ["sha256_no_check_if_latest"] } let(:cask_token) { "version-latest-with-checksum" } it { is_expected.not_to fail_with(message) } @@ -706,21 +695,18 @@ describe Cask::Audit, :cask do describe "sha256 checks" do context "when version is :latest and sha256 is not :no_check" do - let(:only) { ["sha256_no_check_if_latest"] } let(:cask_token) { "version-latest-with-checksum" } it { is_expected.to fail_with("you should use sha256 :no_check when version is :latest") } end context "when sha256 is not a legal SHA-256 digest" do - let(:only) { ["sha256_actually_256"] } let(:cask_token) { "invalid-sha256" } it { is_expected.to fail_with("sha256 string must be of 64 hexadecimal characters") } end context "when sha256 is sha256 for empty string" do - let(:only) { ["sha256_invalid"] } let(:cask_token) { "sha256-for-empty-string" } it { is_expected.to fail_with(/cannot use the sha256 for an empty string/) } @@ -728,7 +714,6 @@ describe Cask::Audit, :cask do end describe "hosting with livecheck checks" do - let(:only) { ["hosting_with_livecheck"] } let(:message) { /please add a livecheck/ } context "when the download does not use hosting with a livecheck" do @@ -776,7 +761,6 @@ describe Cask::Audit, :cask do end describe "latest with appcast checks" do - let(:only) { ["latest_with_appcast_or_livecheck"] } let(:message) { "Casks with an `appcast` should not use `version :latest`." } context "when the Cask is :latest and does not have an appcast" do @@ -799,8 +783,6 @@ describe Cask::Audit, :cask do end describe "denylist checks" do - let(:only) { ["denylist"] } - context "when the Cask is not on the denylist" do let(:cask_token) { "adobe-air" } @@ -823,7 +805,6 @@ describe Cask::Audit, :cask do end describe "latest with auto_updates checks" do - let(:only) { ["latest_with_auto_updates"] } let(:message) { "Casks with `version :latest` should not use `auto_updates`." } context "when the Cask is :latest and does not have auto_updates" do @@ -852,7 +833,6 @@ describe Cask::Audit, :cask do end describe "preferred download URL formats" do - let(:only) { ["download_url_format"] } let(:message) { /URL format incorrect/ } context "with incorrect SourceForge URL format" do @@ -887,8 +867,6 @@ describe Cask::Audit, :cask do end describe "generic artifact checks" do - let(:only) { ["generic_artifacts"] } - context "with relative target" do let(:cask_token) { "generic-artifact-relative-target" } @@ -909,8 +887,6 @@ describe Cask::Audit, :cask do end describe "url checks" do - let(:only) { %w[unnecessary_verified missing_verified no_match] } - context "with a block" do let(:cask_token) { "booby-trap" } @@ -924,7 +900,7 @@ describe Cask::Audit, :cask do let(:online) { false } it "does not evaluate the block" do - expect(run).not_to fail_with(/Boom/) + expect(run).not_to pass end end @@ -939,7 +915,6 @@ describe Cask::Audit, :cask do end describe "token conflicts" do - let(:only) { ["token_conflicts"] } let(:cask_token) { "with-binary" } let(:token_conflicts) { true } @@ -960,7 +935,6 @@ describe Cask::Audit, :cask do end describe "audit of downloads" do - let(:only) { ["download"] } let(:cask_token) { "basic-cask" } let(:cask) { Cask::CaskLoader.load(cask_token) } let(:download_double) { instance_double(Cask::Download) } @@ -985,7 +959,6 @@ describe Cask::Audit, :cask do context "when an exception is raised" do let(:cask) { instance_double(Cask::Cask) } - let(:only) { ["description_present"] } it "fails the audit" do expect(cask).to receive(:tap).and_raise(StandardError.new) @@ -993,8 +966,7 @@ describe Cask::Audit, :cask do end end - describe "checking description" do - let(:only) { ["description_present"] } + describe "without description" do let(:cask_token) { "without-description" } let(:cask) do tmp_cask cask_token.to_s, <<~RUBY @@ -1024,132 +996,131 @@ describe Cask::Audit, :cask do expect(run).to warn_with(/should have a description/) end end + end - context "with description" do - let(:cask_token) { "with-description" } - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask "#{cask_token}" do - version "1.0" - sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" - url "https://brew.sh/\#{version}.zip" - name "Audit" - desc "Cask Auditor" - homepage "https://brew.sh/" - app "Audit.app" - end - RUBY - end + context "with description" do + let(:cask_token) { "with-description" } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask "#{cask_token}" do + version "1.0" + sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" + url "https://brew.sh/\#{version}.zip" + name "Audit" + desc "Cask Auditor" + homepage "https://brew.sh/" + app "Audit.app" + end + RUBY + end - it "passes" do - expect(run).to pass - end + it "passes" do + expect(run).to pass end end - describe "checking verified" do - let(:only) { %w[unnecessary_verified missing_verified no_match required_stanzas] } + context "when the url matches the homepage" do let(:cask_token) { "foo" } - - context "when the url matches the homepage" do - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask '#{cask_token}' do - version '1.0' - sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' - url 'https://foo.brew.sh/foo.zip' - name 'Audit' - desc 'Audit Description' - homepage 'https://foo.brew.sh' - app 'Audit.app' - end - RUBY - end - - it { is_expected.to pass } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask '#{cask_token}' do + version '1.0' + sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' + url 'https://foo.brew.sh/foo.zip' + name 'Audit' + desc 'Audit Description' + homepage 'https://foo.brew.sh' + app 'Audit.app' + end + RUBY end - context "when the url does not match the homepage" do - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask '#{cask_token}' do - version "1.8.0_72,8.13.0.5" - sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" - url "https://brew.sh/foo-\#{version.after_comma}.zip" - name "Audit" - desc "Audit Description" - homepage "https://foo.example.org" - app "Audit.app" - end - RUBY - end + it { is_expected.to pass } + end - it { is_expected.to fail_with(/a 'verified' parameter has to be added/) } + context "when the url does not match the homepage" do + let(:cask_token) { "foo" } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask '#{cask_token}' do + version "1.8.0_72,8.13.0.5" + sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" + url "https://brew.sh/foo-\#{version.after_comma}.zip" + name "Audit" + desc "Audit Description" + homepage "https://foo.example.org" + app "Audit.app" + end + RUBY end - context "when the url does not match the homepage with verified" do - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask "#{cask_token}" do - version "1.8.0_72,8.13.0.5" - sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" - url "https://brew.sh/foo-\#{version.after_comma}.zip", verified: "brew.sh" - name "Audit" - desc "Audit Description" - homepage "https://foo.example.org" - app "Audit.app" - end - RUBY - end + it { is_expected.to fail_with(/a 'verified' parameter has to be added/) } + end - it { is_expected.to pass } + context "when the url does not match the homepage with verified" do + let(:cask_token) { "foo" } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask "#{cask_token}" do + version "1.8.0_72,8.13.0.5" + sha256 "8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a" + url "https://brew.sh/foo-\#{version.after_comma}.zip", verified: "brew.sh" + name "Audit" + desc "Audit Description" + homepage "https://foo.example.org" + app "Audit.app" + end + RUBY end - context "when there is no homepage" do - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask '#{cask_token}' do - version '1.8.0_72,8.13.0.5' - sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' - url 'https://brew.sh/foo.zip' - name 'Audit' - desc 'Audit Description' - app 'Audit.app' - end - RUBY - end + it { is_expected.to pass } + end - it { is_expected.to fail_with(/a homepage stanza is required/) } + context "when there is no homepage" do + let(:cask_token) { "foo" } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask '#{cask_token}' do + version '1.8.0_72,8.13.0.5' + sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' + url 'https://brew.sh/foo.zip' + name 'Audit' + desc 'Audit Description' + app 'Audit.app' + end + RUBY end - context "when url is lazy" do - let(:strict) { true } - let(:cask_token) { "with-lazy" } - let(:cask) do - tmp_cask cask_token.to_s, <<~RUBY - cask '#{cask_token}' do - version '1.8.0_72,8.13.0.5' - sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' - url do - ['https://brew.sh/foo.zip', {referer: 'https://example.com', cookies: {'foo' => 'bar'}}] - end - name 'Audit' - desc 'Audit Description' - homepage 'https://brew.sh' - app 'Audit.app' + it { is_expected.to fail_with(/a homepage stanza is required/) } + end + + context "when url is lazy" do + let(:strict) { true } + let(:cask_token) { "with-lazy" } + let(:cask) do + tmp_cask cask_token.to_s, <<~RUBY + cask '#{cask_token}' do + version '1.8.0_72,8.13.0.5' + sha256 '8dd95daa037ac02455435446ec7bc737b34567afe9156af7d20b2a83805c1d8a' + url do + ['https://brew.sh/foo.zip', {referer: 'https://example.com', cookies: {'foo' => 'bar'}}] end - RUBY - end + name 'Audit' + desc 'Audit Description' + homepage 'https://brew.sh' + app 'Audit.app' + end + RUBY + end - it { is_expected.to pass } + it { is_expected.to pass } - it "receives a referer" do - expect(audit.cask.url.referer).to eq "https://example.com" - end + it "receives a referer" do + expect(audit.cask.url.referer).to eq "https://example.com" + end - it "receives cookies" do - expect(audit.cask.url.cookies).to eq "foo" => "bar" - end + it "receives cookies" do + expect(audit.cask.url.cookies).to eq "foo" => "bar" end end end