Merge pull request #4278 from commitay/audit-sourceforge-appcast

cask audit: check for sourceforge appcast
This commit is contained in:
commitay 2018-06-07 10:42:30 +10:00 committed by GitHub
commit bb7ec947e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 48 deletions

View File

@ -34,7 +34,7 @@ module Hbc
check_single_pre_postflight check_single_pre_postflight
check_single_uninstall_zap check_single_uninstall_zap
check_untrusted_pkg check_untrusted_pkg
check_github_releases_appcast check_hosting_with_appcast
check_latest_with_appcast check_latest_with_appcast
check_stanza_requires_uninstall check_stanza_requires_uninstall
self self
@ -246,11 +246,23 @@ module Hbc
add_warning "Casks with an appcast should not use version :latest" add_warning "Casks with an appcast should not use version :latest"
end end
def check_github_releases_appcast def check_hosting_with_appcast
return if cask.appcast return if cask.appcast
check_github_releases_appcast
check_sourceforge_appcast
end
def check_github_releases_appcast
return unless cask.url.to_s =~ %r{github.com/([^/]+)/([^/]+)/releases/download/(\S+)} return unless cask.url.to_s =~ %r{github.com/([^/]+)/([^/]+)/releases/download/(\S+)}
add_warning "Cask uses GitHub releases, please add an appcast. See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/appcast.md" add_warning "Download uses GitHub releases, please add an appcast. See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/appcast.md"
end
def check_sourceforge_appcast
return if cask.version.latest?
return unless cask.url.to_s =~ %r{sourceforge.net/(\S+)}
add_warning "Download is hosted on SourceForge, please add an appcast. See https://github.com/Homebrew/homebrew-cask/blob/master/doc/cask_language_reference/stanzas/appcast.md"
end end
def check_url def check_url

View File

@ -94,190 +94,190 @@ describe Hbc::Audit, :cask do
end end
describe "pkg allow_untrusted checks" do describe "pkg allow_untrusted checks" do
let(:error_msg) { "allow_untrusted is not permitted in official Homebrew-Cask taps" } let(:warning_msg) { "allow_untrusted is not permitted in official Homebrew-Cask taps" }
context "when the Cask has no pkg stanza" do context "when the Cask has no pkg stanza" do
let(:cask_token) { "basic-cask" } let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask does not have allow_untrusted" do context "when the Cask does not have allow_untrusted" do
let(:cask_token) { "with-uninstall-pkgutil" } let(:cask_token) { "with-uninstall-pkgutil" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has allow_untrusted" do context "when the Cask has allow_untrusted" do
let(:cask_token) { "with-allow-untrusted" } let(:cask_token) { "with-allow-untrusted" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "when the Cask stanza requires uninstall" do describe "when the Cask stanza requires uninstall" do
let(:error_msg) { "installer and pkg stanzas require an uninstall stanza" } let(:warning_msg) { "installer and pkg stanzas require an uninstall stanza" }
context "when the Cask does not require an uninstall" do context "when the Cask does not require an uninstall" do
let(:cask_token) { "basic-cask" } let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the pkg Cask has an uninstall" do context "when the pkg Cask has an uninstall" do
let(:cask_token) { "with-uninstall-pkgutil" } let(:cask_token) { "with-uninstall-pkgutil" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the installer Cask has an uninstall" do context "when the installer Cask has an uninstall" do
let(:cask_token) { "installer-with-uninstall" } let(:cask_token) { "installer-with-uninstall" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the installer Cask does not have an uninstall" do context "when the installer Cask does not have an uninstall" do
let(:cask_token) { "with-installer-manual" } let(:cask_token) { "with-installer-manual" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
context "when the pkg Cask does not have an uninstall" do context "when the pkg Cask does not have an uninstall" do
let(:cask_token) { "pkg-without-uninstall" } let(:cask_token) { "pkg-without-uninstall" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "preflight stanza checks" do describe "preflight stanza checks" do
let(:error_msg) { "only a single preflight stanza is allowed" } let(:warning_msg) { "only a single preflight stanza is allowed" }
context "when the Cask has no preflight stanza" do context "when the Cask has no preflight stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one preflight stanza" do context "when the Cask has only one preflight stanza" do
let(:cask_token) { "with-preflight" } let(:cask_token) { "with-preflight" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple preflight stanzas" do context "when the Cask has multiple preflight stanzas" do
let(:cask_token) { "with-preflight-multi" } let(:cask_token) { "with-preflight-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "uninstall_postflight stanza checks" do describe "uninstall_postflight stanza checks" do
let(:error_msg) { "only a single postflight stanza is allowed" } let(:warning_msg) { "only a single postflight stanza is allowed" }
context "when the Cask has no postflight stanza" do context "when the Cask has no postflight stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one postflight stanza" do context "when the Cask has only one postflight stanza" do
let(:cask_token) { "with-postflight" } let(:cask_token) { "with-postflight" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple postflight stanzas" do context "when the Cask has multiple postflight stanzas" do
let(:cask_token) { "with-postflight-multi" } let(:cask_token) { "with-postflight-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "uninstall stanza checks" do describe "uninstall stanza checks" do
let(:error_msg) { "only a single uninstall stanza is allowed" } let(:warning_msg) { "only a single uninstall stanza is allowed" }
context "when the Cask has no uninstall stanza" do context "when the Cask has no uninstall stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one uninstall stanza" do context "when the Cask has only one uninstall stanza" do
let(:cask_token) { "with-uninstall-rmdir" } let(:cask_token) { "with-uninstall-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple uninstall stanzas" do context "when the Cask has multiple uninstall stanzas" do
let(:cask_token) { "with-uninstall-multi" } let(:cask_token) { "with-uninstall-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "uninstall_preflight stanza checks" do describe "uninstall_preflight stanza checks" do
let(:error_msg) { "only a single uninstall_preflight stanza is allowed" } let(:warning_msg) { "only a single uninstall_preflight stanza is allowed" }
context "when the Cask has no uninstall_preflight stanza" do context "when the Cask has no uninstall_preflight stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one uninstall_preflight stanza" do context "when the Cask has only one uninstall_preflight stanza" do
let(:cask_token) { "with-uninstall-preflight" } let(:cask_token) { "with-uninstall-preflight" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple uninstall_preflight stanzas" do context "when the Cask has multiple uninstall_preflight stanzas" do
let(:cask_token) { "with-uninstall-preflight-multi" } let(:cask_token) { "with-uninstall-preflight-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "uninstall_postflight stanza checks" do describe "uninstall_postflight stanza checks" do
let(:error_msg) { "only a single uninstall_postflight stanza is allowed" } let(:warning_msg) { "only a single uninstall_postflight stanza is allowed" }
context "when the Cask has no uninstall_postflight stanza" do context "when the Cask has no uninstall_postflight stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one uninstall_postflight stanza" do context "when the Cask has only one uninstall_postflight stanza" do
let(:cask_token) { "with-uninstall-postflight" } let(:cask_token) { "with-uninstall-postflight" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple uninstall_postflight stanzas" do context "when the Cask has multiple uninstall_postflight stanzas" do
let(:cask_token) { "with-uninstall-postflight-multi" } let(:cask_token) { "with-uninstall-postflight-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
describe "zap stanza checks" do describe "zap stanza checks" do
let(:error_msg) { "only a single zap stanza is allowed" } let(:warning_msg) { "only a single zap stanza is allowed" }
context "when the Cask has no zap stanza" do context "when the Cask has no zap stanza" do
let(:cask_token) { "with-uninstall-rmdir" } let(:cask_token) { "with-uninstall-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has only one zap stanza" do context "when the Cask has only one zap stanza" do
let(:cask_token) { "with-zap-rmdir" } let(:cask_token) { "with-zap-rmdir" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask has multiple zap stanzas" do context "when the Cask has multiple zap stanzas" do
let(:cask_token) { "with-zap-multi" } let(:cask_token) { "with-zap-multi" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end
@ -439,46 +439,68 @@ describe Hbc::Audit, :cask do
end end
describe "GitHub releases appcast check" do describe "GitHub releases appcast check" do
let(:error_msg) { /Cask uses GitHub releases/ } let(:appcast_warning) { /Download uses GitHub releases/ }
context "when the Cask does not use GitHub releases" do context "when the download does not use GitHub releases" do
let(:cask_token) { "basic-cask" } let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(appcast_warning) }
end end
context "when the Cask uses GitHub releases and has an appcast" do context "when the download uses GitHub releases and has an appcast" do
let(:cask_token) { "github-with-appcast" } let(:cask_token) { "github-with-appcast" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(appcast_warning) }
end end
context "when the Cask uses GitHub releases and does not have an appcast" do context "when the download uses GitHub releases and does not have an appcast" do
let(:cask_token) { "github-without-appcast" } let(:cask_token) { "github-without-appcast" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(appcast_warning) }
end
end
describe "SourceForge appcast check" do
let(:appcast_warning) { /Download is hosted on SourceForge/ }
context "when the download is not hosted on SourceForge" do
let(:cask_token) { "basic-cask" }
it { is_expected.not_to warn_with(appcast_warning) }
end
context "when the download is hosted on SourceForge and has an appcast" do
let(:cask_token) { "sourceforge-with-appcast" }
it { is_expected.not_to warn_with(appcast_warning) }
end
context "when the download is hosted on SourceForge and does not have an appcast" do
let(:cask_token) { "sourceforge-correct-url-format" }
it { is_expected.to warn_with(appcast_warning) }
end end
end end
describe "latest with appcast checks" do describe "latest with appcast checks" do
let(:error_msg) { "Casks with an appcast should not use version :latest" } let(:warning_msg) { "Casks with an appcast should not use version :latest" }
context "when the Cask is :latest and does not have an appcast" do context "when the Cask is :latest and does not have an appcast" do
let(:cask_token) { "version-latest" } let(:cask_token) { "version-latest" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask is versioned and has an appcast" do context "when the Cask is versioned and has an appcast" do
let(:cask_token) { "with-appcast" } let(:cask_token) { "with-appcast" }
it { is_expected.not_to warn_with(error_msg) } it { is_expected.not_to warn_with(warning_msg) }
end end
context "when the Cask is :latest and has an appcast" do context "when the Cask is :latest and has an appcast" do
let(:cask_token) { "latest-with-appcast" } let(:cask_token) { "latest-with-appcast" }
it { is_expected.to warn_with(error_msg) } it { is_expected.to warn_with(warning_msg) }
end end
end end

View File

@ -0,0 +1,8 @@
cask 'sourceforge-with-appcast' do
version '1.2.3'
url 'https://downloads.sourceforge.net/something/Something-1.2.3.dmg'
appcast 'https://sourceforge.net/projects/something/rss',
checkpoint: '407fb59baa4b9eb7651d9243b89c30b7481590947ef78bd5a4c24f5810f56531'
homepage 'https://sourceforge.net/projects/something/'
end