brew doctor output
Your system is ready to brew.
Verification
brew config output
HOMEBREW_VERSION: 6.0.0-2-g1cd9e81
ORIGIN: https://github.com/Homebrew/brew
HEAD: 1cd9e81cc250a12f586b590ebbff64bb07771d83
Last commit: 2 hours ago
Branch: main
Core tap: N/A
Core cask tap: N/A
HOMEBREW_PREFIX: /opt/homebrew
HOMEBREW_BAT_THEME: base16
HOMEBREW_CASK_OPTS: []
HOMEBREW_DOWNLOAD_CONCURRENCY: 16
HOMEBREW_EDITOR: nvim
HOMEBREW_FORBID_PACKAGES_FROM_PATHS: set
HOMEBREW_MAKE_JOBS: 8
HOMEBREW_REQUIRE_TAP_TRUST: set
Homebrew Ruby: 4.0.5 => /opt/homebrew/Library/Homebrew/vendor/portable-ruby/4.0.5_1/bin/ruby
CPU: octa-core 64-bit arm_blizzard_avalanche
Clang: 21.0.0 build 2100
Git: 2.50.1 => /Library/Developer/CommandLineTools/usr/bin/git
Curl: 8.7.1 => /usr/bin/curl
macOS: 26.5-arm64
CLT: 26.5.0.0.1777544298
Xcode: N/A
Rosetta 2: false
What were you trying to do (and why)?
I wanted to use the new tap trust mechanism declaratively from my Brewfile, so that machines provisioned from it do not need per-machine brew trust --tap calls:
tap "oven-sh/bun", trusted: true
brew "oven-sh/bun/bun"
What happened (include all command output)?
The trusted: true option on tap entries without a custom remote is silently dropped: the tap is not added to trust.json, and every formula from it produces a trust warning during the brew bundle upgrade check:
Warning: Cannot check whether oven-sh/bun/bun is outdated because its tap is not trusted. Run `brew trust --formula oven-sh/bun/bun` to trust it.
The cause is in the Brewfile DSL; Dsl#tap accepts only positional parameters:
|
sig { params(name: String, clone_target: T.nilable(String), options: Homebrew::Bundle::EntryOptions).void } |
|
def tap(name, clone_target = nil, options = {}) |
|
options[:clone_target] = clone_target |
|
name = Homebrew::Bundle::Dsl.sanitize_tap_name(name) |
|
@entries << Entry.new(:tap, name, options) |
|
end |
Since the method declares no keyword parameters, Ruby converts trusted: true into a positional Hash, which fills the clone_target slot while options stays empty:
tap "foo/bar", trusted: true
# entry options: {clone_target: {trusted: true}}
tap "baz/qux", "https://example.com/qux", trusted: true
# entry options: {trusted: true, clone_target: "https://example.com/qux"}
So Installer.apply_trust! never sees options[:trusted] for "by name" taps, and the option only survives when a remote URL happens to occupy the clone_target position (which is also why the misplaced Hash goes unnoticed: for already-installed taps clone_target is never used).
This also breaks dump round-tripping, since the dumper emits exactly this form for any explicitly trusted tap, with or without a remote:
|
tapline = "tap \"#{tap.name}\"#{remote}" |
|
tapline += ", trusted: true" if Homebrew::Trust.explicitly_trusted_tap?(tap) |
brew trust --tap foo/bar followed by brew bundle dump therefore produces a Brewfile whose trust information is lost when parsed back.
The "by name" case is clearly intended to work; there is a dedicated test for it, but it constructs the Dsl::Entry by hand and thus bypasses the parser:
|
it "trusts `trusted: true` taps by name" do |
|
tap_entry = Homebrew::Bundle::Dsl::Entry.new(:tap, "thirdparty/tap", { trusted: true }) |
|
|
|
expect(Homebrew::Trust).to receive(:trust!).with(:tap, "thirdparty/tap").and_return(true) |
|
|
|
described_class.install!([tap_entry], quiet: true) |
|
end |
dsl_spec.rb has no trusted: coverage at all, and the one dump test asserting trusted: true output happens to use a tap with a custom remote, so the gap is invisible to CI. Making Dsl#tap accept keyword arguments (plus a parser-level or dump round-trip test) should cover it.
What did you expect to happen?
I expected tap "oven-sh/bun", trusted: true to behave like brew trust --tap oven-sh/bun: the tap gets recorded in trust.json and formulae from it produce no trust warnings during brew bundle.
Step-by-step reproduction instructions (by running brew commands)
printf 'tap "oven-sh/bun", trusted: true\nbrew "oven-sh/bun/bun"\n' > Brewfile
brew bundle install --file Brewfile
brew trust --json v1
brew bundle install prints the trust warning quoted above during its upgrade check, and the brew trust --json v1 output shows that oven-sh/bun was not added to the trusted taps. Adding a custom remote as the second argument (tap "oven-sh/bun", "https://github.com/oven-sh/homebrew-bun", trusted: true) makes the same option work.
brew doctoroutputVerification
brew updatetwice and am still able to reproduce my issue.brew doctoroutput" above saysYour system is ready to brewor a definitely unrelatedTiermessage.brew install wget. If they do, open an issue at https://github.com/Homebrew/homebrew-core/issues/new/choose instead.brew configoutputWhat were you trying to do (and why)?
I wanted to use the new tap trust mechanism declaratively from my Brewfile, so that machines provisioned from it do not need per-machine
brew trust --tapcalls:What happened (include all command output)?
The
trusted: trueoption ontapentries without a custom remote is silently dropped: the tap is not added totrust.json, and every formula from it produces a trust warning during thebrew bundleupgrade check:The cause is in the Brewfile DSL;
Dsl#tapaccepts only positional parameters:brew/Library/Homebrew/bundle/dsl.rb
Lines 86 to 91 in 1cd9e81
Since the method declares no keyword parameters, Ruby converts
trusted: trueinto a positionalHash, which fills theclone_targetslot whileoptionsstays empty:So
Installer.apply_trust!never seesoptions[:trusted]for "by name" taps, and the option only survives when a remote URL happens to occupy theclone_targetposition (which is also why the misplacedHashgoes unnoticed: for already-installed tapsclone_targetis never used).This also breaks dump round-tripping, since the dumper emits exactly this form for any explicitly trusted tap, with or without a remote:
brew/Library/Homebrew/bundle/tap.rb
Lines 94 to 95 in 1cd9e81
brew trust --tap foo/barfollowed bybrew bundle dumptherefore produces a Brewfile whose trust information is lost when parsed back.The "by name" case is clearly intended to work; there is a dedicated test for it, but it constructs the
Dsl::Entryby hand and thus bypasses the parser:brew/Library/Homebrew/test/bundle/installer_spec.rb
Lines 112 to 118 in 1cd9e81
dsl_spec.rbhas notrusted:coverage at all, and the one dump test assertingtrusted: trueoutput happens to use a tap with a custom remote, so the gap is invisible to CI. MakingDsl#tapaccept keyword arguments (plus a parser-level or dump round-trip test) should cover it.What did you expect to happen?
I expected
tap "oven-sh/bun", trusted: trueto behave likebrew trust --tap oven-sh/bun: the tap gets recorded intrust.jsonand formulae from it produce no trust warnings duringbrew bundle.Step-by-step reproduction instructions (by running
brewcommands)brew bundle installprints the trust warning quoted above during its upgrade check, and thebrew trust --json v1output shows thatoven-sh/bunwas not added to the trusted taps. Adding a custom remote as the second argument (tap "oven-sh/bun", "https://github.com/oven-sh/homebrew-bun", trusted: true) makes the same option work.