Fix symlinked tap loading issue in cask loader
Co-authored-by: MikeMcQuaid <125011+MikeMcQuaid@users.noreply.github.com>
This commit is contained in:
parent
07091cfbea
commit
6297f98d06
@ -6,6 +6,7 @@ require "cask/cask"
|
||||
require "uri"
|
||||
require "utils/curl"
|
||||
require "utils/output"
|
||||
require "utils/path"
|
||||
require "extend/hash/keys"
|
||||
require "api"
|
||||
|
||||
@ -112,9 +113,7 @@ module Cask
|
||||
|
||||
return unless path.expand_path.exist?
|
||||
return if invalid_path?(path)
|
||||
|
||||
return if Homebrew::EnvConfig.forbid_packages_from_paths? &&
|
||||
!path.realpath.to_s.start_with?("#{Caskroom.path}/", "#{HOMEBREW_LIBRARY}/Taps/")
|
||||
return unless ::Utils::Path.loadable_package_path?(path, :cask)
|
||||
|
||||
new(path)
|
||||
end
|
||||
|
@ -7,6 +7,7 @@ require "tab"
|
||||
require "utils"
|
||||
require "utils/bottles"
|
||||
require "utils/output"
|
||||
require "utils/path"
|
||||
require "service"
|
||||
require "utils/curl"
|
||||
require "deprecate_disable"
|
||||
@ -727,29 +728,7 @@ module Formulary
|
||||
end
|
||||
|
||||
return unless path.expand_path.exist?
|
||||
|
||||
if Homebrew::EnvConfig.forbid_packages_from_paths?
|
||||
path_realpath = path.realpath.to_s
|
||||
path_string = path.to_s
|
||||
if (path_realpath.end_with?(".rb") || path_string.end_with?(".rb")) &&
|
||||
!path_realpath.start_with?("#{HOMEBREW_CELLAR}/", "#{HOMEBREW_LIBRARY}/Taps/") &&
|
||||
!path_string.start_with?("#{HOMEBREW_CELLAR}/", "#{HOMEBREW_LIBRARY}/Taps/")
|
||||
if path_string.include?("./") || path_string.end_with?(".rb") || path_string.count("/") != 2
|
||||
raise <<~WARNING
|
||||
Homebrew requires formulae to be in a tap, rejecting:
|
||||
#{path_string} (#{path_realpath})
|
||||
|
||||
To create a tap, run e.g.
|
||||
brew tap-new <user|org>/<repository>
|
||||
To create a formula in a tap run e.g.
|
||||
brew create <url> --tap=<user|org>/<repository>
|
||||
WARNING
|
||||
elsif path_string.count("/") == 2
|
||||
# Looks like a tap, let's quietly return but not error.
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
return unless ::Utils::Path.loadable_package_path?(path, :formula)
|
||||
|
||||
if (tap = Tap.from_path(path))
|
||||
# Only treat symlinks in taps as aliases.
|
||||
|
@ -236,4 +236,73 @@ RSpec.describe Cask::CaskLoader, :cask do
|
||||
expect(described_class.load_prefer_installed("test-cask").tap).to eq(foo_tap)
|
||||
end
|
||||
end
|
||||
|
||||
describe "FromPathLoader with symlinked taps" do
|
||||
let(:cask_token) { "testcask" }
|
||||
let(:tmpdir) { mktmpdir }
|
||||
let(:real_tap_path) { tmpdir / "real_tap" }
|
||||
let(:homebrew_prefix) { tmpdir / "homebrew" }
|
||||
let(:taps_dir) { homebrew_prefix / "Library" / "Taps" / "testuser" }
|
||||
let(:symlinked_tap_path) { taps_dir / "homebrew-testtap" }
|
||||
let(:cask_file_path) { symlinked_tap_path / "Casks" / "#{cask_token}.rb" }
|
||||
let(:cask_content) do
|
||||
<<~RUBY
|
||||
cask "#{cask_token}" do
|
||||
version "1.0.0"
|
||||
sha256 "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
||||
|
||||
url "https://example.com/#{cask_token}-\#{version}.dmg"
|
||||
name "Test Cask"
|
||||
desc "A test cask for symlink testing"
|
||||
homepage "https://example.com"
|
||||
|
||||
app "TestCask.app"
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
after do
|
||||
tmpdir.rmtree if tmpdir.exist?
|
||||
end
|
||||
|
||||
before do
|
||||
# Create real tap directory structure
|
||||
(real_tap_path / "Casks").mkpath
|
||||
(real_tap_path / "Casks" / "#{cask_token}.rb").write(cask_content)
|
||||
|
||||
# Create homebrew prefix structure
|
||||
taps_dir.mkpath
|
||||
|
||||
# Create symlink to the tap (this simulates what setup-homebrew does)
|
||||
symlinked_tap_path.make_symlink(real_tap_path)
|
||||
|
||||
# Set HOMEBREW_LIBRARY to our test prefix for the security check
|
||||
stub_const("HOMEBREW_LIBRARY", homebrew_prefix / "Library")
|
||||
allow(Homebrew::EnvConfig).to receive(:forbid_packages_from_paths?).and_return(true)
|
||||
end
|
||||
|
||||
context "when HOMEBREW_FORBID_PACKAGES_FROM_PATHS is enabled" do
|
||||
it "allows loading casks from symlinked taps" do
|
||||
loader = Cask::CaskLoader::FromPathLoader.try_new(cask_file_path)
|
||||
expect(loader).not_to be_nil
|
||||
expect(loader).to be_a(Cask::CaskLoader::FromPathLoader)
|
||||
|
||||
cask = loader.load(config: nil)
|
||||
expect(cask.token).to eq(cask_token)
|
||||
expect(cask.version).to eq(Version.new("1.0.0"))
|
||||
end
|
||||
end
|
||||
|
||||
context "when HOMEBREW_FORBID_PACKAGES_FROM_PATHS is disabled" do
|
||||
before do
|
||||
allow(Homebrew::EnvConfig).to receive(:forbid_packages_from_paths?).and_return(false)
|
||||
end
|
||||
|
||||
it "allows loading casks from symlinked taps" do
|
||||
loader = Cask::CaskLoader::FromPathLoader.try_new(cask_file_path)
|
||||
expect(loader).not_to be_nil
|
||||
expect(loader).to be_a(Cask::CaskLoader::FromPathLoader)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -10,5 +10,44 @@ module Utils
|
||||
child_pathname.ascend { |p| return true if p == parent_pathname }
|
||||
false
|
||||
end
|
||||
|
||||
sig { params(path: Pathname, package_type: Symbol).returns(T::Boolean) }
|
||||
def self.loadable_package_path?(path, package_type)
|
||||
return true unless Homebrew::EnvConfig.forbid_packages_from_paths?
|
||||
|
||||
path_realpath = path.realpath.to_s
|
||||
path_string = path.to_s
|
||||
|
||||
allowed_paths = ["#{HOMEBREW_LIBRARY}/Taps/"]
|
||||
allowed_paths << if package_type == :formula
|
||||
"#{HOMEBREW_CELLAR}/"
|
||||
else
|
||||
"#{Cask::Caskroom.path}/"
|
||||
end
|
||||
|
||||
return true if !path_realpath.end_with?(".rb") && !path_string.end_with?(".rb")
|
||||
return true if allowed_paths.any? { |path| path_realpath.start_with?(path) }
|
||||
return true if allowed_paths.any? { |path| path_string.start_with?(path) }
|
||||
|
||||
# Looks like a local path, Ruby file and not a tap.
|
||||
if path_string.include?("./") || path_string.end_with?(".rb") || path_string.count("/") != 2
|
||||
package_type_plural = Utils.pluralize(package_type.to_s, 2)
|
||||
path_realpath_if_different = " (#{path_realpath})" if path_realpath != path_string
|
||||
create_flag = " --cask" if package_type == :cask
|
||||
|
||||
raise <<~WARNING
|
||||
Homebrew requires #{package_type_plural} to be in a tap, rejecting:
|
||||
#{path_string}#{path_realpath_if_different}
|
||||
|
||||
To create a tap, run e.g.
|
||||
brew tap-new <user|org>/<repository>
|
||||
To create a #{package_type} in a tap run e.g.
|
||||
brew create#{create_flag} <url> --tap=<user|org>/<repository>
|
||||
WARNING
|
||||
else
|
||||
# Looks like a tap, let's quietly reject but not error.
|
||||
path_string.count("/") != 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user