Limit implicit item trust to install commands

- Match implicit trust to the documented installation behaviour.
  Other commands require existing trust for the tap or item.
- Retain the dispatched name in `Homebrew.running_command` and limit
  `ARGV` allowances to `install`, `reinstall` and `upgrade`, which
  announce and persist item trust.
- Preserve early formula loading for command-specific options before
  `trust_fully_qualified_items!` runs.
- Cover formula and cask loads, both `--tap` forms and existing alias,
  rename and external command behaviour.
This commit is contained in:
Mike McQuaid committed 2026-10-24 18:58:00 +01:00
1 parent e92663d173
commit 271fe96061
3 files changed
+82 -27

No files matched your search

+4
View File
@@ -128,8 +128,12 @@ module Homebrew
ENV.fetch("HOMEBREW_AUTO_UPDATE_COMMAND", false).present?
end
sig { returns(T.nilable(String)) }
attr_reader :running_command
sig { params(cmd: T.nilable(String)).void }
def running_command=(cmd)
@running_command = T.let(cmd, T.nilable(String))
@running_command_with_args = T.let("#{cmd} #{ARGV.join(" ")}", T.nilable(String))
end
+77 -27
View File
@@ -1,6 +1,7 @@
# typed: strict
# frozen_string_literal: true
require "cask/cask_loader"
require "formulary"
require "tap"
require "trust"
@@ -319,6 +320,7 @@ RSpec.describe Homebrew::Trust, :trust_store do
end
before do
allow(Homebrew).to receive(:running_command).and_return("install")
without_partial_double_verification { allow($stderr).to receive(:ohai) }
formula_path.dirname.mkpath
formula_path.write <<~RUBY
@@ -838,41 +840,88 @@ RSpec.describe Homebrew::Trust, :trust_store do
end
end
it "allows explicitly named formula files when trust checks are enabled" do
old_argv = ARGV.dup
tap = Tap.fetch("thirdparty", "foo")
formula_path = tap.formula_dir/"default-trust.rb"
formula_path.dirname.mkpath
shared_examples "explicit formula installation" do |command|
T.bind(self, T.class_of(RSpec::Core::ExampleGroup))
ARGV.replace(["thirdparty/foo/default-trust"])
expect(described_class.trusted_formula_file?(formula_path)).to be(true)
it "allows explicitly named formula files for #{command}" do
old_argv = ARGV.dup
tap = Tap.fetch("thirdparty", "foo")
formula_path = tap.formula_dir/"default-trust.rb"
formula_path.dirname.mkpath
allow(Homebrew).to receive(:running_command).and_return(command)
expect(described_class.trusted?(:formula, "thirdparty/foo/default-trust")).to be(false)
ensure
ARGV.replace(old_argv) if old_argv
described_class.clear!(:tap)
described_class.clear!(:formula)
FileUtils.rm_rf HOMEBREW_TAP_DIRECTORY/"thirdparty"
ARGV.replace(["thirdparty/foo/default-trust"])
expect(described_class.trusted_formula_file?(formula_path)).to be(true)
ensure
ARGV.replace(old_argv) if old_argv
FileUtils.rm_rf HOMEBREW_TAP_DIRECTORY/"thirdparty"
end
end
it "allows files from explicitly named taps when trust checks are enabled" do
old_argv = ARGV.dup
tap = Tap.fetch("thirdparty", "foo")
cask_path = tap.cask_dir/"default-trust.rb"
cask_path.dirname.mkpath
it_behaves_like "explicit formula installation", "install"
it_behaves_like "explicit formula installation", "reinstall"
it_behaves_like "explicit formula installation", "upgrade"
ARGV.replace(["--tap", "thirdparty/foo"])
expect(described_class.trusted_cask_file?(cask_path)).to be(true)
shared_examples "untrusted tap arguments" do |arguments|
T.bind(self, T.class_of(RSpec::Core::ExampleGroup))
expect(described_class.trusted?(:tap, "thirdparty/foo")).to be(false)
expect(described_class.trusted?(:cask, "thirdparty/foo/default-trust")).to be(false)
ensure
ARGV.replace(old_argv) if old_argv
described_class.clear!(:tap)
described_class.clear!(:cask)
FileUtils.rm_rf HOMEBREW_TAP_DIRECTORY/"thirdparty"
sig { returns(Pathname) }
let(:formula_path) { Tap.fetch("thirdparty", "foo").formula_dir/"default-trust.rb" }
sig { returns(Pathname) }
let(:cask_path) { Tap.fetch("thirdparty", "foo").cask_dir/"default-trust.rb" }
around do |example|
old_argv = ARGV.dup
ARGV.replace(arguments)
example.run
ensure
ARGV.replace(old_argv)
end
before do
allow(Homebrew).to receive(:running_command).and_return("info")
formula_path.dirname.mkpath
formula_path.write <<~RUBY
class DefaultTrust < Formula
raise "must not evaluate untrusted formula"
end
RUBY
cask_path.dirname.mkpath
cask_path.write <<~RUBY
cask "default-trust" do
raise "must not evaluate untrusted cask"
end
RUBY
end
after do
FileUtils.rm_rf HOMEBREW_TAP_DIRECTORY/"thirdparty"
end
it "does not trust the formula file" do
expect(described_class.trusted_formula_file?(formula_path)).to be(false)
end
it "does not trust the cask file" do
expect(described_class.trusted_cask_file?(cask_path)).to be(false)
end
it "refuses to evaluate the formula" do
expect { Formulary.factory("thirdparty/foo/default-trust") }
.to raise_error(Homebrew::UntrustedTapError)
end
it "refuses to evaluate the cask" do
expect { Cask::CaskLoader.load("thirdparty/foo/default-trust") }
.to raise_error(Homebrew::UntrustedTapError)
end
end
it_behaves_like "untrusted tap arguments", ["thirdparty/foo/default-trust"]
it_behaves_like "untrusted tap arguments", ["--tap=thirdparty/foo"]
it_behaves_like "untrusted tap arguments", ["--tap", "thirdparty/foo"]
it "does not allow files from a tap named as a bare argument when trust checks are enabled" do
old_argv = ARGV.dup
tap = Tap.fetch("thirdparty", "foo")
@@ -889,6 +938,7 @@ RSpec.describe Homebrew::Trust, :trust_store do
end
it "does not allow explicitly named command files when trust checks are enabled" do
allow(Homebrew).to receive(:running_command).and_return("install")
old_argv = ARGV.dup
tap = Tap.fetch("thirdparty", "foo")
command_path = tap.path/"cmd/brew-default-trust.rb"
+1
View File
@@ -589,6 +589,7 @@ module Homebrew
sig { params(type: Symbol, full_name: String, tap: Tap).returns(T::Boolean) }
def self.explicitly_allowed?(type, full_name, tap)
return false if type == :command
return false unless %w[install reinstall upgrade].include?(Homebrew.running_command)
downcased_args = ARGV.map(&:downcase)
downcased_full_name = full_name.downcase