fix(git): never block internal git calls on credential prompts - #73709
Merged
Conversation
Port from openai/codex#34540 / #34612 ("detach non-interactive subprocesses from stdin"): internal git invocations that run with nobody attached — MCP catalog installs, plugin install/update, profile distribution staging, worktree base fetches, and the desktop review pane's git/gh backend — could hang on a credential prompt when a remote is private, misconfigured, or requires auth. git prompts on the inherited terminal (or via Git Credential Manager on Windows), so the operation silently waits until its timeout, or forever at sites without one (mcp_catalog clones have no timeout at all and inherit the parent terminal). - Add noninteractive_git_env() to hermes_cli/_subprocess_compat.py: GIT_TERMINAL_PROMPT=0 + GCM_INTERACTIVE=Never on a copy of the environment; GIT_ASKPASS/SSH_ASKPASS deliberately preserved so working non-interactive auth still succeeds. - Wire it + stdin=DEVNULL into: mcp_catalog._do_git_install (clone/ checkout), plugins_cmd (clone + pull), profile_distribution._git_clone, web_git._git/_gh (gh also gets GH_PROMPT_DISABLED=1), and cli.py's worktree base fetch helper. - Tests: env contract, a real-git E2E against a local 401 Basic-auth HTTP server proving fail-fast ("terminal prompts disabled") instead of a hang, and per-call-site plumbing assertions. Sabotage-verified: removing the env from web_git._git fails the site test.
Contributor
૮ >ﻌ< ა ci reviewran on f2cdb1c ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence is publishing... debug info |
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Internal git invocations can no longer hang on a credential prompt — they fail fast with a readable error instead. Port of the non-portable-half-adapted invariant from openai/codex#34540 and openai/codex#34612 ("detach non-interactive subprocesses from stdin").
Root cause: Hermes shells out to git from several contexts where nobody is attached to answer a prompt — MCP catalog installs, plugin install/update, profile distribution staging, worktree base fetches, and the desktop review pane's git/gh REST backend. When a remote is private, misconfigured, or requires auth, git's default is to prompt on the inherited terminal (or pop a Git Credential Manager dialog on Windows). The operation then silently waits until its timeout — or forever at the sites without one (
mcp_catalog._do_git_install's clones have no timeout and inherit the parent terminal, sohermes mcp installon a private manifest URL hangs indefinitely).Changes
hermes_cli/_subprocess_compat.py: newnoninteractive_git_env()— copy of the environment withGIT_TERMINAL_PROMPT=0+GCM_INTERACTIVE=Never.GIT_ASKPASS/SSH_ASKPASSdeliberately preserved: a working askpass helper or ssh-agent is legitimate non-interactive auth and must keep succeeding.stdin=subprocess.DEVNULLat each internal call site:hermes_cli/mcp_catalog.py—_do_git_installclone/checkout (previously untimed + terminal-inherited)hermes_cli/plugins_cmd.py— plugingit cloneandgit pull --ff-onlyhermes_cli/profile_distribution.py—_git_clonestaginghermes_cli/web_git.py—_gitand_gh(dashboard/desktop review pane;ghadditionally getsGH_PROMPT_DISABLED=1, its documented prompt kill-switch)cli.py— worktree base-fetch helper (hermes -wupstream/default-branch fetches)tests/hermes_cli/test_noninteractive_git.py— env contract tests, per-call-site plumbing assertions, and a real-git E2E: a local HTTP server answering 401 + Basic challenge;git cloneagainst it with the hardened env exits fast with "terminal prompts disabled" instead of waiting for a username.Scope note: this is internal plumbing only. The agent-facing terminal tool is untouched — it has its own policy layer and a user-visible PTY where prompting can be legitimate (open PRs #73196/#7990 cover that surface; this PR neither overlaps nor conflicts with them).
Validation
hermes mcp installw/ private repoSabotage-verified: removing the env/stdin hardening from
web_git._gitmakes the corresponding test fail.Infographic