fix: follow-up fixes for conditional VCS requests (#27711)

Follow-ups from #27627 

- Memoizes `Config.Git()` with a mutex so the provider's ETag response
cache survives across calls. Only successful construction is cached;
errors are retried.
- Moves the HTTP client onto `Config.HTTPClient`, wired through
`ConvertConfig`, so `Git()` no longer takes a per-call argument that
would be silently ignored after memoization.
- `newGitHub` and `newGitLab` now return `(Provider, error)`,
eliminating the typed-nil-interface class in `gitprovider.New` rather
than the single instance.
- Gates the 304 branch on a `haveCached` flag instead of a nil body
check.
- Only caches bodies that decode successfully, preventing poisoned
entries.
- Keys the response cache on the full token digest rather than a
truncated prefix.
- Tests added: `TestConfigGitMemoizesProvider`,
`TestConfigGitRetriesOnConstructorError`,
`TestGitLabConstructorErrorReturnsNilInterface`,
`TestResponseCacheStore`,
`TestConditionalRequestReuse/MalformedResponseNotCached`;
`TestConvertYAML/CustomScopesAndEndpoint` now asserts
`Config.HTTPClient` wiring.

Follow-ups tracked in #28139, #28140, #28141, #28142.

> 🤖 Generated by Coder Agents on behalf of @johnstcn.
This commit is contained in:
Cian Johnston
2026-08-18 09:00:20 +01:00
committed by GitHub
parent b674d40d39
commit 6079c514ee
11 changed files with 273 additions and 52 deletions
@@ -1061,4 +1061,40 @@ func TestConditionalRequestReuse(t *testing.T) {
assert.Equal(t, 0, conditionalRequests,
"a different token must not send If-None-Match from another token's cache")
})
t.Run("MalformedResponseNotCached", func(t *testing.T) {
t.Parallel()
const etag = `"poison-etag"`
var conditionalRequests int
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("If-None-Match") != "" {
conditionalRequests++
w.Header().Set("ETag", etag)
w.WriteHeader(http.StatusNotModified)
return
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("ETag", etag)
// A body that cannot be decoded as a pull request list.
_, _ = w.Write([]byte(`<html>proxy error</html>`))
}))
defer srv.Close()
gp, err := gitprovider.New("github", srv.URL+"/api/v3", srv.Client())
require.NoError(t, err)
require.NotNil(t, gp)
branch := gitprovider.BranchRef{Owner: "owner", Repo: "repo", Branch: "feat"}
_, err = gp.ResolveBranchPullRequest(context.Background(), "test-token", branch)
require.Error(t, err)
_, err = gp.ResolveBranchPullRequest(context.Background(), "test-token", branch)
require.Error(t, err)
assert.Equal(t, 0, conditionalRequests,
"a body that failed to decode must not be cached with its ETag")
})
}