diff --git a/Library/Homebrew/download_strategy/git_download_strategy.rb b/Library/Homebrew/download_strategy/git_download_strategy.rb index e78c539b06d17..e27f85d90650e 100644 --- a/Library/Homebrew/download_strategy/git_download_strategy.rb +++ b/Library/Homebrew/download_strategy/git_download_strategy.rb @@ -29,12 +29,8 @@ def initialize(url, name, version, **meta) # @api public sig { override.returns(Time) } def source_modified_time - # This runs while staging inside the sandbox, where reading the user Git - # config is denied and makes Git exit; null the global config here, unlike - # the download-time commands that read it for credential helpers. - require "utils/git" result = system_command("git", args: ["--git-dir", git_dir, "show", "-s", "--format=%cD"], - env: env.merge(Utils::Git.no_global_config_env), print_stderr: false) + env: local_git_env, print_stderr: false) raise "Failed to read the Git commit time:\n#{result.stderr}" unless result.success? Time.parse(result.stdout) @@ -49,7 +45,7 @@ def source_revision = current_revision.presence sig { override.returns(String) } def last_commit args = ["--git-dir", git_dir, "rev-parse", "--short=#{MINIMUM_COMMIT_HASH_LENGTH}", "HEAD"] - @last_commit ||= silent_command("git", args:).stdout.chomp.presence + @last_commit ||= system_command("git", args:, env: local_git_env, print_stderr: false).stdout.chomp.presence @last_commit || "" end @@ -62,6 +58,16 @@ def env { "GIT_TERMINAL_PROMPT" => "0" } end + # Local, read-only repository inspections (`git --git-dir … rev-parse`/`show`) + # can run while staging inside the sandbox, where reading the user's global Git + # config is denied and makes Git exit. Null it here, unlike the download-time + # commands that read it for credential helpers. + sig { returns(T::Hash[String, String]) } + def local_git_env + require "utils/git" + env.merge(Utils::Git.no_global_config_env) + end + sig { override.returns(String) } def cache_tag if partial_clone_sparse_checkout? @@ -104,7 +110,8 @@ def ref? sig { override.returns(String) } def current_revision - silent_command("git", args: ["--git-dir", git_dir, "rev-parse", "-q", "--verify", "HEAD"]).stdout.strip + system_command("git", args: ["--git-dir", git_dir, "rev-parse", "-q", "--verify", "HEAD"], + env: local_git_env, print_stderr: false).stdout.strip end sig { override.returns(T::Boolean) } diff --git a/Library/Homebrew/test/download_strategies/git_spec.rb b/Library/Homebrew/test/download_strategies/git_spec.rb index b3cc2f8c6e367..fb24d6921f507 100644 --- a/Library/Homebrew/test/download_strategies/git_spec.rb +++ b/Library/Homebrew/test/download_strategies/git_spec.rb @@ -63,13 +63,28 @@ def setup_git_repo end end - specify "#last_commit" do - cached_location.cd do - setup_git_repo - FileUtils.touch "LICENSE" - git_commit_all + describe "#last_commit" do + specify "returns the short hash of the last commit" do + cached_location.cd do + setup_git_repo + FileUtils.touch "LICENSE" + git_commit_all + end + expect(strategy.last_commit).to eq("f68266e") + end + + it "nulls the global Git config so sandboxed staging reads do not fail" do + expect(strategy).to receive(:system_command) + .with( + "git", + args: ["--git-dir", cached_location/".git", "rev-parse", "--short=7", "HEAD"], + env: { "GIT_TERMINAL_PROMPT" => "0", "GIT_CONFIG_GLOBAL" => File::NULL }, + print_stderr: false, + ) + .and_return(instance_double(SystemCommand::Result, stdout: "f68266e\n")) + + expect(strategy.last_commit).to eq("f68266e") end - expect(strategy.last_commit).to eq("f68266e") end describe "#fetch_last_commit" do