From e66df8cfb1fdc82a61825c02e99822f29c23ac2c Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Thu, 1 Aug 2024 11:36:36 -0400 Subject: [PATCH 1/3] attestation: specialize error when `gh` is old See https://github.com/Homebrew/homebrew-core/issues/177384#issuecomment-2263195832. Signed-off-by: William Woodruff --- Library/Homebrew/attestation.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Library/Homebrew/attestation.rb b/Library/Homebrew/attestation.rb index 853643465fa30..7cc4bce456422 100644 --- a/Library/Homebrew/attestation.rb +++ b/Library/Homebrew/attestation.rb @@ -52,6 +52,12 @@ class GhAuthNeeded < RuntimeError; end # @api private class GhAuthInvalid < RuntimeError; end + # Raised if the version of `gh` invoked is too old to support + # attestations. + # + # @api private + class GhTooOld < RuntimeError; end + # Returns whether attestation verification is enabled. # # @api private @@ -143,6 +149,11 @@ def self.check_attestation(bottle, signing_repo, signing_workflow = nil, subject raise MissingAttestationError, "attestation not found: #{e}" if e.stderr.include?("HTTP 404: Not Found") + if e.stderr.include?("unknown command \"attestation\" for \"gh\"") + raise GhTooOld, + "your version of `gh` is too old; run `brew upgrade gh` to continue" + end + raise InvalidAttestationError, "attestation verification failed: #{e}" end From 30acccf4b3bd9c16583eba1b1616ba55d0b98e38 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 12 Aug 2024 14:54:55 -0400 Subject: [PATCH 2/3] attestation: disable if gh is too old Signed-off-by: William Woodruff --- Library/Homebrew/attestation.rb | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Library/Homebrew/attestation.rb b/Library/Homebrew/attestation.rb index 7cc4bce456422..9f359ece4a207 100644 --- a/Library/Homebrew/attestation.rb +++ b/Library/Homebrew/attestation.rb @@ -52,12 +52,6 @@ class GhAuthNeeded < RuntimeError; end # @api private class GhAuthInvalid < RuntimeError; end - # Raised if the version of `gh` invoked is too old to support - # attestations. - # - # @api private - class GhTooOld < RuntimeError; end - # Returns whether attestation verification is enabled. # # @api private @@ -68,6 +62,9 @@ def self.enabled? return false if ENV.fetch("CI", false) return false if OS.unsupported_configuration? + gh_version = Formula["gh"].any_installed_version + return false if gh_version.nil? || gh_version < "2.49" + # Always check credentials last to avoid unnecessary credential extraction. (Homebrew::EnvConfig.developer? || Homebrew::EnvConfig.devcmdrun?) && GitHub::API.credentials.present? end @@ -84,7 +81,7 @@ def self.gh_executable # to prevent a cycle during bootstrapping. This can eventually be resolved # by vendoring a pure-Ruby Sigstore verifier client. with_env(HOMEBREW_NO_VERIFY_ATTESTATIONS: "1") do - @gh_executable = ensure_executable!("gh", reason: "verifying attestations", latest: true) + @gh_executable = ensure_formula_installed!("gh", reason: "verifying attestations", latest: true).opt_bin/"gh" end T.must(@gh_executable) @@ -149,11 +146,6 @@ def self.check_attestation(bottle, signing_repo, signing_workflow = nil, subject raise MissingAttestationError, "attestation not found: #{e}" if e.stderr.include?("HTTP 404: Not Found") - if e.stderr.include?("unknown command \"attestation\" for \"gh\"") - raise GhTooOld, - "your version of `gh` is too old; run `brew upgrade gh` to continue" - end - raise InvalidAttestationError, "attestation verification failed: #{e}" end From be8ee6ea2227f86cd68b38fb24da240d48cac889 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Mon, 12 Aug 2024 15:10:18 -0400 Subject: [PATCH 3/3] fixup attestation_spec Signed-off-by: William Woodruff --- Library/Homebrew/test/attestation_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Library/Homebrew/test/attestation_spec.rb b/Library/Homebrew/test/attestation_spec.rb index 7a7f32662ad64..40a8d43b1ff05 100644 --- a/Library/Homebrew/test/attestation_spec.rb +++ b/Library/Homebrew/test/attestation_spec.rb @@ -4,6 +4,7 @@ RSpec.describe Homebrew::Attestation do let(:fake_gh) { Pathname.new("/extremely/fake/gh") } + let(:fake_gh_formula) { instance_double(Formula, opt_bin: Pathname.new("/extremely/fake")) } let(:fake_old_gh) { Pathname.new("/extremely/fake/old/gh") } let(:fake_gh_creds) { "fake-gh-api-token" } let(:fake_error_status) { instance_double(Process::Status, exitstatus: 1, termsig: nil) } @@ -66,12 +67,12 @@ end describe "::gh_executable" do - it "calls ensure_executable" do - expect(described_class).to receive(:ensure_executable!) + it "calls ensure_formula_installed" do + expect(described_class).to receive(:ensure_formula_installed!) .with("gh", reason: "verifying attestations", latest: true) - .and_return(fake_gh) + .and_return(fake_gh_formula) - described_class.gh_executable + described_class.gh_executable == fake_gh end end