fix(server): worktree submodule checkout no longer waits on hidden credential prompts#33029

open3
main
fix/issue-33017
opened1d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

When a new worktree checks out submodules, git submodule update --init runs without a timeout, which is intentional so long clones can finish. It also inherits the server's interactive credential settings. If a submodule remote asks for credentials and the server environment has a hidden prompt (an inherited GIT_ASKPASS/SSH_ASKPASS helper, a Git Credential Manager dialog, or a terminal prompt), the clone waits forever. Worktree setup stays at "Check out files 100%", and /side keeps answering "Available once the thread's worktree is set up."

Reproduction: a repo whose .gitmodules points at an HTTP remote that always answers 401, with the server started with GIT_ASKPASS set to a helper that never returns. Then create a new-worktree thread.

Change

The submodule update in GitVcsDriverCore.createWorktree now gets the same non-interactive environment that fetchRemote and the background status fetch already use: GCM_INTERACTIVE=never, empty GIT_ASKPASS, GIT_TERMINAL_PROMPT=0, empty SSH_ASKPASS, SSH_ASKPASS_REQUIRE=never. It applies with and without the progress callback, and the progress path keeps LANGUAGE=C.

An authentication failure now fails the command quickly and goes through the existing best-effort onSubmodulesFinished({ ok: false }) path, so worktree preparation settles. There is still no timeout, so long legitimate clones still finish. Credential helpers with saved logins and SSH agents keep working. The user docs on worktree submodules now say that private submodules need credentials Git already has.

Interaction with pingdotgg/t3code#24105: if that PR lands, its opt-in to keep GIT_ASKPASS should cover this call site as well as the two fetch paths.

Scope and approval

Fixes pingdotgg/t3code#33017

Triaged via the automated issue flow.

Verification

  • New test makes worktree submodule checkout non-interactive (progress: false|true) in apps/server/src/vcs/GitVcsDriverCore.test.ts. It uses the existing real Git/SSH fixture with interactive values in the inherited environment.

    • On main, both cases fail: expected [ 'GCM_INTERACTIVE=always', … ] to deeply equal [ 'GCM_INTERACTIVE=never', … ].
    • With the fix, both pass.
  • The existing submodule and non-interactive tests still pass: slow checkout matrix, failed checkout, cancellation, mode resolution, and background fetch.

  • vp run check:changed: format, lint, knip, typecheck (3 packages), and 242 tests in 2 files all pass.

  • Runtime check in the real app, a dev server on a fresh database. Same steps before and after: "New worktree" thread on a synthetic repo whose submodule remote always answers 401, server started with GIT_ASKPASS pointing at a helper that logs and never returns.

    Before (main ade473018d)After (27db835d50)
    Worktree setupstuck at "Check out files 100%" for over a minutesettles; the agent replies on the new branch
    git submodule updatewaiting in the askpass helper on Username for 'http://127.0.0.1:18733'exits 1, reason: 'authentication_failed'; helper never invoked
    /side"Side chat not started. Available once the thread's worktree is set up."opens the side chat
    Runtime transcript and repro scripts (synthetic)
    text
    1$ GIT_ASKPASS=hang-askpass.sh timeout 10 git submodule update --init --recursive
    2Cloning into '.../wt1/private'...
    3exit=124 after 10s
    4askpass invoked: Username for 'http://127.0.0.1:18733':
    5
    6$ GIT_ASKPASS= GCM_INTERACTIVE=never GIT_TERMINAL_PROMPT=0 SSH_ASKPASS= SSH_ASKPASS_REQUIRE=never \
    7 timeout 10 git submodule update --init --recursive
    8fatal: could not read Username for 'http://127.0.0.1:18733': terminal prompts disabled
    9Failed to clone 'private' a second time, aborting
    10exit=1 after 0s
    11
    12# app, before: ps while setup is stuck
    133818259 73s git submodule update --init --recursive
    143818348 73s /bin/sh hang-askpass.sh Username for 'http://127.0.0.1:18733':
    15
    16# app, after: server log
    17WARN worktree submodule checkout failed; submodules may be incomplete
    18 operation: 'GitVcsDriver.createWorktree.updateSubmodules', exitCode: 1, reason: 'authentication_failed'

    auth401.py (port as argument):

    python
    1import http.server, sys
    2class H(http.server.BaseHTTPRequestHandler):
    3 def do_GET(self):
    4 self.send_response(401); self.send_header("WWW-Authenticate", 'Basic realm="private"')
    5 self.send_header("Content-Length", "0"); self.end_headers()
    6 do_POST = do_GET
    7http.server.ThreadingHTTPServer(("127.0.0.1", int(sys.argv[1])), H).serve_forever()

    hang-askpass.sh:

    sh
    1#!/bin/sh
    2echo "askpass invoked: $*" >> askpass.log
    3sleep 100000

    The parent repo has .gitmodules with url = http://127.0.0.1:18733/private.git, plus a gitlink added with git update-index --add --cacheinfo 160000,<sha>,private.

  • Not checked:

    • The reporter's exact macOS setup: real GCM or SSH askpass dialogs, and their mix of SSH and HTTPS submodules. The fix is platform-independent, and the test covers the SSH and GCM variables.
    • Screenshots of the before/after UI were taken but are not attached. The change has no UI of its own.

AI-assisted; verified with the tests and tools listed above.

Checks

21 successful · 11 skipped · 1 neutral
All checks passed
27db835

Added 3 commits

  • docs: worktree submodules clone without sign-in prompts27db835
  • test(server): worktree submodule checkout is non-interactive (reproduces #33017)67814ed
  • fix(server): worktree submodule checkout no longer waits on hidden credential promptscde6840
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Submodule checkout now suppresses credential prompts so hidden sign-in requests cannot stall worktree setup. This changes default authentication behavior: a human must accept that private submodules requiring interactive sign-in or askpass helpers may remain empty.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded21.5 KiB21.5 KiB0 B (0.0%)24.4 KiB✅
CodexLive turn messages110 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.9 KiB21.9 KiB0 B (0.0%)24.4 KiB✅
ClaudeLive turn messages110 (0.0%)8✅

Baseline: ade4730 · PR result: 27db835 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Submodule updates now receive the non-interactive authentication environment whether progress callbacks are enabled or not. A regression test covers both settings, and the documentation describes credential requirements for private submodules.

Changes: Submodule checkout

Layer / File(s)Summary
Submodule update environment and coverage
apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts, docs/user/project-settings.md
Submodule updates now use STATUS_UPSTREAM_REFRESH_ENV in both callback cases. The test checks both progress settings and verifies the SSH wrapper environment and completion result. The documentation states that private submodules need credentials available to Git on the server and remain empty without them.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

  • #26390 — The update remains without a timeout and reports failure through the existing completion path. Repair or retry of failed or incomplete submodules is not addressed.
  • #23044 — The update uses the non-interactive credential environment. This change does not add the requested GIT_ASKPASS opt-in.

Suggested reviewers: ixab3r, saphid, t3dotgg

Merge Risk: External image Minimal · up to 27db8

The change addresses non-interactive submodule checkout in both progress modes. No issue requiring a fix before merge is established.

Pre-merge checks: Passed 4

Check nameStatusExplanation
Title checkPassedThe title names the main change: worktree submodule checkout no longer waits on hidden credential prompts. It matches the summary, which adds the non-interactive credential environment to the submodul…
Description checkPassedThe description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section gives the failure mode, the reproduction steps, and the envi…
Linked Issues checkPassedDirectly linked issue #33017 requires (1) a non-interactive auth environment for the automatic worktree submodule update, with and without progress callbacks, (2) keeping the progress path's LANGUAGE=…
Out of Scope Changes checkPassedThe reviewed changes fall into three groups, and each connects to #33017:
- apps/server/src/vcs/GitVcsDriverCore.ts: the environment change in the createWorktree submodule update. This is the requeste…
Full details: Title check

Explanation

The title names the main change: worktree submodule checkout no longer waits on hidden credential prompts. It matches the summary, which adds the non-interactive credential environment to the submodule update in createWorktree, with and without progress callbacks. The title follows the conventional commit form and is specific enough for a teammate scanning history. Its length of 85 characters is acceptable.

Full details: Description check

Explanation

The description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section gives the failure mode, the reproduction steps, and the environment. The Change section explains the fix and why it applies with and without the progress callback. The Scope section links issue #33017 and notes triage through the automated issue flow. The Verification section lists a named test with before and after results, the repo check command results, and a runtime check with a transcript. It also states what was not checked. The Scope section relies on a triaged issue, not an explicit maintainer approval comment. The template asks for the approval comment to be linked, and the description does not cite one. The template also asks for an agent model and harness line at the end, and the description has only a generic AI-assisted note. These gaps are minor. The description is mostly complete.

Full details: Linked Issues check

Explanation

Directly linked issue #33017 requires (1) a non-interactive auth environment for the automatic worktree submodule update, with and without progress callbacks, (2) keeping the progress path's LANGUAGE=C, (3) no restored short timeout, and (4) auth failures reported through the existing submodule result so setup settles.

Code evidence at the reviewed head (diff of apps/server/src/vcs/GitVcsDriverCore.ts against the merge base, around the submodule update call in createWorktree):

  • The progress branch now sets env to { ...STATUS_UPSTREAM_REFRESH_ENV, LANGUAGE: "C" } and keeps the progress callbacks. This satisfies (1) and (2).
  • The non-progress branch now sets env: STATUS_UPSTREAM_REFRESH_ENV where it previously had no env. This satisfies (1) without progress callbacks.
  • timeoutMs: null is unchanged. This satisfies (3).
  • The diff does not alter the failure handling. Per the PR description and the linked issue, the existing best-effort onSubmodulesFinished({ ok: false }) path handles the failure. The PR reports that the new test shows the failure callback fires.

Automated test: the PR adds makes worktree submodule checkout non-interactive (progress: false|true). Per the PR description, it fails on main and passes with the change. I did not read the test file. This conclusion relies on the PR description for the test result.

The macOS GCM and SSH askpass dialog cases were not reproduced. The linked issue treats these as the reporter's environment, and the PR states they were not checked. They do not change the coding requirements, which the synthetic runtime check and the env-based test address.

Full details: Out of Scope Changes check

Explanation

The reviewed changes fall into three groups, and each connects to #33017:

  • apps/server/src/vcs/GitVcsDriverCore.ts: the environment change in the createWorktree submodule update. This is the requested fix.
  • apps/server/src/vcs/GitVcsDriverCore.test.ts: a regression test for the same call site, per the PR description and raw summary. It supports the fix.
  • docs/user/project-settings.md: a documentation note that private submodules need credentials Git already has. The PR description states this follows from the non-interactive behavior. Documentation that describes the changed behavior is a legitimate supporting change.

The code diff contains no unrelated edits. The change does not add a timeout, does not remove the /side guard, and does not modify the fetch paths. The docs diff could not be read from the checkout, so its content is judged from the PR description and raw summary only. This does not change the verdict because the text is documentation that matches the described behavior.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info

External image Run configuration

External image Commits

Reviewing files that changed from the base of the PR and between ade473018d32003658b7d38693e083ee2e314bd8 and 27db835d5094e372276cbe75c224761f28bc971b.

External image Files selected for processing: 3

  • apps/server/src/vcs/GitVcsDriverCore.test.ts
  • apps/server/src/vcs/GitVcsDriverCore.ts
  • docs/user/project-settings.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.