Skip to content

fix(downloader): bound git network hangs and retry transient 504s - #2463

Open
Erik Osterman (Cloud Posse) (osterman) wants to merge 6 commits into
mainfrom
osterman/go-getter-timeout-retries
Open

Erik Osterman (Cloud Posse) (osterman) wants to merge 6 commits into
mainfrom
osterman/go-getter-timeout-retries

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented May 21, 2026 •

Copy link
Copy Markdown
Member

what

  • Prepend -c http.lowSpeedLimit=1000 -c http.lowSpeedTime=30 to every network-touching git invocation in pkg/downloader/get_git.go (clone/fetch/pull/ls-remote/submodule update) so stalled HTTP(S) transfers surface within ~30 s instead of consuming the full context budget.
  • Always set GIT_SSH_COMMAND with ConnectTimeout=30, ServerAliveInterval=15, ServerAliveCountMax=4 — even without an sshKeyFile — to bound SSH transports the same way.
  • Add "returned error: 5", "could not resolve host", and "early eof" to isRetryableGitError. The previous "gateway timeout" pattern did not match git's real wire format (fatal: ... The requested URL returned error: 504), so retries never fired.
  • Apply a conservative default RetryConfig (3 attempts, exponential 2 s → 30 s with jitter) in pkg/provisioner/source/vendor.go when sourceSpec.Retry is nil, so auto-provisioned sources retry on transient 5xx/DNS failures instead of failing the whole apply.
  • Demote log.Info("Running hooks", "event", event) to log.Debug in cmd/terraform/utils.go to match the sibling debug log in pkg/hooks/hooks.go and remove per-invocation noise.

why

  • A user pipeline appeared frozen for ~15 minutes during before.terraform.apply and then failed with a GitLab 504 from go-getter. The same atmos invocation succeeded a second later, confirming the failure was transient.
  • Root cause was three compounding gaps: git had no per-command network deadline, the 5-minute context cancelled three sequential commands (5 + 5 + 5 = 15 min hang), the retry predicate didn't match the actual 504 string git emits, and auto-provisioned sources had no default retry policy.
  • The hooks INFO log fires on every terraform plan/apply/init even when no user hooks would execute, so it was operational noise rather than an actionable signal.

references

  • N/A — internal incident report; no GitHub issue yet.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Git/network reliability by enforcing HTTP low-speed knobs and applying SSH connect/keepalive timeouts for all network operations; SSH key flags are only used when a key is configured.
    • Broadened transient-error detection to retry on more network/HTTP failures (HTTP 5xx patterns, DNS resolution failures, early EOF).
    • Added a default exponential-backoff retry policy for vendor/source auto-provisioning.
    • Lowered hook-runner log level from Info to Debug.
  • Tests

    • Added and updated unit tests covering Git network/SSH timeout behavior, enhanced retry/error classification, and the default provision retry config.

Review Change Stack

…hook log

- Prepend `-c http.lowSpeedLimit=1000 -c http.lowSpeedTime=30` to every
  network-touching git invocation (clone/fetch/pull/ls-remote/submodule
  update) so stalled HTTP(S) transfers surface within ~30s instead of
  consuming the full 5-minute context budget x 3 commands = ~15 min hang.
- Always set GIT_SSH_COMMAND with ConnectTimeout=30, ServerAliveInterval=15,
  ServerAliveCountMax=4 -- even without an sshKeyFile -- to bound SSH
  transports the same way.
- Add "returned error: 5", "could not resolve host", and "early eof" to
  isRetryableGitError. The previous "gateway timeout" pattern did not
  match git's real wire format (fatal: ... The requested URL returned
  error: 504), so retries never fired on the reported incident.
- Apply a conservative default RetryConfig (3 attempts, exponential
  2s->30s with jitter) in pkg/provisioner/source/vendor.go when
  sourceSpec.Retry is nil, so auto-provisioned sources retry on
  transient 5xx/DNS failures instead of failing the whole apply.
- Demote log.Info("Running hooks", "event", event) to log.Debug in
  cmd/terraform/utils.go -- matches the sibling debug log in
  pkg/hooks/hooks.go and removes per-invocation noise.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@atmos-pro

atmos-pro Bot commented May 21, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More. Ask AI.

@osterman Erik Osterman (Cloud Posse) (osterman) added the patch A minor, backward compatible change label May 21, 2026
@github-actions github-actions Bot added the size/m Medium size PR label May 21, 2026
@github-actions

github-actions Bot commented May 21, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented May 21, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Hardens Git transport and retries: adds HTTP low-speed git settings and shared command construction, enforces SSH timeouts for all git commands, broadens retryable-git error detection, provides a default exponential-backoff retry for vendor/source provisioning, and lowers a hook log to debug.

Changes

Git network resilience and SSH timeout enhancements

Layer / File(s) Summary
Network configuration core and setupGitEnv always-on SSH timeouts
pkg/downloader/get_git.go, pkg/downloader/get_git_network_test.go, pkg/downloader/get_git_test.go
Adds HTTP low-speed limit/time constants, gitNetworkConfigArgs() and gitCommandContext() helpers, and refactors setupGitEnv() to always populate GIT_SSH_COMMAND with SSH ConnectTimeout/ServerAlive options while adding -i <key> only when a key path is provided. Adds/updates unit tests validating these behaviors.
Apply network configuration across Git subcommands
pkg/downloader/get_git.go
Replaces direct exec.CommandContext calls with gitCommandContext for ls-remote, clone, fetch, pull, and submodule update, ensuring consistent HTTP low-speed and SSH timeout settings are applied.
Extended retryable error pattern detection
pkg/downloader/get_git.go, pkg/downloader/get_git_retry_test.go
Expands isRetryableGitError() to recognize additional transient patterns (HTTP 5xx-like transport messages, DNS resolution failures, early EOF) and adds regression tests including non-retryable 4xx cases (404, 401).

Default source provisioning retry configuration

Layer / File(s) Summary
Default retry configuration and VendorSource integration
pkg/provisioner/source/vendor.go, pkg/provisioner/source/vendor_test.go
Adds defaultProvisionRetryConfig() returning a conservative exponential backoff schema.RetryConfig (3 attempts, 2s–30s delay, 2× multiplier, 0.1 jitter) and updates VendorSource to always supply a retry config (use provided or defaults). Includes a unit test validating defaults.

Logging adjustment

Layer / File(s) Summary
Debug-level hook logging
cmd/terraform/utils.go
Changes the hook execution log from Info to Debug while preserving the message and event field.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant gitCommandContext
  participant GitServer
  Caller->>gitCommandContext: build git cmd with -c http.lowSpeedLimit/time and setupGitEnv (GIT_SSH_COMMAND)
  gitCommandContext->>GitServer: execute network git subcommand (ls-remote/clone/fetch/pull/submodule update)
  GitServer-->>gitCommandContext: output or transient error
  gitCommandContext-->>Caller: return output/exit status (retry decision uses isRetryableGitError)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • aknysh
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding network timeout bounds to git commands and extending retry logic for transient 5xx errors.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osterman/go-getter-timeout-retries

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
pkg/provisioner/source/vendor.go (1)

34-52: 💤 Low value

Tiny nit: locals are only needed for addressability.

The intermediate locals exist solely so you can take addresses of literal values. That's fine and idiomatic, but if you want to trim a few lines you could inline via a small helper like ptr[T any](v T) *T { return &v }. Totally optional — current form is perfectly readable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/provisioner/source/vendor.go` around lines 34 - 52, The local variables
in defaultProvisionRetryConfig (maxAttempts, initialDelay, maxDelay, multiplier,
jitter) are only created to take addresses of literals; replace them by using a
small generic helper ptr[T any](v T) *T and call
ptr(defaultProvisionRetryMaxAttempts), ptr(defaultProvisionRetryInitialDelay),
etc., when constructing the schema.RetryConfig in defaultProvisionRetryConfig so
you can remove the intermediate locals and keep the same addressable values.
pkg/provisioner/source/vendor_test.go (1)

705-719: ⚡ Quick win

Consider also asserting the defaults flow through VendorSource.

The test pins the field values nicely, but there's no coverage confirming that VendorSource actually falls back to defaultProvisionRetryConfig() when sourceSpec.Retry is nil (and uses the user-provided one when set). A small test with an injectable/fake downloader, or asserting the option list passed to NewGoGetterDownloader, would lock down the wiring you just added in lines 117-121 of vendor.go. Happy to sketch one if useful.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/provisioner/source/vendor_test.go` around lines 705 - 719, Add a unit
test that verifies VendorSource uses defaultProvisionRetryConfig() when
sourceSpec.Retry is nil and uses the provided Retry when set by creating a
VendorSource (or calling the factory function that constructs it) with an
injectable/fake downloader or by spying the options passed to
NewGoGetterDownloader; assert that the retry-related option values passed into
NewGoGetterDownloader (or observed on the fake downloader) equal the defaults
from defaultProvisionRetryConfig() in the nil case and equal the user-provided
values in the non-nil case, referencing VendorSource,
defaultProvisionRetryConfig, NewGoGetterDownloader and sourceSpec.Retry to
locate the wiring to test.
pkg/downloader/get_git_network_test.go (1)

24-33: ⚡ Quick win

Assert arg order directly for the prepend contract.

Current contains-checks won’t fail if -c flags move after the subcommand. Since this test’s contract is ordering, assert positional args.

Suggested patch.
-	joined := strings.Join(cmd.Args, " ")
-	assert.Contains(t, joined, "-c http.lowSpeedLimit="+gitHTTPLowSpeedLimit)
-	assert.Contains(t, joined, "-c http.lowSpeedTime="+gitHTTPLowSpeedTime)
-
-	// The actual subcommand must still be present after the -c flags.
-	assert.Contains(t, joined, "clone")
-	assert.Contains(t, joined, "https://example.com/repo.git")
+	assert.GreaterOrEqual(t, len(cmd.Args), 8)
+	assert.Equal(t, "-c", cmd.Args[1])
+	assert.Equal(t, "http.lowSpeedLimit="+gitHTTPLowSpeedLimit, cmd.Args[2])
+	assert.Equal(t, "-c", cmd.Args[3])
+	assert.Equal(t, "http.lowSpeedTime="+gitHTTPLowSpeedTime, cmd.Args[4])
+	assert.Equal(t, "clone", cmd.Args[5])
+	assert.Equal(t, "https://example.com/repo.git", cmd.Args[6])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/downloader/get_git_network_test.go` around lines 24 - 33, The test
currently only checks substrings in joined (strings.Join(cmd.Args, " ")) which
won't guarantee ordering; update the assertions to check positional ordering on
cmd.Args directly: verify that the two -c flags ("-c
http.lowSpeedLimit="+gitHTTPLowSpeedLimit and "-c
http.lowSpeedTime="+gitHTTPLowSpeedTime) appear in cmd.Args before the
subcommand "clone" and the repo URL "https://example.com/repo.git". Use
index/position checks on cmd.Args (not joined) so the prepend contract for the
network-tuning flags is enforced.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/downloader/get_git_network_test.go`:
- Around line 41-47: The test currently captures the first GIT_SSH_COMMAND it
sees by breaking out of the loop, which can return a stale value when multiple
entries exist; update the lookup logic for cmd.Env so it iterates the whole
slice and assigns sshEnv to the last matching "GIT_SSH_COMMAND=" entry (i.e.,
remove the break and keep overwriting sshEnv), and/or make the test
deterministic by sanitizing cmd.Env before running (remove duplicate
GIT_SSH_COMMAND entries or explicitly set the expected single value); apply the
same fix to the other identical loop that inspects cmd.Env around the other
assertion.

---

Nitpick comments:
In `@pkg/downloader/get_git_network_test.go`:
- Around line 24-33: The test currently only checks substrings in joined
(strings.Join(cmd.Args, " ")) which won't guarantee ordering; update the
assertions to check positional ordering on cmd.Args directly: verify that the
two -c flags ("-c http.lowSpeedLimit="+gitHTTPLowSpeedLimit and "-c
http.lowSpeedTime="+gitHTTPLowSpeedTime) appear in cmd.Args before the
subcommand "clone" and the repo URL "https://example.com/repo.git". Use
index/position checks on cmd.Args (not joined) so the prepend contract for the
network-tuning flags is enforced.

In `@pkg/provisioner/source/vendor_test.go`:
- Around line 705-719: Add a unit test that verifies VendorSource uses
defaultProvisionRetryConfig() when sourceSpec.Retry is nil and uses the provided
Retry when set by creating a VendorSource (or calling the factory function that
constructs it) with an injectable/fake downloader or by spying the options
passed to NewGoGetterDownloader; assert that the retry-related option values
passed into NewGoGetterDownloader (or observed on the fake downloader) equal the
defaults from defaultProvisionRetryConfig() in the nil case and equal the
user-provided values in the non-nil case, referencing VendorSource,
defaultProvisionRetryConfig, NewGoGetterDownloader and sourceSpec.Retry to
locate the wiring to test.

In `@pkg/provisioner/source/vendor.go`:
- Around line 34-52: The local variables in defaultProvisionRetryConfig
(maxAttempts, initialDelay, maxDelay, multiplier, jitter) are only created to
take addresses of literals; replace them by using a small generic helper ptr[T
any](v T) *T and call ptr(defaultProvisionRetryMaxAttempts),
ptr(defaultProvisionRetryInitialDelay), etc., when constructing the
schema.RetryConfig in defaultProvisionRetryConfig so you can remove the
intermediate locals and keep the same addressable values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 72b7837e-e5c6-4771-9481-fa7444a78228

📥 Commits

Reviewing files that changed from the base of the PR and between b010bae and 28f8210.

📒 Files selected for processing (7)
  • cmd/terraform/utils.go
  • pkg/downloader/get_git.go
  • pkg/downloader/get_git_network_test.go
  • pkg/downloader/get_git_retry_test.go
  • pkg/downloader/get_git_test.go
  • pkg/provisioner/source/vendor.go
  • pkg/provisioner/source/vendor_test.go

Comment thread pkg/downloader/get_git_network_test.go Outdated
@codecov

codecov Bot commented May 21, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.10145% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.59%. Comparing base (0a1d3ad) to head (17066e5).
⚠️ Report is 192 commits behind head on main.

Files with missing lines Patch % Lines
pkg/downloader/get_git.go 96.07% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2463      +/-   ##
==========================================
+ Coverage   78.54%   78.59%   +0.05%     
==========================================
  Files        1144     1144              
  Lines      109984   110037      +53     
==========================================
+ Hits        86387    86485      +98     
+ Misses      18807    18760      -47     
- Partials     4790     4792       +2     
Flag Coverage Δ
unittests 78.59% <97.10%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cmd/terraform/utils.go 58.77% <100.00%> (ø)
pkg/provisioner/source/vendor.go 64.89% <100.00%> (+9.19%) ⬆️
pkg/downloader/get_git.go 86.51% <96.07%> (+1.92%) ⬆️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

setupGitEnv only filters non-empty inherited GIT_SSH_COMMAND values, so
when the parent env has GIT_SSH_COMMAND="" the resulting cmd.Env carries
both the empty entry and the new augmented one. A first-match loop reads
the wrong value.

- Pull the lookup into a tiny helper that walks the whole slice and
  returns the last GIT_SSH_COMMAND= entry (last-wins is how effective
  env actually evaluates in practice).
- Scrub GIT_SSH_COMMAND via t.Setenv at the top of both network tests
  so the baseline is deterministic regardless of CI shell config.

Addresses CodeRabbit review feedback on PR #2463.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
CI's gofumpt is stricter than the locally-installed version and required:
- log.Debug call's first argument moved to its own line in cmd/terraform/utils.go.
- append() and fmt.Errorf() multi-line arg lists with a leading break and a
  trailing comma + closing paren on their own lines in pkg/downloader/get_git.go.

No behavior change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
Comment thread pkg/downloader/get_git.go Outdated
Comment on lines +93 to +94
gitHTTPLowSpeedLimit = "1000"
gitHTTPLowSpeedTime = "30"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe support envars to control overrides for this?

Comment thread pkg/downloader/get_git.go Outdated
Comment on lines +98 to +100
sshConnectTimeoutSeconds = "30"
sshServerAliveInterval = "15"
sshServerAliveCountMax = "4"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, env var overrides

Defaults stay the same (1 KB/s for 30 s on HTTP, 30 s connect / 15 s
keepalive on SSH) but each knob is now overridable per-environment:

- ATMOS_GIT_HTTP_LOW_SPEED_LIMIT  (bytes/sec)
- ATMOS_GIT_HTTP_LOW_SPEED_TIME   (seconds)
- ATMOS_GIT_SSH_CONNECT_TIMEOUT   (seconds)
- ATMOS_GIT_SSH_SERVER_ALIVE_INTERVAL (seconds)
- ATMOS_GIT_SSH_SERVER_ALIVE_COUNT_MAX (count)

A shared numericEnvOr() helper validates the override is a non-negative
integer; anything else (typos like "60s", negatives) logs a warning and
falls back to the default so a misconfigured env var can never silently
disable the timeout. Unit tests cover the override path, the validator's
rejection of bad input, and the empty-string fallthrough.

These are runtime-tuning env vars, not Atmos config — read via os.Getenv
with //nolint:forbidigo matching the precedent in pkg/config/git_root.go
and pkg/config/utils.go (ATMOS_VERSION_ENFORCEMENT).

Addresses review feedback on PR #2463.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/downloader/get_git_network_test.go (1)

21-33: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert argument order directly in the prepend test.

This currently proves presence, not ordering. The test can pass even if -c flags drift after clone, which weakens the prepend contract.

Suggested patch.
 func TestGitCommandContext_PrependsNetworkArgs(t *testing.T) {
 	cmd := gitCommandContext(t.Context(), "clone", "https://example.com/repo.git", "/tmp/dst")
 
-	// cmd.Args[0] is the resolved git binary path; subsequent args must lead
-	// with the network-tuning -c flags before the subcommand.
-	joined := strings.Join(cmd.Args, " ")
-	assert.Contains(t, joined, "-c http.lowSpeedLimit="+defaultGitHTTPLowSpeedLimit)
-	assert.Contains(t, joined, "-c http.lowSpeedTime="+defaultGitHTTPLowSpeedTime)
-
-	// The actual subcommand must still be present after the -c flags.
-	assert.Contains(t, joined, "clone")
-	assert.Contains(t, joined, "https://example.com/repo.git")
+	// cmd.Args[0] is the resolved git binary path; subsequent args must lead
+	// with the network-tuning -c flags before the subcommand.
+	assert.Equal(t, "-c", cmd.Args[1])
+	assert.Equal(t, "http.lowSpeedLimit="+defaultGitHTTPLowSpeedLimit, cmd.Args[2])
+	assert.Equal(t, "-c", cmd.Args[3])
+	assert.Equal(t, "http.lowSpeedTime="+defaultGitHTTPLowSpeedTime, cmd.Args[4])
+	assert.Equal(t, "clone", cmd.Args[5])
+	assert.Equal(t, "https://example.com/repo.git", cmd.Args[6])
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/downloader/get_git_network_test.go` around lines 21 - 33, The test
TestGitCommandContext_PrependsNetworkArgs currently only checks presence of the
-c flags; change it to assert ordering by inspecting cmd.Args (from
gitCommandContext) and ensuring the indices of "-c
http.lowSpeedLimit="+defaultGitHTTPLowSpeedLimit and "-c
http.lowSpeedTime="+defaultGitHTTPLowSpeedTime are both less than the index of
the subcommand "clone"; use index lookup on cmd.Args (or iterate to find
positions) and assert pos(flag) < pos("clone") for each flag so the test
verifies the flags are prepended, not just present.
🧹 Nitpick comments (1)
pkg/downloader/get_git_network_test.go (1)

77-97: ⚡ Quick win

Use a table-driven test for numeric override scenarios.

These four tests cover one function with scenario variations; folding into one table-driven test reduces repetition and makes future cases easier to add.

Suggested refactor.
-func TestNumericEnvOr_AcceptsValidOverride(t *testing.T) {
-	t.Setenv(envGitHTTPLowSpeedTime, "60")
-	assert.Equal(t, "60", gitHTTPLowSpeedTime(), "valid override should win over default")
-}
-
-func TestNumericEnvOr_RejectsNonNumericOverride(t *testing.T) {
-	// A typo like "60s" must not silently disable the timeout (git would error
-	// or interpret it as 0). Fall back to the safe default.
-	t.Setenv(envGitHTTPLowSpeedTime, "60s")
-	assert.Equal(t, defaultGitHTTPLowSpeedTime, gitHTTPLowSpeedTime())
-}
-
-func TestNumericEnvOr_RejectsNegativeOverride(t *testing.T) {
-	t.Setenv(envGitHTTPLowSpeedTime, "-1")
-	assert.Equal(t, defaultGitHTTPLowSpeedTime, gitHTTPLowSpeedTime())
-}
-
-func TestNumericEnvOr_EmptyValueFallsBackToDefault(t *testing.T) {
-	t.Setenv(envGitHTTPLowSpeedTime, "")
-	assert.Equal(t, defaultGitHTTPLowSpeedTime, gitHTTPLowSpeedTime())
-}
+func TestNumericEnvOr_GitHTTPLowSpeedTime(t *testing.T) {
+	tests := []struct {
+		name  string
+		value string
+		want  string
+	}{
+		{name: "accepts valid override", value: "60", want: "60"},
+		{name: "rejects non-numeric override", value: "60s", want: defaultGitHTTPLowSpeedTime},
+		{name: "rejects negative override", value: "-1", want: defaultGitHTTPLowSpeedTime},
+		{name: "empty value falls back to default", value: "", want: defaultGitHTTPLowSpeedTime},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Setenv(envGitHTTPLowSpeedTime, tc.value)
+			assert.Equal(t, tc.want, gitHTTPLowSpeedTime())
+		})
+	}
+}
As per coding guidelines: "Use table-driven tests for testing multiple scenarios in Go."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/downloader/get_git_network_test.go` around lines 77 - 97, Combine the
four similar tests into a single table-driven test (e.g., TestNumericEnvOr) that
iterates over cases with fields like name, envValue, and expected; for each case
call t.Run(case.name, func(t *testing.T) { t.Setenv(envGitHTTPLowSpeedTime,
case.envValue); assert.Equal(t, case.expected, gitHTTPLowSpeedTime()) }). Use
the existing symbols envGitHTTPLowSpeedTime, defaultGitHTTPLowSpeedTime and the
gitHTTPLowSpeedTime() helper to build the cases for "60" -> "60", "60s" ->
defaultGitHTTPLowSpeedTime, "-1" -> defaultGitHTTPLowSpeedTime, and "" ->
defaultGitHTTPLowSpeedTime. Ensure each case uses t.Run so failures are reported
per scenario.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/downloader/get_git_network_test.go`:
- Around line 21-33: The test TestGitCommandContext_PrependsNetworkArgs
currently only checks presence of the -c flags; change it to assert ordering by
inspecting cmd.Args (from gitCommandContext) and ensuring the indices of "-c
http.lowSpeedLimit="+defaultGitHTTPLowSpeedLimit and "-c
http.lowSpeedTime="+defaultGitHTTPLowSpeedTime are both less than the index of
the subcommand "clone"; use index lookup on cmd.Args (or iterate to find
positions) and assert pos(flag) < pos("clone") for each flag so the test
verifies the flags are prepended, not just present.

---

Nitpick comments:
In `@pkg/downloader/get_git_network_test.go`:
- Around line 77-97: Combine the four similar tests into a single table-driven
test (e.g., TestNumericEnvOr) that iterates over cases with fields like name,
envValue, and expected; for each case call t.Run(case.name, func(t *testing.T) {
t.Setenv(envGitHTTPLowSpeedTime, case.envValue); assert.Equal(t, case.expected,
gitHTTPLowSpeedTime()) }). Use the existing symbols envGitHTTPLowSpeedTime,
defaultGitHTTPLowSpeedTime and the gitHTTPLowSpeedTime() helper to build the
cases for "60" -> "60", "60s" -> defaultGitHTTPLowSpeedTime, "-1" ->
defaultGitHTTPLowSpeedTime, and "" -> defaultGitHTTPLowSpeedTime. Ensure each
case uses t.Run so failures are reported per scenario.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 93b017c6-9c8c-46b1-af2f-af99b3f10e74

📥 Commits

Reviewing files that changed from the base of the PR and between fdff000 and 17066e5.

📒 Files selected for processing (3)
  • pkg/downloader/get_git.go
  • pkg/downloader/get_git_network_test.go
  • pkg/downloader/get_git_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/downloader/get_git.go
  • pkg/downloader/get_git_test.go

@mergify

mergify Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflict This PR has conflicts patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant