Repository navigation
feat(git): fail-fast SSH and HTTP env for network fetch (PR C) - #23
bschellenberger2600 wants to merge 12 commits into
Conversation
Extend PrepareNetworkGit with batch-mode SSH (when GIT_SSH_COMMAND and core.sshCommand are unset) and HTTP low-speed limits when unset. Document fetch_timeout_sec, --fetch-timeout, and GIT_RAIN_GLOBAL_FETCH_TIMEOUT_SEC. Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…into cursor/network-failfast-env-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Fail-fast SSH overrides GIT_SSH
- Skip GIT_SSH_COMMAND injection when GIT_SSH is already set so custom SSH wrappers are not overridden.
- ✅ Fixed: Fail-fast test ignores global config
- core.sshCommand probes now use cmd.Env, and tests null out global/system gitconfig so injection assertions stay deterministic.
Or push these changes by commenting:
@cursor push 1edbefaa2b
Preview (1edbefaa2b)
diff --git a/internal/git/command.go b/internal/git/command.go
--- a/internal/git/command.go
+++ b/internal/git/command.go
@@ -9,7 +9,7 @@
// PrepareNetworkGit configures cmd for fetch/push operations that may contact
// a remote. Delegates to git-harness for GIT_TERMINAL_PROMPT=0, then adds
// fail-fast SSH and HTTP env unless the user already set GIT_SSH_COMMAND,
-// GIT_HTTP_LOW_SPEED_*, or core.sshCommand in the repo.
+// GIT_SSH, GIT_HTTP_LOW_SPEED_*, or core.sshCommand.
func PrepareNetworkGit(cmd *exec.Cmd) {
harnessgit.PrepareNetworkGit(cmd)
applyFailFastNetworkEnv(cmd)
diff --git a/internal/git/command_test.go b/internal/git/command_test.go
--- a/internal/git/command_test.go
+++ b/internal/git/command_test.go
@@ -18,10 +18,14 @@
}
func isolatedPrepareNetworkEnv(t *testing.T) []string {
+ t.Helper()
return []string{
"PATH=" + os.Getenv("PATH"),
"HOME=" + os.Getenv("HOME"),
"USER=" + os.Getenv("USER"),
+ // Keep core.sshCommand probes from picking up the developer's global config.
+ "GIT_CONFIG_GLOBAL=/dev/null",
+ "GIT_CONFIG_SYSTEM=/dev/null",
}
}
@@ -60,6 +64,20 @@
}
}
+func TestPrepareNetworkGit_PreservesUserGitSSH(t *testing.T) {
+ repo := testutil.CreateTestRepo(t, testutil.RepoOptions{Name: "failfast-user-git-ssh"})
+ cmd := exec.Command("git", "fetch", "--all")
+ cmd.Dir = repo
+ cmd.Env = append(isolatedPrepareNetworkEnv(t), "GIT_SSH=/usr/bin/custom-ssh")
+ PrepareNetworkGit(cmd)
+
+ for _, e := range cmd.Env {
+ if strings.HasPrefix(e, "GIT_SSH_COMMAND=") {
+ t.Fatalf("should not set GIT_SSH_COMMAND when GIT_SSH is set, got %s", e)
+ }
+ }
+}
+
func TestPrepareNetworkGit_PreservesCoreSSHCommand(t *testing.T) {
repo := testutil.CreateTestRepo(t, testutil.RepoOptions{Name: "failfast-core-ssh"})
runGit := exec.Command("git", "-C", repo, "config", "core.sshCommand", "ssh -o IdentityFile=/tmp/from-core")
diff --git a/internal/git/network_env.go b/internal/git/network_env.go
--- a/internal/git/network_env.go
+++ b/internal/git/network_env.go
@@ -21,7 +21,9 @@
env = setEnvIfUnset(env, "GIT_HTTP_LOW_SPEED_LIMIT", defaultHTTPLowSpeedLimit)
env = setEnvIfUnset(env, "GIT_HTTP_LOW_SPEED_TIME", defaultHTTPLowSpeedTimeSec)
- if !envHasPrefix(env, "GIT_SSH_COMMAND=") && !repoHasCoreSSHCommand(cmd.Dir) {
+ // GIT_SSH_COMMAND overrides GIT_SSH; only inject when neither is set and
+ // core.sshCommand is unset (same preserve path as an explicit SSH wrapper).
+ if !envHasPrefix(env, "GIT_SSH_COMMAND=") && !envHasPrefix(env, "GIT_SSH=") && !repoHasCoreSSHCommand(cmd.Dir, env) {
sshCmd := fmt.Sprintf("ssh -o BatchMode=yes -o ConnectTimeout=%d", defaultSSHConnectTimeoutSec)
env = append(env, "GIT_SSH_COMMAND="+sshCmd)
}
@@ -47,10 +49,12 @@
return false
}
-func repoHasCoreSSHCommand(repoDir string) bool {
+func repoHasCoreSSHCommand(repoDir string, env []string) bool {
if strings.TrimSpace(repoDir) == "" {
return false
}
- out, err := exec.Command("git", "-C", repoDir, "config", "--get", "core.sshCommand").Output()
+ cmd := exec.Command("git", "-C", repoDir, "config", "--get", "core.sshCommand")
+ cmd.Env = env
+ out, err := cmd.Output()
return err == nil && strings.TrimSpace(string(out)) != ""
}You can send follow-ups to the cloud agent here.
Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
…into cursor/network-failfast-env-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
…into cursor/network-failfast-env-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
… gitconfig Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
…-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
…-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: SSH probe ignores command environment
- repoHasCoreSSHCommand now runs git config with the command Env so GIT_CONFIG isolation and custom environments are honored when deciding to inject GIT_SSH_COMMAND.
Or push these changes by commenting:
@cursor push 09ca40a6f0
Preview (09ca40a6f0)
diff --git a/internal/git/network_env.go b/internal/git/network_env.go
--- a/internal/git/network_env.go
+++ b/internal/git/network_env.go
@@ -21,7 +21,7 @@
env = setEnvIfUnset(env, "GIT_HTTP_LOW_SPEED_LIMIT", defaultHTTPLowSpeedLimit)
env = setEnvIfUnset(env, "GIT_HTTP_LOW_SPEED_TIME", defaultHTTPLowSpeedTimeSec)
- if !envHasPrefix(env, "GIT_SSH_COMMAND=") && !envHasPrefix(env, "GIT_SSH=") && !repoHasCoreSSHCommand(cmd.Dir) {
+ if !envHasPrefix(env, "GIT_SSH_COMMAND=") && !envHasPrefix(env, "GIT_SSH=") && !repoHasCoreSSHCommand(cmd.Dir, env) {
sshCmd := fmt.Sprintf("ssh -o BatchMode=yes -o ConnectTimeout=%d", defaultSSHConnectTimeoutSec)
env = append(env, "GIT_SSH_COMMAND="+sshCmd)
}
@@ -47,10 +47,12 @@
return false
}
-func repoHasCoreSSHCommand(repoDir string) bool {
+func repoHasCoreSSHCommand(repoDir string, env []string) bool {
if strings.TrimSpace(repoDir) == "" {
return false
}
- out, err := exec.Command("git", "-C", repoDir, "config", "--get", "core.sshCommand").Output()
+ probe := exec.Command("git", "-C", repoDir, "config", "--get", "core.sshCommand")
+ probe.Env = env
+ out, err := probe.Output()
return err == nil && strings.TrimSpace(string(out)) != ""
}You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit b61bc2d. Configure here.
…-971d Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
Skip BatchMode GIT_SSH_COMMAND injection when GIT_SSH is set, and run core.sshCommand probes with the command env so tests can null out global gitconfig via GIT_CONFIG_GLOBAL/SYSTEM. Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>
Pass the prepared command environment into the SSH config probe so GIT_CONFIG_* isolation (and any custom Env) is respected when deciding whether to inject fail-fast GIT_SSH_COMMAND. Co-authored-by: Ben Schellenberger <bschellenberger2600@users.noreply.github.com>


Stacked stall-review fix 3/3. Base:
cursor/run-cancel-signals-971d(PR B).Summary
PrepareNetworkGit(git-rain wrapper) after git-harnessGIT_TERMINAL_PROMPT=0:GIT_SSH_COMMANDwith-o BatchMode=yes -o ConnectTimeout=30only whenGIT_SSH_COMMANDis unset and the repo has nocore.sshCommand.GIT_HTTP_LOW_SPEED_LIMIT/GIT_HTTP_LOW_SPEED_TIMEwhen unset.fetch_timeout_sec,--fetch-timeout,GIT_RAIN_GLOBAL_FETCH_TIMEOUT_SEC, and fail-fast env behavior in README and AGENTS.md.Tests
TestPrepareNetworkGit_SetsFailFastEnvTestPrepareNetworkGit_PreservesUserGitSSHCommandTestPrepareNetworkGit_PreservesCoreSSHCommandTestPrepareNetworkGit_PreservesUserHTTPLowSpeedExit code policy
Unreachable remotes still exit 0 (frozen); only Ctrl-C / run interrupt exits non-zero from PR B.
Verification
go vet ./...— passgo test -race -count=1 ./...— pass except known pre-existingTestNetworkFetch_UnauthenticatedHTTPSFailsWithoutPrompt(PR test: make network auth fetch regression test deterministic #21)