From 860d07d18211a0154ffaa4e77bf2a43c2b2473a9 Mon Sep 17 00:00:00 2001 From: Chris Birkhold Date: Thu, 8 Oct 2026 22:32:32 -0700 Subject: [PATCH] don't leak GIT_* env into `npm install` for `language: node` When a node hook environment is installed from `git commit` inside a submodule, git exports absolute GIT_DIR / GIT_INDEX_FILE paths. `npm install git+file://` inherited them, so npm's checkout of the hook repository overwrote the submodule's index and the commit failed with `fatal: unable to read `. Run the install with no_git_env(), as is already done for the initial clone in store.py. Signed-off-by: Chris Birkhold --- pre_commit/languages/node.py | 3 ++- tests/languages/node_test.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pre_commit/languages/node.py b/pre_commit/languages/node.py index 17b7393ab..3ab6e2b8b 100644 --- a/pre_commit/languages/node.py +++ b/pre_commit/languages/node.py @@ -13,6 +13,7 @@ from pre_commit.envcontext import PatchesT from pre_commit.envcontext import UNSET from pre_commit.envcontext import Var +from pre_commit.git import no_git_env from pre_commit.languages.python import bin_dir from pre_commit.prefix import Prefix from pre_commit.util import cmd_output @@ -103,4 +104,4 @@ def install_environment( 'npm', 'install', '--allow-git=root', '--install-links', '-g', *pkgs, ) - lang_base.setup_cmd(prefix, install) + lang_base.setup_cmd(prefix, install, env=no_git_env()) diff --git a/tests/languages/node_test.py b/tests/languages/node_test.py index 778501a69..b2df9f6a3 100644 --- a/tests/languages/node_test.py +++ b/tests/languages/node_test.py @@ -144,6 +144,29 @@ def test_node_hook_system(tmp_path): assert ret == (0, b'Hello World\n') +def test_node_hook_install_does_not_write_callers_index(tmp_path): + # git sets GIT_DIR / GIT_INDEX_FILE to absolute paths when running hooks + # in a submodule, `npm install git+file://...` must not inherit them + hook_repo = tmp_path.joinpath('hook') + hook_repo.mkdir() + _make_hello_world(hook_repo) + + user_repo = tmp_path.joinpath('user') + cmd_output_b('git', 'init', user_repo) + user_repo.joinpath('f').touch() + cmd_output_b('git', 'add', 'f', cwd=user_repo) + + git_dir = user_repo.joinpath('.git') + with envcontext.envcontext(( + ('GIT_DIR', str(git_dir)), + ('GIT_INDEX_FILE', str(git_dir.joinpath('index'))), + )): + ret = run_language(hook_repo, node, 'node-hello') + assert ret == (0, b'Hello World\n') + + assert cmd_output('git', 'ls-files', cwd=user_repo)[1] == 'f\n' + + def test_node_with_user_config_set(tmp_path): cfg = tmp_path.joinpath('cfg') cfg.write_text('cache=/dne\n')