formula_cellar_checks: more granular mismatched_binary_allowlist

Add support for providing more granular glob patterns via the
mismatched_binary_allowlist.json rather than an all-or-nothing option.
This allows catching any unwanted binaries in new releases.

The glob patterns are assumed to be relative to the formula's prefix.
Patterns are matched using fnmatch with flags for:
* `File::FNM_DOTMATCH` to allow matching all files with `**/*`
* `File::FNM_EXTGLOB` to behave like `Dir.glob` for `{a,b}`
* `File::FNM_PATHNAME` to allow restricting `*` across directories

The original file format of `["<formula>"]` should behave similar to
`{"<formula>": "**/*"}`.

Also some changes to add type signature.

Signed-off-by: Michael Cho <michael@michaelcho.dev>
This commit is contained in:
Michael Cho 2024-03-23 22:30:17 -04:00
parent 9a1793a5ad
commit a5160e355f
No known key found for this signature in database
GPG Key ID: 55E85E28A7CD1E85

View File

@ -334,6 +334,7 @@ module FormulaCellarChecks
"No `cpuid` instruction detected. #{formula} should not use `ENV.runtime_cpu_detection`." "No `cpuid` instruction detected. #{formula} should not use `ENV.runtime_cpu_detection`."
end end
sig { params(formula: Formula).returns(T.nilable(String)) }
def check_binary_arches(formula) def check_binary_arches(formula)
return unless formula.prefix.directory? return unless formula.prefix.directory?
@ -347,19 +348,31 @@ module FormulaCellarChecks
compatible_universal_binaries, mismatches = mismatches.partition do |file, arch| compatible_universal_binaries, mismatches = mismatches.partition do |file, arch|
arch == :universal && file.archs.include?(Hardware::CPU.arch) arch == :universal && file.archs.include?(Hardware::CPU.arch)
end.map(&:to_h) # To prevent transformation into nested arrays end
# To prevent transformation into nested arrays
compatible_universal_binaries = compatible_universal_binaries.to_h
mismatches = mismatches.to_h
universal_binaries_expected = if formula.tap.present? && formula.tap.core_tap? universal_binaries_expected = if (formula_tap = formula.tap).present? && formula_tap.core_tap?
formula.tap.audit_exception(:universal_binary_allowlist, formula.name) formula_tap.audit_exception(:universal_binary_allowlist, formula.name)
else else
true true
end end
return if T.must(mismatches).empty? && universal_binaries_expected
mismatches_expected = formula.tap.blank? || mismatches_expected = (formula_tap = formula.tap).blank? ||
formula.tap.audit_exception(:mismatched_binary_allowlist, formula.name) formula_tap.audit_exception(:mismatched_binary_allowlist, formula.name)
return if T.must(compatible_universal_binaries).empty? && mismatches_expected mismatches_expected = [mismatches_expected] if mismatches_expected.is_a?(String)
if mismatches_expected.is_a?(Array)
glob_flags = File::FNM_DOTMATCH | File::FNM_EXTGLOB | File::FNM_PATHNAME
mismatches.delete_if do |file, _arch|
mismatches_expected.any? { |pattern| file.fnmatch?("#{formula.prefix.realpath}/#{pattern}", glob_flags) }
end
mismatches_expected = false
return if mismatches.empty? && compatible_universal_binaries.empty?
end
return if mismatches.empty? && universal_binaries_expected
return if compatible_universal_binaries.empty? && mismatches_expected
return if universal_binaries_expected && mismatches_expected return if universal_binaries_expected && mismatches_expected
s = "" s = ""