From 18a8b12f7afe69903d35f5d5d55e1e6c2c00d816 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Fri, 3 May 2024 12:37:01 -0400 Subject: [PATCH] attestations: improve authentication techniques Signed-off-by: William Woodruff --- Library/Homebrew/attestation.rb | 19 ++++++++++++++++++- Library/Homebrew/formula_installer.rb | 10 ++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Library/Homebrew/attestation.rb b/Library/Homebrew/attestation.rb index 2dc57ad57a..45412b82a8 100644 --- a/Library/Homebrew/attestation.rb +++ b/Library/Homebrew/attestation.rb @@ -33,6 +33,12 @@ module Homebrew # @api private class InvalidAttestationError < RuntimeError; end + # Raised if attestation verification cannot continue due to missing + # credentials. + # + # @api private + class GhAuthNeeded < RuntimeError; end + # Returns a path to a suitable `gh` executable for attestation verification. # # @api private @@ -56,6 +62,7 @@ module Homebrew # `https://github/OWNER/REPO/.github/workflows/WORKFLOW.yml@REF` format. # # @return [Hash] the JSON-decoded response. + # @raise [GhAuthNeeded] on any authentication failures # @raise [InvalidAttestationError] on any verification failures # # @api private @@ -69,9 +76,18 @@ module Homebrew cmd += ["--cert-identity", signing_workflow] if signing_workflow.present? + # Fail early if we have no credentials. The command below invariably + # fails without them, so this saves us a network roundtrip before + # presenting the user with the same error. + credentials = GitHub::API.credentials + raise GhAuthNeeded, "missing credentials" if credentials.blank? + begin - output = Utils.safe_popen_read(*cmd) + output = Utils.safe_popen_read({ "GH_TOKEN" => credentials }, *cmd) rescue ErrorDuringExecution => e + # Even if we have credentials, they may be invalid or malformed. + raise GhAuthNeeded, "invalid credentials" if e.status.exitstatus == 4 + raise InvalidAttestationError, "attestation verification failed: #{e}" end @@ -100,6 +116,7 @@ module Homebrew # This is a specialization of `check_attestation` for homebrew-core. # # @return [Hash] the JSON-decoded response + # @raise [GhAuthNeeded] on any authentication failures # @raise [InvalidAttestationError] on any verification failures # # @api private diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb index e038dd8f50..d41673003e 100644 --- a/Library/Homebrew/formula_installer.rb +++ b/Library/Homebrew/formula_installer.rb @@ -1261,6 +1261,16 @@ on_request: installed_on_request?, options:) ohai "Verifying attestation for #{formula.name}" begin Homebrew::Attestation.check_core_attestation formula.bottle + rescue Homebrew::Attestation::GhAuthNeeded + raise CannotInstallFormulaError, <<~EOS + The bottle for #{formula.name} could not be verified. + + This typically indicates a missing GitHub API token, which you + can resolve either by setting `HOMEBREW_GITHUB_API_TOKEN` or + by running: + + gh auth login + EOS rescue Homebrew::Attestation::InvalidAttestationError => e raise CannotInstallFormulaError, <<~EOS The bottle for #{formula.name} has an invalid build provenance attestation.