Skip to content

brew audit --tap=… on Linux eagerly loads casks before its own next [] if os == :linux filter #22148

@moonfruit

Description

@moonfruit

brew doctor output

Your system is ready to brew.

(reproduced inside the official ghcr.io/homebrew/brew:main Docker image used by brew test-bot on GitHub Actions; doctor output on the runner is clean aside from unrelated Tier notices)

Verification

  • I ran brew update twice and am still able to reproduce my issue.
  • My "brew doctor output" above says Your system is ready to brew or a definitely unrelated Tier message.
  • This issue's title and/or description do not reference a single formula e.g. brew install wget.

brew config output

HOMEBREW_VERSION: 5.1.9-6-gca9228e
ORIGIN: https://github.com/Homebrew/brew
Branch: main
HOMEBREW_PREFIX: /home/linuxbrew/.linuxbrew
Homebrew Ruby: 4.0.3 => /home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/vendor/portable-ruby/4.0.3/bin/ruby
CPU: quad-core 64-bit icelake
Kernel: Linux 6.17.0-1010-azure x86_64 GNU/Linux
OS: Ubuntu 22.04.5 LTS
Host glibc: 2.35
Host libstdc++: 6.0.30

(captured from the ghcr.io/homebrew/brew:main container running on ubuntu-latest; the same failure also reproduces on ubuntu-24.04-arm)

What were you trying to do (and why)?

Run brew test-bot --only-tap-syntax against a third-party tap on Linux as part of a GitHub Actions matrix job (macOS + ubuntu-latest + ubuntu-24.04-arm). The tap contains macOS-only casks that legitimately use the sha256 arm: …, intel: … shorthand together with depends_on macos: ….

What happened (include all command output)?

==> brew test-bot --only-tap-syntax
…
Error: Cask 'sfm@alpha' definition is invalid: invalid 'sha256' value: nil
Error: 1 failed step!

Failing run: https://github.com/moonfruit/homebrew-tap/actions/runs/25418501691/job/72730024519

The offending cask: https://github.com/moonfruit/homebrew-tap/blob/cask/Casks/sfm%40alpha.rb

cask "sfm@alpha" do
  arch arm: "Apple", intel: "Intel"

  version "1.14.0-alpha.21"
  sha256 arm:   "acc0eb4…",
         intel: "539c681…"

  url "https://github.com/SagerNet/sing-box/releases/download/v#{version}/SFM-#{version}-#{arch}.pkg"
  
  depends_on macos: ">= :ventura"
  
end

What did you expect to happen?

brew test-bot --only-tap-syntax should not abort on Linux for a cask that:

  1. is gated by depends_on macos: …, and
  2. uses the sha256 arm:/intel: shorthand which is documented as a macOS-only convenience (intel: is internally aliased to x86_64:, and sha256 only resolves through the macos: branch of on_system_conditional for those keywords).

brew audit already knows it must not audit casks on Linux — Library/Homebrew/dev-cmd/audit.rb does:

errors = os_arch_combinations.flat_map do |os, arch|
  next [] if os == :linux
  
end

…but the cask is loaded eagerly, before that filter, when --tap= is used:

https://github.com/Homebrew/brew/blob/master/Library/Homebrew/dev-cmd/audit.rb#L141-L147

elsif args.tap
  Tap.fetch(args.tap).then do |tap|
    [
      tap.formula_files.map { |path| Formulary.factory(path) },
      tap.cask_files.map { |path| Cask::CaskLoader.load(path) },
    ]
  end

On Linux that load runs in the host's OS context, where Cask::DSL#sha256(arm:, intel:) resolves through on_system_conditional(linux: on_arch_conditional(arm: arm64_linux, intel: x86_64_linux)) (Library/Homebrew/cask/dsl.rb:503-525). Because the cask only sets arm:/intel:, both arm64_linux and x86_64_linux are nil, so sha256 raises CaskInvalidError: invalid 'sha256' value: nil — even though the audit code itself would have skipped this cask on Linux a few lines later.

Compare with Readall.valid_casks?, which is overridden only on macOS (Library/Homebrew/extend/os/mac/readall.rb); on Linux the base implementation returns true without loading any cask, so brew readall --aliases --os=all --arch=all <tap> is unaffected. The eager load in dev-cmd/audit.rb is the only step in --only-tap-syntax that actually fails.

Step-by-step reproduction instructions (by running brew commands)

Inside ghcr.io/homebrew/brew:main (or any Linux brew install):

brew tap moonfruit/tap https://github.com/moonfruit/homebrew-tap
brew test-bot --only-tap-syntax
# or, more directly:
brew audit --except=installed --tap=moonfruit/tap

Result:

Error: Cask 'sfm@alpha' definition is invalid: invalid 'sha256' value: nil

A minimal cask that triggers the same failure on Linux without any tap setup:

cask \"macos-only-example\" do
  version \"1.0\"
  sha256 arm:   \"0000000000000000000000000000000000000000000000000000000000000000\",
         intel: \"1111111111111111111111111111111111111111111111111111111111111111\"
  url \"https://example.invalid/x.pkg\"
  name \"Example\"
  desc \"macOS-only cask\"
  homepage \"https://example.invalid/\"
  depends_on macos: \">= :ventura\"
  pkg \"x.pkg\"
end

Suggested fix

Either:

  1. defer loading cask files until after the os == :linux filter (e.g. wrap the load in a SimulateSystem.with(os: :macos, arch:) block, or load with paths instead of objects and only instantiate inside the per-OS loop), or
  2. on Linux, skip cask collection entirely under --tap= (mirroring what Readall.valid_casks? already does for brew readall).

Today the only workaround in tap CI is to replace --only-tap-syntax on Linux with manual brew style + brew readall and to drop brew audit --tap= (or to enumerate every formula by name), which is awkward for taps that legitimately mix macOS-only casks with cross-platform formulae.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions