Skip to content

fix(git): never block internal git calls on credential prompts - #73709

Merged
teknium1 merged 1 commit into
mainfrom
codex-port/noninteractive-internal-git
Jul 29, 2026
Merged

fix(git): never block internal git calls on credential prompts#73709
teknium1 merged 1 commit into
mainfrom
codex-port/noninteractive-internal-git

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

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, so hermes mcp install on a private manifest URL hangs indefinitely).

Changes

  • hermes_cli/_subprocess_compat.py: new noninteractive_git_env() — copy of the environment with GIT_TERMINAL_PROMPT=0 + GCM_INTERACTIVE=Never. GIT_ASKPASS/SSH_ASKPASS deliberately preserved: a working askpass helper or ssh-agent is legitimate non-interactive auth and must keep succeeding.
  • Wired with stdin=subprocess.DEVNULL at each internal call site:
    • hermes_cli/mcp_catalog.py_do_git_install clone/checkout (previously untimed + terminal-inherited)
    • hermes_cli/plugins_cmd.py — plugin git clone and git pull --ff-only
    • hermes_cli/profile_distribution.py_git_clone staging
    • hermes_cli/web_git.py_git and _gh (dashboard/desktop review pane; gh additionally gets GH_PROMPT_DISABLED=1, its documented prompt kill-switch)
    • cli.py — worktree base-fetch helper (hermes -w upstream/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 clone against 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

Before After
hermes mcp install w/ private repo hangs indefinitely (no timeout, inherits terminal) fails fast: "terminal prompts disabled"
Desktop review-pane fetch/push w/ auth error request hangs until 30s timeout fails fast, real error in toast
Plugin install/update from private URL hangs until 60s timeout fails fast
New tests 11/11 pass (incl. live-git 401 E2E)
Sibling tests (mcp_catalog, plugins_cmd, profile_distribution, subprocess_timeouts, windows_compat, stdin_guard, web_server_git, worktree_sync_base, working_diff) 269 passed, 4 skipped

Sabotage-verified: removing the env/stdin hardening from web_git._git makes the corresponding test fail.

Infographic

noninteractive-internal-git

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.
@teknium1 teknium1 added the ci-reviewed applied to manually approve dangerous changes label Jul 29, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard tool/mcp MCP client and OAuth area/auth Authentication, OAuth, credential pools labels Jul 29, 2026
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on f2cdb1c

ℹ️ Info

Desktop E2E visual evidence · View test artifacts · View job

1 visual diff.

inline evidence is publishing...


debug info

MCP catalog security review

MCP catalog security review · View job

ci-reviewed label is present.

@teknium1
teknium1 merged commit 58708c7 into main Jul 29, 2026
73 of 77 checks passed
@teknium1
teknium1 deleted the codex-port/noninteractive-internal-git branch July 29, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools ci-reviewed applied to manually approve dangerous changes comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants