-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
(note: this is not priority request, more "notes")
brew tap-new
runs most Git commands inside a minimal with_env
sandbox that keeps only HOME
(and sometimes TMPDIR
). This strips the user’s PATH
, so global Git hooks that rely on non-system interpreters (e.g., perlbrew or Homebrew-installed Perl) fail. Worse, the initial git init
is executed outside the sandbox, so the repository is half-created before the failure occurs -- and any env-based protections the sandbox provides are bypassed, potentially opening a security gap.
env
Homebrew 4.5.8-157-g114d660-dirty
git version 2.50.0 from homebrew
custom githook which uses Git::Hook, installed not in system paths, but for Perl 5.42.0 from perlbrew
macOS 15.5
Longer story (detailed)
Symptoms
- Global or template Git hooks do spawn (
#!/usr/bin/env perl
resolves to the system Perl) but then fail at runtime because required modules (e.g.Git::Hooks
) are missing from@INC
. As soon as the hook dies,brew tap-new
aborts midway. - The process stops after
git init
, leaving an incomplete tap directory on disk. This might lead to future block for both directions of changes.
Expected vs Actual
Expected: All Git commands triggered by brew tap-new
should inherit the same environment--either the full user PATH
or a consistently sanitised version--so that global Git hooks run without incident.
Actual: The first git init
inherits the full PATH
, while subsequent commands (git add
, git commit
, git branch
) run inside the pared-down with_env
sandbox. Hooks load the system Perl successfully but then die with errors such as:
Can't locate Git/Hooks.pm in \@INC ...
The missing module lives in a path injected by Perlbrew, which is no longer present in PATH
/PERL5LIB
inside the sandbox.
Minimal reproduction
# 1. Install a non-system Perl and expose it via PATH
perlbrew install perl-5.42.0
perlbrew switch perl-5.42.0
# Install cpanminus into this Perl and install Git::Hooks there
perlbrew install-cpanm
cpanm Git::Hooks # this installed in $HOME/... and never visible for system Perl
# 2. Create a temporary pre‑commit hook that uses that Perl
mkdir -p ~/.git-templates/hooks
cat > ~/.git-templates/hooks/pre-commit <<'EOF'
#!/usr/bin/env perl
use strict;
use warnings;
use Git::Hooks; # deliberately missing from system Perl
print "This line never runs in macOS system Perl";
EOF
chmod +x ~/.git-templates/hooks/pre-commit
# 3. Point Git *for this test only* at that template dir and run tap‑new
# (store any previous value and restore it afterwards so we don't pollute the tester's setup)
prev_template=$(git config --global --get init.templateDir || true)
git config --global init.templateDir ~/.git-templates
brew tap-new foo/bar # fails during git commit
# 4. Clean‑up: restore original git templateDir (or unset if it was blank)
if [ -n "$prev_template" ]; then
git config --global init.templateDir "$prev_template"
else
git config --global --unset init.templateDir || true
fi
Root cause analysis
safe_system "git", "-c", "init.defaultBranch=#{branch}", "init" # ← full ENV
Utils::UID.drop_euid do
env = { HOME: Utils::UID.uid_home }.compact # ← PATH is stripped
with_env(env) do
safe_system "git", *args, "add", "--all"
safe_system "git", *args, "commit", "-m", "Create #{tap} tap"
end
end
git init
inherits the full environment, but git add/commit/branch
run under a reduced one, so any hook requiring PATH
fails.
Impact & security note
- Breaks workflows that depend on Homebrew-installed language toolchains (Perlbrew, pyenv, asdf, etc.).
- If
with_env
exists for security hardening, running the first Git command outside it defeats that goal.
Workaround
Quick fix (hard-coded): inject the necessary Perlbrew (or other toolchain) paths into env[:PATH]
just before calling with_env
, e.g.:
user_path = [
"#{ENV["HOME"]}/perl5/perlbrew/bin",
"#{ENV["HOMEBREW_PREFIX"]}/opt/perl/bin"
].join(":")
env[:PATH] = "#{user_path}:#{ENV.fetch("PATH")}" # prepend safely
This is intentionally narrow and brittle--sufficient for a one-off tap creation but not a portable solution.
Not solved yet: I have not found a clean, cross-platform way to let Perlbrew (or pyenv/asdf) regenerate its PATH inside the sandbox without re-executing their shell init scripts. Ideas welcome. I mean:
#{ENV["HOME"]}/perl5/perlbrew/perls/perl-5.42.0/bin # example perlbrew version bin
Proposed directions
- Wrap all Git commands, including
git init
, in the same environment. - Instead of blanking
PATH
, merge a filtered version (e.g., keep segments owned by the invoking UID). - Document the limitation if the current behaviour is intentional.