From e6dfcd3ce728af3af5d25839203a7b458b63bc06 Mon Sep 17 00:00:00 2001 From: "Babak K. Shandiz" Date: Wed, 27 May 2026 18:07:19 +0100 Subject: [PATCH 1/2] fix: use separate http client for non-github hosts Signed-off-by: Babak K. Shandiz Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com> --- api/http_client.go | 44 +++++++++++ api/http_client_test.go | 49 ++++++++++++ internal/codespaces/api/api.go | 30 ++++---- internal/codespaces/codespaces.go | 6 +- internal/codespaces/codespaces_test.go | 4 +- pkg/cmd/attestation/api/client.go | 23 +++--- pkg/cmd/attestation/api/client_test.go | 52 ++++++------- pkg/cmd/attestation/download/download.go | 7 +- pkg/cmd/attestation/download/download_test.go | 9 +-- pkg/cmd/attestation/inspect/inspect.go | 15 ++-- .../attestation/trustedroot/trustedroot.go | 10 ++- .../trustedroot/trustedroot_test.go | 9 +++ pkg/cmd/attestation/verification/sigstore.go | 12 +-- pkg/cmd/attestation/verify/verify.go | 15 ++-- pkg/cmd/attestation/verify/verify_test.go | 3 + pkg/cmd/codespace/common.go | 2 +- pkg/cmd/codespace/mock_api.go | 74 +++++++++---------- pkg/cmd/codespace/ports_test.go | 2 +- pkg/cmd/factory/default.go | 11 +++ pkg/cmd/release/shared/attestation.go | 18 ++--- pkg/cmd/release/verify-asset/verify_asset.go | 15 ++-- .../release/verify-asset/verify_asset_test.go | 3 + pkg/cmd/release/verify/verify.go | 15 ++-- pkg/cmd/release/verify/verify_test.go | 3 + pkg/cmdutil/factory.go | 6 +- 25 files changed, 294 insertions(+), 143 deletions(-) diff --git a/api/http_client.go b/api/http_client.go index 206b8ed56a8..078a2a86c8a 100644 --- a/api/http_client.go +++ b/api/http_client.go @@ -86,6 +86,50 @@ func NewHTTPClient(opts HTTPClientOptions) (*http.Client, error) { return client, nil } +// ExternalHTTPClientOptions holds options for creating an external HTTP client. +type ExternalHTTPClientOptions struct { + AppVersion string + Log io.Writer + LogColorize bool + Transport http.RoundTripper +} + +// NewExternalHTTPClient creates an HTTP client for talking to non-GitHub hosts. +// It includes debug logging and a User-Agent header but does not attach any +// authentication tokens or GitHub-specific headers. +func NewExternalHTTPClient(opts ExternalHTTPClientOptions) (*http.Client, error) { + clientOpts := ghAPI.ClientOptions{ + Host: "none", + AuthToken: "none", + LogIgnoreEnv: true, + SkipDefaultHeaders: true, + Transport: opts.Transport, + } + + debugEnabled, debugValue := utils.IsDebugEnabled() + logVerboseHTTP := false + if strings.Contains(debugValue, "api") { + logVerboseHTTP = true + } + + if logVerboseHTTP || debugEnabled { + clientOpts.Log = opts.Log + clientOpts.LogColorize = opts.LogColorize + clientOpts.LogVerboseHTTP = logVerboseHTTP + } + + clientOpts.Headers = map[string]string{ + userAgent: fmt.Sprintf("GitHub CLI %s", opts.AppVersion), + } + + client, err := ghAPI.NewHTTPClient(clientOpts) + if err != nil { + return nil, err + } + + return client, nil +} + func NewCachedHTTPClient(httpClient *http.Client, ttl time.Duration) *http.Client { newClient := *httpClient newClient.Transport = AddCacheTTLHeader(httpClient.Transport, ttl) diff --git a/api/http_client_test.go b/api/http_client_test.go index 198c0849118..56be00af6b0 100644 --- a/api/http_client_test.go +++ b/api/http_client_test.go @@ -381,6 +381,55 @@ func TestNewHTTPClientWithoutTelemetryDisabler(t *testing.T) { assert.Equal(t, 204, res.StatusCode) } +func TestNewExternalHTTPClient(t *testing.T) { + tests := []struct { + name string + url string + }{ + { + name: "third-party host", + url: "https://example.com/path", + }, + { + // Even when talking to GitHub, the external client must not set + // authorization or any GitHub-specific headers. + name: "github.com host", + url: "https://api.github.com/repos/cli/cli", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var gotReq *http.Request + transport := &funcTripper{roundTrip: func(req *http.Request) (*http.Response, error) { + gotReq = req + return &http.Response{StatusCode: 204, Body: io.NopCloser(strings.NewReader(""))}, nil + }} + + client, err := NewExternalHTTPClient(ExternalHTTPClientOptions{ + AppVersion: "v1.2.3", + Transport: transport, + }) + require.NoError(t, err) + + req, err := http.NewRequest("GET", tt.url, nil) + require.NoError(t, err) + + res, err := client.Do(req) + require.NoError(t, err) + assert.Equal(t, 204, res.StatusCode) + + // No headers should be set by default, except for User-Agent which should include the app version. + assert.Equal(t, []string{"GitHub CLI v1.2.3"}, gotReq.Header.Values("user-agent")) + assert.Empty(t, gotReq.Header.Values("authorization")) + assert.Empty(t, gotReq.Header.Values("x-github-api-version")) + assert.Empty(t, gotReq.Header.Values("accept")) + assert.Empty(t, gotReq.Header.Values("content-type")) + assert.Empty(t, gotReq.Header.Values("time-zone")) + }) + } +} + type fakeTelemetryDisabler struct { disabled bool } diff --git a/internal/codespaces/api/api.go b/internal/codespaces/api/api.go index 0d1eaf5b34f..2bd0a5e3be6 100644 --- a/internal/codespaces/api/api.go +++ b/internal/codespaces/api/api.go @@ -60,10 +60,11 @@ const ( // API is the interface to the codespace service. type API struct { - client func() (*http.Client, error) - githubAPI string - githubServer string - retryBackoff time.Duration + client func() (*http.Client, error) + externalClient func() (*http.Client, error) + githubAPI string + githubServer string + retryBackoff time.Duration } // New creates a new API client connecting to the configured endpoints with the HTTP client. @@ -93,10 +94,11 @@ func New(f *cmdutil.Factory) *API { } return &API{ - client: f.HttpClient, - githubAPI: strings.TrimSuffix(apiURL, "/"), - githubServer: strings.TrimSuffix(serverURL, "/"), - retryBackoff: 100 * time.Millisecond, + client: f.HttpClient, + externalClient: f.ExternalHttpClient, + githubAPI: strings.TrimSuffix(apiURL, "/"), + githubServer: strings.TrimSuffix(serverURL, "/"), + retryBackoff: 100 * time.Millisecond, } } @@ -1214,12 +1216,8 @@ func (a *API) withRetry(f func() (*http.Response, error)) (*http.Response, error }, backoff.WithMaxRetries(bo, 3)) } -// HTTPClient returns the HTTP client used to make requests to the API. -func (a *API) HTTPClient() (*http.Client, error) { - httpClient, err := a.client() - if err != nil { - return nil, err - } - - return httpClient, nil +// ExternalHTTPClient returns an HTTP client for requests to non-GitHub hosts. +// It must not carry GitHub authentication credentials. +func (a *API) ExternalHTTPClient() (*http.Client, error) { + return a.externalClient() } diff --git a/internal/codespaces/codespaces.go b/internal/codespaces/codespaces.go index 92185120a2e..c30e126abc6 100644 --- a/internal/codespaces/codespaces.go +++ b/internal/codespaces/codespaces.go @@ -39,7 +39,7 @@ func connectionReady(codespace *api.Codespace) bool { type apiClient interface { GetCodespace(ctx context.Context, name string, includeConnection bool) (*api.Codespace, error) StartCodespace(ctx context.Context, name string) error - HTTPClient() (*http.Client, error) + ExternalHTTPClient() (*http.Client, error) } type progressIndicator interface { @@ -66,12 +66,12 @@ func GetCodespaceConnection(ctx context.Context, progress progressIndicator, api progress.StartProgressIndicatorWithLabel("Connecting to codespace") defer progress.StopProgressIndicator() - httpClient, err := apiClient.HTTPClient() + externalHttpClient, err := apiClient.ExternalHTTPClient() if err != nil { return nil, fmt.Errorf("error getting http client: %w", err) } - return connection.NewCodespaceConnection(ctx, codespace, httpClient) + return connection.NewCodespaceConnection(ctx, codespace, externalHttpClient) } // waitUntilCodespaceConnectionReady waits for a Codespace to be running and is able to be connected to. diff --git a/internal/codespaces/codespaces_test.go b/internal/codespaces/codespaces_test.go index d931b96ef4b..aceb970483f 100644 --- a/internal/codespaces/codespaces_test.go +++ b/internal/codespaces/codespaces_test.go @@ -202,8 +202,8 @@ func (m *mockApiClient) GetCodespace(ctx context.Context, name string, includeCo return m.onGetCodespace() } -func (m *mockApiClient) HTTPClient() (*http.Client, error) { - panic("Not implemented") +func (m *mockApiClient) ExternalHTTPClient() (*http.Client, error) { + return nil, nil } type mockProgressIndicator struct{} diff --git a/pkg/cmd/attestation/api/client.go b/pkg/cmd/attestation/api/client.go index 469b1a1a1d9..41c713d7c0c 100644 --- a/pkg/cmd/attestation/api/client.go +++ b/pkg/cmd/attestation/api/client.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + neturl "net/url" "strings" "time" @@ -67,18 +68,18 @@ type Client interface { } type LiveClient struct { - githubAPI githubApiClient - httpClient httpClient - host string - logger *ioconfig.Handler + githubAPI githubApiClient + externalHttpClient httpClient + host string + logger *ioconfig.Handler } -func NewLiveClient(hc *http.Client, host string, l *ioconfig.Handler) *LiveClient { +func NewLiveClient(hc *http.Client, externalClient *http.Client, host string, l *ioconfig.Handler) *LiveClient { return &LiveClient{ - githubAPI: api.NewClientFromHTTP(hc), - host: strings.TrimSuffix(host, "/"), - httpClient: hc, - logger: l, + githubAPI: api.NewClientFromHTTP(hc), + host: strings.TrimSuffix(host, "/"), + externalHttpClient: externalClient, + logger: l, } } @@ -121,7 +122,7 @@ func (c *LiveClient) buildRequestURL(params FetchParams) (string, error) { // ref: https://github.com/cli/go-gh/blob/d32c104a9a25c9de3d7c7b07a43ae0091441c858/example_gh_test.go#L96 url = fmt.Sprintf("%s?per_page=%d", url, perPage) if params.PredicateType != "" { - url = fmt.Sprintf("%s&predicate_type=%s", url, params.PredicateType) + url = fmt.Sprintf("%s&predicate_type=%s", url, neturl.QueryEscape(params.PredicateType)) } return url, nil } @@ -225,7 +226,7 @@ func (c *LiveClient) getBundle(url string) (*bundle.Bundle, error) { var sgBundle *bundle.Bundle bo := backoff.NewConstantBackOff(getAttestationRetryInterval) err := backoff.Retry(func() error { - resp, err := c.httpClient.Get(url) + resp, err := c.externalHttpClient.Get(url) if err != nil { return fmt.Errorf("request to fetch bundle from URL failed: %w", err) } diff --git a/pkg/cmd/attestation/api/client_test.go b/pkg/cmd/attestation/api/client_test.go index d9381612dd2..e27297b51d2 100644 --- a/pkg/cmd/attestation/api/client_test.go +++ b/pkg/cmd/attestation/api/client_test.go @@ -28,8 +28,8 @@ func NewClientWithMockGHClient(hasNextPage bool) Client { githubAPI: mockAPIClient{ OnRESTWithNext: fetcher.OnRESTSuccessWithNextPage, }, - httpClient: httpClient, - logger: l, + externalHttpClient: httpClient, + logger: l, } } @@ -37,8 +37,8 @@ func NewClientWithMockGHClient(hasNextPage bool) Client { githubAPI: mockAPIClient{ OnRESTWithNext: fetcher.OnRESTSuccess, }, - httpClient: httpClient, - logger: l, + externalHttpClient: httpClient, + logger: l, } } @@ -137,8 +137,8 @@ func TestGetByDigest_NoAttestationsFound(t *testing.T) { githubAPI: mockAPIClient{ OnRESTWithNext: fetcher.OnRESTWithNextNoAttestations, }, - httpClient: httpClient, - logger: io.NewTestHandler(), + externalHttpClient: httpClient, + logger: io.NewTestHandler(), } attestations, err := c.GetByDigest(testFetchParamsWithRepo) @@ -167,8 +167,8 @@ func TestGetByDigest_Error(t *testing.T) { func TestFetchBundleFromAttestations_BundleURL(t *testing.T) { httpClient := &mockHttpClient{} client := LiveClient{ - httpClient: httpClient, - logger: io.NewTestHandler(), + externalHttpClient: httpClient, + logger: io.NewTestHandler(), } att1 := makeTestAttestation() @@ -184,8 +184,8 @@ func TestFetchBundleFromAttestations_BundleURL(t *testing.T) { func TestFetchBundleFromAttestations_MissingBundleAndBundleURLFields(t *testing.T) { httpClient := &mockHttpClient{} client := LiveClient{ - httpClient: httpClient, - logger: io.NewTestHandler(), + externalHttpClient: httpClient, + logger: io.NewTestHandler(), } // If both the BundleURL and Bundle fields are empty, the function should @@ -207,8 +207,8 @@ func TestFetchBundleFromAttestations_FailOnTheSecondAttestation(t *testing.T) { } c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } att1 := makeTestAttestation() @@ -223,8 +223,8 @@ func TestFetchBundleFromAttestations_FailAfterRetrying(t *testing.T) { mockHTTPClient := &reqFailHttpClient{} c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } a := makeTestAttestation() @@ -239,8 +239,8 @@ func TestFetchBundleFromAttestations_FallbackToBundleField(t *testing.T) { mockHTTPClient := &mockHttpClient{} c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } // If the bundle URL is empty, the code will fallback to the bundle field @@ -257,8 +257,8 @@ func TestGetBundle(t *testing.T) { mockHTTPClient := &mockHttpClient{} c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } b, err := c.getBundle("https://mybundleurl.com") @@ -276,8 +276,8 @@ func TestGetBundle_SuccessfulRetry(t *testing.T) { } c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } b, err := c.getBundle("mybundleurl") @@ -290,8 +290,8 @@ func TestGetBundle_SuccessfulRetry(t *testing.T) { func TestGetBundle_PermanentBackoffFail(t *testing.T) { mockHTTPClient := &invalidBundleClient{} c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } b, err := c.getBundle("mybundleurl") @@ -307,8 +307,8 @@ func TestGetBundle_RequestFail(t *testing.T) { mockHTTPClient := &reqFailHttpClient{} c := &LiveClient{ - httpClient: mockHTTPClient, - logger: io.NewTestHandler(), + externalHttpClient: mockHTTPClient, + logger: io.NewTestHandler(), } b, err := c.getBundle("mybundleurl") @@ -360,8 +360,8 @@ func TestGetAttestationsRetries(t *testing.T) { githubAPI: mockAPIClient{ OnRESTWithNext: fetcher.FlakyOnRESTSuccessWithNextPageHandler(), }, - httpClient: &mockHttpClient{}, - logger: io.NewTestHandler(), + externalHttpClient: &mockHttpClient{}, + logger: io.NewTestHandler(), } testFetchParamsWithRepo.Limit = 30 diff --git a/pkg/cmd/attestation/download/download.go b/pkg/cmd/attestation/download/download.go index 8d1d1dc0511..f0024018044 100644 --- a/pkg/cmd/attestation/download/download.go +++ b/pkg/cmd/attestation/download/download.go @@ -84,6 +84,11 @@ func NewDownloadCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Comman return err } + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + if opts.Hostname == "" { opts.Hostname, _ = ghauth.DefaultHost() } @@ -91,7 +96,7 @@ func NewDownloadCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Comman return err } - opts.APIClient = api.NewLiveClient(hc, opts.Hostname, opts.Logger) + opts.APIClient = api.NewLiveClient(hc, externalClient, opts.Hostname, opts.Logger) opts.OCIClient = oci.NewLiveClient() opts.Store = NewLiveStore("") diff --git a/pkg/cmd/attestation/download/download_test.go b/pkg/cmd/attestation/download/download_test.go index 11872daf900..d470c7afbce 100644 --- a/pkg/cmd/attestation/download/download_test.go +++ b/pkg/cmd/attestation/download/download_test.go @@ -15,7 +15,6 @@ import ( "github.com/cli/cli/v2/pkg/cmd/attestation/test" "github.com/cli/cli/v2/pkg/cmdutil" - "github.com/cli/cli/v2/pkg/httpmock" "github.com/cli/cli/v2/pkg/iostreams" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -39,10 +38,10 @@ func TestNewDownloadCmd(t *testing.T) { f := &cmdutil.Factory{ IOStreams: testIO, HttpClient: func() (*http.Client, error) { - reg := &httpmock.Registry{} - client := &http.Client{} - httpmock.ReplaceTripper(client, reg) - return client, nil + return nil, nil + }, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil }, } diff --git a/pkg/cmd/attestation/inspect/inspect.go b/pkg/cmd/attestation/inspect/inspect.go index 9a2bb5d3f58..97aa149fb56 100644 --- a/pkg/cmd/attestation/inspect/inspect.go +++ b/pkg/cmd/attestation/inspect/inspect.go @@ -86,17 +86,18 @@ func NewInspectCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command return err } + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + config := verification.SigstoreConfig{ - HttpClient: hc, - Logger: opts.Logger, + ExternalHttpClient: externalClient, + Logger: opts.Logger, } if ghauth.IsTenancy(opts.Hostname) { - hc, err := f.HttpClient() - if err != nil { - return err - } - apiClient := api.NewLiveClient(hc, opts.Hostname, opts.Logger) + apiClient := api.NewLiveClient(hc, externalClient, opts.Hostname, opts.Logger) td, err := apiClient.GetTrustDomain() if err != nil { return fmt.Errorf("error getting trust domain, make sure you are authenticated against the host: %w", err) diff --git a/pkg/cmd/attestation/trustedroot/trustedroot.go b/pkg/cmd/attestation/trustedroot/trustedroot.go index 29dd6fcd9fd..242ebcd1fb3 100644 --- a/pkg/cmd/attestation/trustedroot/trustedroot.go +++ b/pkg/cmd/attestation/trustedroot/trustedroot.go @@ -71,6 +71,12 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com if err != nil { return err } + + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + if ghauth.IsTenancy(opts.Hostname) { c, err := f.Config() if err != nil { @@ -81,7 +87,7 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com return fmt.Errorf("not authenticated with %s", opts.Hostname) } logger := io.NewHandler(f.IOStreams) - apiClient := api.NewLiveClient(hc, opts.Hostname, logger) + apiClient := api.NewLiveClient(hc, externalClient, opts.Hostname, logger) td, err := apiClient.GetTrustDomain() if err != nil { return err @@ -93,7 +99,7 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com return runF(opts) } - if err := getTrustedRoot(tuf.New, opts, hc); err != nil { + if err := getTrustedRoot(tuf.New, opts, externalClient); err != nil { return fmt.Errorf("Failed to verify the TUF repository: %w", err) } diff --git a/pkg/cmd/attestation/trustedroot/trustedroot_test.go b/pkg/cmd/attestation/trustedroot/trustedroot_test.go index 0d67c44459f..02457a42d80 100644 --- a/pkg/cmd/attestation/trustedroot/trustedroot_test.go +++ b/pkg/cmd/attestation/trustedroot/trustedroot_test.go @@ -34,6 +34,9 @@ func TestNewTrustedRootCmd(t *testing.T) { httpmock.ReplaceTripper(client, reg) return client, nil }, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, } testcases := []struct { @@ -120,6 +123,9 @@ func TestNewTrustedRootWithTenancy(t *testing.T) { }, nil }, HttpClient: httpClientFunc, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, } cmd := NewTrustedRootCmd(f, func(_ *Options) error { @@ -148,6 +154,9 @@ func TestNewTrustedRootWithTenancy(t *testing.T) { }, nil }, HttpClient: httpClientFunc, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, } cmd := NewTrustedRootCmd(f, func(_ *Options) error { diff --git a/pkg/cmd/attestation/verification/sigstore.go b/pkg/cmd/attestation/verification/sigstore.go index e76d55a6b60..7ab3e083172 100644 --- a/pkg/cmd/attestation/verification/sigstore.go +++ b/pkg/cmd/attestation/verification/sigstore.go @@ -31,10 +31,10 @@ type AttestationProcessingResult struct { } type SigstoreConfig struct { - TrustedRoot string - Logger *io.Handler - NoPublicGood bool - HttpClient *http.Client + TrustedRoot string + Logger *io.Handler + NoPublicGood bool + ExternalHttpClient *http.Client // If tenancy mode is not used, trust domain is empty TrustDomain string // TUFMetadataDir @@ -76,7 +76,7 @@ func NewLiveSigstoreVerifier(config SigstoreConfig) (*LiveSigstoreVerifier, erro // No custom trusted root is set, so configure Public Good and GitHub verifiers if !config.NoPublicGood { - publicGoodVerifier, err := newPublicGoodVerifier(config.TUFMetadataDir, config.HttpClient) + publicGoodVerifier, err := newPublicGoodVerifier(config.TUFMetadataDir, config.ExternalHttpClient) if err != nil { // Log warning but continue - PGI unavailability should not block GitHub attestation verification config.Logger.VerbosePrintf("Warning: failed to initialize Sigstore Public Good verifier: %v\n", err) @@ -86,7 +86,7 @@ func NewLiveSigstoreVerifier(config SigstoreConfig) (*LiveSigstoreVerifier, erro } } - github, err := newGitHubVerifier(config.TrustDomain, config.TUFMetadataDir, config.HttpClient) + github, err := newGitHubVerifier(config.TrustDomain, config.TUFMetadataDir, config.ExternalHttpClient) if err != nil { config.Logger.VerbosePrintf("Warning: failed to initialize GitHub verifier: %v\n", err) } else { diff --git a/pkg/cmd/attestation/verify/verify.go b/pkg/cmd/attestation/verify/verify.go index 90cc5643c36..120f94d6588 100644 --- a/pkg/cmd/attestation/verify/verify.go +++ b/pkg/cmd/attestation/verify/verify.go @@ -173,6 +173,11 @@ func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command return err } + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + opts.OCIClient = oci.NewLiveClient() if opts.Hostname == "" { @@ -183,13 +188,13 @@ func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command return err } - opts.APIClient = api.NewLiveClient(hc, opts.Hostname, opts.Logger) + opts.APIClient = api.NewLiveClient(hc, externalClient, opts.Hostname, opts.Logger) config := verification.SigstoreConfig{ - HttpClient: hc, - Logger: opts.Logger, - NoPublicGood: opts.NoPublicGood, - TrustedRoot: opts.TrustedRoot, + ExternalHttpClient: externalClient, + Logger: opts.Logger, + NoPublicGood: opts.NoPublicGood, + TrustedRoot: opts.TrustedRoot, } // Prepare for tenancy if detected diff --git a/pkg/cmd/attestation/verify/verify_test.go b/pkg/cmd/attestation/verify/verify_test.go index 2b821a435d9..295d4a30a30 100644 --- a/pkg/cmd/attestation/verify/verify_test.go +++ b/pkg/cmd/attestation/verify/verify_test.go @@ -54,6 +54,9 @@ func TestNewVerifyCmd(t *testing.T) { httpmock.ReplaceTripper(client, reg) return client, nil }, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, } testcases := []struct { diff --git a/pkg/cmd/codespace/common.go b/pkg/cmd/codespace/common.go index e56e6c0b86a..0acb89a511d 100644 --- a/pkg/cmd/codespace/common.go +++ b/pkg/cmd/codespace/common.go @@ -82,7 +82,7 @@ type apiClient interface { ListDevContainers(ctx context.Context, repoID int, branch string, limit int) (devcontainers []api.DevContainerEntry, err error) GetCodespaceRepoSuggestions(ctx context.Context, partialSearch string, params api.RepoSearchParameters) ([]string, error) GetCodespaceBillableOwner(ctx context.Context, nwo string) (*api.User, error) - HTTPClient() (*http.Client, error) + ExternalHTTPClient() (*http.Client, error) } var errNoCodespaces = errors.New("you have no codespaces") diff --git a/pkg/cmd/codespace/mock_api.go b/pkg/cmd/codespace/mock_api.go index e4de0ae7a90..7dc5bf6ce94 100644 --- a/pkg/cmd/codespace/mock_api.go +++ b/pkg/cmd/codespace/mock_api.go @@ -26,6 +26,9 @@ import ( // EditCodespaceFunc: func(ctx context.Context, codespaceName string, params *codespacesAPI.EditCodespaceParams) (*codespacesAPI.Codespace, error) { // panic("mock out the EditCodespace method") // }, +// ExternalHTTPClientFunc: func() (*http.Client, error) { +// panic("mock out the ExternalHTTPClient method") +// }, // GetCodespaceFunc: func(ctx context.Context, name string, includeConnection bool) (*codespacesAPI.Codespace, error) { // panic("mock out the GetCodespace method") // }, @@ -53,9 +56,6 @@ import ( // GetUserFunc: func(ctx context.Context) (*codespacesAPI.User, error) { // panic("mock out the GetUser method") // }, -// HTTPClientFunc: func() (*http.Client, error) { -// panic("mock out the HTTPClient method") -// }, // ListCodespacesFunc: func(ctx context.Context, opts codespacesAPI.ListCodespacesOptions) ([]*codespacesAPI.Codespace, error) { // panic("mock out the ListCodespaces method") // }, @@ -87,6 +87,9 @@ type apiClientMock struct { // EditCodespaceFunc mocks the EditCodespace method. EditCodespaceFunc func(ctx context.Context, codespaceName string, params *codespacesAPI.EditCodespaceParams) (*codespacesAPI.Codespace, error) + // ExternalHTTPClientFunc mocks the ExternalHTTPClient method. + ExternalHTTPClientFunc func() (*http.Client, error) + // GetCodespaceFunc mocks the GetCodespace method. GetCodespaceFunc func(ctx context.Context, name string, includeConnection bool) (*codespacesAPI.Codespace, error) @@ -114,9 +117,6 @@ type apiClientMock struct { // GetUserFunc mocks the GetUser method. GetUserFunc func(ctx context.Context) (*codespacesAPI.User, error) - // HTTPClientFunc mocks the HTTPClient method. - HTTPClientFunc func() (*http.Client, error) - // ListCodespacesFunc mocks the ListCodespaces method. ListCodespacesFunc func(ctx context.Context, opts codespacesAPI.ListCodespacesOptions) ([]*codespacesAPI.Codespace, error) @@ -161,6 +161,9 @@ type apiClientMock struct { // Params is the params argument value. Params *codespacesAPI.EditCodespaceParams } + // ExternalHTTPClient holds details about calls to the ExternalHTTPClient method. + ExternalHTTPClient []struct { + } // GetCodespace holds details about calls to the GetCodespace method. GetCodespace []struct { // Ctx is the ctx argument value. @@ -242,9 +245,6 @@ type apiClientMock struct { // Ctx is the ctx argument value. Ctx context.Context } - // HTTPClient holds details about calls to the HTTPClient method. - HTTPClient []struct { - } // ListCodespaces holds details about calls to the ListCodespaces method. ListCodespaces []struct { // Ctx is the ctx argument value. @@ -288,6 +288,7 @@ type apiClientMock struct { lockCreateCodespace sync.RWMutex lockDeleteCodespace sync.RWMutex lockEditCodespace sync.RWMutex + lockExternalHTTPClient sync.RWMutex lockGetCodespace sync.RWMutex lockGetCodespaceBillableOwner sync.RWMutex lockGetCodespaceRepoSuggestions sync.RWMutex @@ -297,7 +298,6 @@ type apiClientMock struct { lockGetOrgMemberCodespace sync.RWMutex lockGetRepository sync.RWMutex lockGetUser sync.RWMutex - lockHTTPClient sync.RWMutex lockListCodespaces sync.RWMutex lockListDevContainers sync.RWMutex lockServerURL sync.RWMutex @@ -425,6 +425,33 @@ func (mock *apiClientMock) EditCodespaceCalls() []struct { return calls } +// ExternalHTTPClient calls ExternalHTTPClientFunc. +func (mock *apiClientMock) ExternalHTTPClient() (*http.Client, error) { + if mock.ExternalHTTPClientFunc == nil { + panic("apiClientMock.ExternalHTTPClientFunc: method is nil but apiClient.ExternalHTTPClient was just called") + } + callInfo := struct { + }{} + mock.lockExternalHTTPClient.Lock() + mock.calls.ExternalHTTPClient = append(mock.calls.ExternalHTTPClient, callInfo) + mock.lockExternalHTTPClient.Unlock() + return mock.ExternalHTTPClientFunc() +} + +// ExternalHTTPClientCalls gets all the calls that were made to ExternalHTTPClient. +// Check the length with: +// +// len(mockedapiClient.ExternalHTTPClientCalls()) +func (mock *apiClientMock) ExternalHTTPClientCalls() []struct { +} { + var calls []struct { + } + mock.lockExternalHTTPClient.RLock() + calls = mock.calls.ExternalHTTPClient + mock.lockExternalHTTPClient.RUnlock() + return calls +} + // GetCodespace calls GetCodespaceFunc. func (mock *apiClientMock) GetCodespace(ctx context.Context, name string, includeConnection bool) (*codespacesAPI.Codespace, error) { if mock.GetCodespaceFunc == nil { @@ -785,33 +812,6 @@ func (mock *apiClientMock) GetUserCalls() []struct { return calls } -// HTTPClient calls HTTPClientFunc. -func (mock *apiClientMock) HTTPClient() (*http.Client, error) { - if mock.HTTPClientFunc == nil { - panic("apiClientMock.HTTPClientFunc: method is nil but apiClient.HTTPClient was just called") - } - callInfo := struct { - }{} - mock.lockHTTPClient.Lock() - mock.calls.HTTPClient = append(mock.calls.HTTPClient, callInfo) - mock.lockHTTPClient.Unlock() - return mock.HTTPClientFunc() -} - -// HTTPClientCalls gets all the calls that were made to HTTPClient. -// Check the length with: -// -// len(mockedapiClient.HTTPClientCalls()) -func (mock *apiClientMock) HTTPClientCalls() []struct { -} { - var calls []struct { - } - mock.lockHTTPClient.RLock() - calls = mock.calls.HTTPClient - mock.lockHTTPClient.RUnlock() - return calls -} - // ListCodespaces calls ListCodespacesFunc. func (mock *apiClientMock) ListCodespaces(ctx context.Context, opts codespacesAPI.ListCodespacesOptions) ([]*codespacesAPI.Codespace, error) { if mock.ListCodespacesFunc == nil { diff --git a/pkg/cmd/codespace/ports_test.go b/pkg/cmd/codespace/ports_test.go index 034c15eb6c6..bd5cfb4f388 100644 --- a/pkg/cmd/codespace/ports_test.go +++ b/pkg/cmd/codespace/ports_test.go @@ -159,7 +159,7 @@ func GetMockApi(allowOrgPorts bool) *apiClientMock { GetCodespaceRepositoryContentsFunc: func(ctx context.Context, codespace *api.Codespace, path string) ([]byte, error) { return nil, nil }, - HTTPClientFunc: func() (*http.Client, error) { + ExternalHTTPClientFunc: func() (*http.Client, error) { return connection.NewMockHttpClient() }, } diff --git a/pkg/cmd/factory/default.go b/pkg/cmd/factory/default.go index f61e51b452f..cc10075f203 100644 --- a/pkg/cmd/factory/default.go +++ b/pkg/cmd/factory/default.go @@ -34,6 +34,7 @@ func New(appVersion string, invokingAgent string, cfgFunc func() (gh.Config, err f.IOStreams = ios f.HttpClient = HttpClientFunc(cfgFunc, ios, appVersion, invokingAgent, telemetryDisabler) f.PlainHttpClient = plainHttpClientFunc(ios, appVersion, invokingAgent, telemetryDisabler) + f.ExternalHttpClient = externalHttpClientFunc(ios, appVersion) f.GitClient = newGitClient(f) // Depends on IOStreams, and Executable f.Remotes = remotesFunc(f) // Depends on Config, and GitClient f.BaseRepo = BaseRepoFunc(f.Remotes) @@ -226,6 +227,16 @@ func plainHttpClientFunc(ios *iostreams.IOStreams, appVersion string, invokingAg } } +func externalHttpClientFunc(ios *iostreams.IOStreams, appVersion string) func() (*http.Client, error) { + return func() (*http.Client, error) { + return api.NewExternalHTTPClient(api.ExternalHTTPClientOptions{ + AppVersion: appVersion, + Log: ios.ErrOut, + LogColorize: ios.ColorEnabled(), + }) + } +} + func newGitClient(f *cmdutil.Factory) *git.Client { io := f.IOStreams client := &git.Client{ diff --git a/pkg/cmd/release/shared/attestation.go b/pkg/cmd/release/shared/attestation.go index 65990290b67..f26d8eb8b05 100644 --- a/pkg/cmd/release/shared/attestation.go +++ b/pkg/cmd/release/shared/attestation.go @@ -23,10 +23,10 @@ type Verifier interface { } type AttestationVerifier struct { - AttClient api.Client - HttpClient *http.Client - IO *iostreams.IOStreams - TrustedRoot string + AttClient api.Client + ExternalHttpClient *http.Client + IO *iostreams.IOStreams + TrustedRoot string } func (v *AttestationVerifier) VerifyAttestation(art *artifact.DigestedArtifact, att *api.Attestation) (*verification.AttestationProcessingResult, error) { @@ -36,11 +36,11 @@ func (v *AttestationVerifier) VerifyAttestation(art *artifact.DigestedArtifact, } verifier, err := verification.NewLiveSigstoreVerifier(verification.SigstoreConfig{ - HttpClient: v.HttpClient, - Logger: att_io.NewHandler(v.IO), - NoPublicGood: true, - TrustDomain: td, - TrustedRoot: v.TrustedRoot, + ExternalHttpClient: v.ExternalHttpClient, + Logger: att_io.NewHandler(v.IO), + NoPublicGood: true, + TrustDomain: td, + TrustedRoot: v.TrustedRoot, }) if err != nil { return nil, err diff --git a/pkg/cmd/release/verify-asset/verify_asset.go b/pkg/cmd/release/verify-asset/verify_asset.go index 2cebce53bc8..9adacf2cae2 100644 --- a/pkg/cmd/release/verify-asset/verify_asset.go +++ b/pkg/cmd/release/verify-asset/verify_asset.go @@ -83,14 +83,19 @@ func NewCmdVerifyAsset(f *cmdutil.Factory, runF func(*VerifyAssetConfig) error) return err } + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + io := f.IOStreams - attClient := api.NewLiveClient(httpClient, baseRepo.RepoHost(), att_io.NewHandler(io)) + attClient := api.NewLiveClient(httpClient, externalClient, baseRepo.RepoHost(), att_io.NewHandler(io)) attVerifier := &shared.AttestationVerifier{ - AttClient: attClient, - HttpClient: httpClient, - IO: io, - TrustedRoot: opts.TrustedRoot, + AttClient: attClient, + ExternalHttpClient: externalClient, + IO: io, + TrustedRoot: opts.TrustedRoot, } config := &VerifyAssetConfig{ diff --git a/pkg/cmd/release/verify-asset/verify_asset_test.go b/pkg/cmd/release/verify-asset/verify_asset_test.go index dc881ec00a9..7535735aa40 100644 --- a/pkg/cmd/release/verify-asset/verify_asset_test.go +++ b/pkg/cmd/release/verify-asset/verify_asset_test.go @@ -54,6 +54,9 @@ func TestNewCmdVerifyAsset_Args(t *testing.T) { HttpClient: func() (*http.Client, error) { return nil, nil }, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, BaseRepo: func() (ghrepo.Interface, error) { return ghrepo.FromFullName("owner/repo") }, diff --git a/pkg/cmd/release/verify/verify.go b/pkg/cmd/release/verify/verify.go index 39e27bbc50b..c1a9ae4a20a 100644 --- a/pkg/cmd/release/verify/verify.go +++ b/pkg/cmd/release/verify/verify.go @@ -79,14 +79,19 @@ func NewCmdVerify(f *cmdutil.Factory, runF func(config *VerifyConfig) error) *co return err } + externalClient, err := f.ExternalHttpClient() + if err != nil { + return err + } + io := f.IOStreams - attClient := api.NewLiveClient(httpClient, baseRepo.RepoHost(), att_io.NewHandler(io)) + attClient := api.NewLiveClient(httpClient, externalClient, baseRepo.RepoHost(), att_io.NewHandler(io)) attVerifier := &shared.AttestationVerifier{ - AttClient: attClient, - HttpClient: httpClient, - IO: io, - TrustedRoot: opts.TrustedRoot, + AttClient: attClient, + ExternalHttpClient: externalClient, + IO: io, + TrustedRoot: opts.TrustedRoot, } config := &VerifyConfig{ diff --git a/pkg/cmd/release/verify/verify_test.go b/pkg/cmd/release/verify/verify_test.go index ccb3b35a6ba..e2d29bb584b 100644 --- a/pkg/cmd/release/verify/verify_test.go +++ b/pkg/cmd/release/verify/verify_test.go @@ -43,6 +43,9 @@ func TestNewCmdVerify_Args(t *testing.T) { HttpClient: func() (*http.Client, error) { return nil, nil }, + ExternalHttpClient: func() (*http.Client, error) { + return nil, nil + }, BaseRepo: func() (ghrepo.Interface, error) { return ghrepo.FromFullName("owner/repo") }, diff --git a/pkg/cmdutil/factory.go b/pkg/cmdutil/factory.go index 1faf859f00c..200314038b2 100644 --- a/pkg/cmdutil/factory.go +++ b/pkg/cmdutil/factory.go @@ -39,5 +39,9 @@ type Factory struct { // auth and other headers. This is meant to be used in situations where the // client needs to specify the headers itself (e.g. during login). PlainHttpClient func() (*http.Client, error) - Remotes func() (context.Remotes, error) + // ExternalHttpClient is an HTTP client for talking to non-GitHub hosts + // It includes debug logging and a User-Agent header but does not attach any + // authentication tokens or GitHub-specific headers. + ExternalHttpClient func() (*http.Client, error) + Remotes func() (context.Remotes, error) } From 98d91db0e22d4ce7165a182652cc335454e32f7d Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Wed, 27 May 2026 11:26:50 -0600 Subject: [PATCH 2/2] test(attestation): align integration tests with new external HTTP client Commit e6dfcd3ce ("fix: use separate http client for non-github hosts") renamed verification.SigstoreConfig.HttpClient to ExternalHttpClient, added an external *http.Client argument to api.NewLiveClient, and added the corresponding Factory.ExternalHttpClient field. It updated the non-tagged unit tests but missed every //go:build integration file in pkg/cmd/attestation/..., which broke trunk CI (build (ubuntu-latest) and build (macos-latest) in the Unit and Integration Tests workflow): - pkg/cmd/attestation/verification and pkg/cmd/attestation/verify failed to build (unknown field HttpClient; not enough arguments in call to api.NewLiveClient). - TestNewInspectCmd_PrintOutputJSONFormat panicked because the cmdutil.Factory literal it builds did not set ExternalHttpClient, so the new f.ExternalHttpClient() call in inspect.go dereferenced a nil func value. Rename the field at the integration-test call sites, pass http.DefaultClient as the new external client to api.NewLiveClient, and populate ExternalHttpClient on the inspect test factory. No production code changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../inspect/inspect_integration_test.go | 3 ++ .../verification/sigstore_integration_test.go | 32 ++++++++--------- .../verify/attestation_integration_test.go | 6 ++-- .../verify/verify_integration_test.go | 34 +++++++++---------- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/pkg/cmd/attestation/inspect/inspect_integration_test.go b/pkg/cmd/attestation/inspect/inspect_integration_test.go index 6c56461afa9..7c0f1f65bb6 100644 --- a/pkg/cmd/attestation/inspect/inspect_integration_test.go +++ b/pkg/cmd/attestation/inspect/inspect_integration_test.go @@ -21,6 +21,9 @@ func TestNewInspectCmd_PrintOutputJSONFormat(t *testing.T) { HttpClient: func() (*http.Client, error) { return http.DefaultClient, nil }, + ExternalHttpClient: func() (*http.Client, error) { + return http.DefaultClient, nil + }, } t.Run("Print output in JSON format", func(t *testing.T) { diff --git a/pkg/cmd/attestation/verification/sigstore_integration_test.go b/pkg/cmd/attestation/verification/sigstore_integration_test.go index d37b94fc835..daa948b950c 100644 --- a/pkg/cmd/attestation/verification/sigstore_integration_test.go +++ b/pkg/cmd/attestation/verification/sigstore_integration_test.go @@ -52,9 +52,9 @@ func TestLiveSigstoreVerifier(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { verifier, err := NewLiveSigstoreVerifier(SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) @@ -73,9 +73,9 @@ func TestLiveSigstoreVerifier(t *testing.T) { t.Run("with 2/3 verified attestations", func(t *testing.T) { verifier, err := NewLiveSigstoreVerifier(SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) @@ -92,9 +92,9 @@ func TestLiveSigstoreVerifier(t *testing.T) { t.Run("fail with 0/2 verified attestations", func(t *testing.T) { verifier, err := NewLiveSigstoreVerifier(SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) @@ -118,9 +118,9 @@ func TestLiveSigstoreVerifier(t *testing.T) { attestations := getAttestationsFor(t, "../test/data/github_provenance_demo-0.0.12-py3-none-any-bundle.jsonl") verifier, err := NewLiveSigstoreVerifier(SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) @@ -133,10 +133,10 @@ func TestLiveSigstoreVerifier(t *testing.T) { attestations := getAttestationsFor(t, "../test/data/sigstore-js-2.1.0_with_2_bundles.jsonl") verifier, err := NewLiveSigstoreVerifier(SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TrustedRoot: test.NormalizeRelativePath("../test/data/trusted_root.json"), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TrustedRoot: test.NormalizeRelativePath("../test/data/trusted_root.json"), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) diff --git a/pkg/cmd/attestation/verify/attestation_integration_test.go b/pkg/cmd/attestation/verify/attestation_integration_test.go index ec3eb271cb1..bb92489c63f 100644 --- a/pkg/cmd/attestation/verify/attestation_integration_test.go +++ b/pkg/cmd/attestation/verify/attestation_integration_test.go @@ -27,9 +27,9 @@ func getAttestationsFor(t *testing.T, bundlePath string) []*api.Attestation { func TestVerifyAttestations(t *testing.T) { sgVerifier, err := verification.NewLiveSigstoreVerifier(verification.SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: io.NewTestHandler(), - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: io.NewTestHandler(), + TUFMetadataDir: o.Some(t.TempDir()), }) require.NoError(t, err) diff --git a/pkg/cmd/attestation/verify/verify_integration_test.go b/pkg/cmd/attestation/verify/verify_integration_test.go index ed20a9007fd..195313b645e 100644 --- a/pkg/cmd/attestation/verify/verify_integration_test.go +++ b/pkg/cmd/attestation/verify/verify_integration_test.go @@ -25,9 +25,9 @@ func TestVerifyIntegration(t *testing.T) { logger := io.NewTestHandler() sigstoreConfig := verification.SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: logger, - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: logger, + TUFMetadataDir: o.Some(t.TempDir()), } ios, _, _, _ := iostreams.Test() @@ -45,7 +45,7 @@ func TestVerifyIntegration(t *testing.T) { sigstoreVerifier, err := verification.NewLiveSigstoreVerifier(sigstoreConfig) require.NoError(t, err) publicGoodOpts := Options{ - APIClient: api.NewLiveClient(hc, host, logger), + APIClient: api.NewLiveClient(hc, http.DefaultClient, host, logger), ArtifactPath: artifactPath, BundlePath: bundlePath, DigestAlgorithm: "sha512", @@ -120,7 +120,7 @@ func TestVerifyIntegration(t *testing.T) { sigstoreVerifier, err := verification.NewLiveSigstoreVerifier(sigstoreConfig) require.NoError(t, err) opts := Options{ - APIClient: api.NewLiveClient(hc, host, logger), + APIClient: api.NewLiveClient(hc, http.DefaultClient, host, logger), ArtifactPath: "oci://ghcr.io/github/artifact-attestations-helm-charts/policy-controller:v0.10.0-github9", UseBundleFromRegistry: true, DigestAlgorithm: "sha256", @@ -145,9 +145,9 @@ func TestVerifyIntegrationCustomIssuer(t *testing.T) { logger := io.NewTestHandler() sigstoreConfig := verification.SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: logger, - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: logger, + TUFMetadataDir: o.Some(t.TempDir()), } ios, _, _, _ := iostreams.Test() @@ -165,7 +165,7 @@ func TestVerifyIntegrationCustomIssuer(t *testing.T) { sigstoreVerifier, err := verification.NewLiveSigstoreVerifier(sigstoreConfig) require.NoError(t, err) baseOpts := Options{ - APIClient: api.NewLiveClient(hc, host, logger), + APIClient: api.NewLiveClient(hc, http.DefaultClient, host, logger), ArtifactPath: artifactPath, BundlePath: bundlePath, DigestAlgorithm: "sha256", @@ -222,9 +222,9 @@ func TestVerifyIntegrationReusableWorkflow(t *testing.T) { logger := io.NewTestHandler() sigstoreConfig := verification.SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: logger, - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: logger, + TUFMetadataDir: o.Some(t.TempDir()), } cfg := config.NewBlankConfig() @@ -243,7 +243,7 @@ func TestVerifyIntegrationReusableWorkflow(t *testing.T) { sigstoreVerifier, err := verification.NewLiveSigstoreVerifier(sigstoreConfig) require.NoError(t, err) baseOpts := Options{ - APIClient: api.NewLiveClient(hc, host, logger), + APIClient: api.NewLiveClient(hc, http.DefaultClient, host, logger), ArtifactPath: artifactPath, BundlePath: bundlePath, DigestAlgorithm: "sha256", @@ -319,9 +319,9 @@ func TestVerifyIntegrationReusableWorkflowSignerWorkflow(t *testing.T) { logger := io.NewTestHandler() sigstoreConfig := verification.SigstoreConfig{ - HttpClient: http.DefaultClient, - Logger: logger, - TUFMetadataDir: o.Some(t.TempDir()), + ExternalHttpClient: http.DefaultClient, + Logger: logger, + TUFMetadataDir: o.Some(t.TempDir()), } cfg := config.NewBlankConfig() @@ -340,7 +340,7 @@ func TestVerifyIntegrationReusableWorkflowSignerWorkflow(t *testing.T) { sigstoreVerifier, err := verification.NewLiveSigstoreVerifier(sigstoreConfig) require.NoError(t, err) baseOpts := Options{ - APIClient: api.NewLiveClient(hc, host, logger), + APIClient: api.NewLiveClient(hc, http.DefaultClient, host, logger), ArtifactPath: artifactPath, BundlePath: bundlePath, Config: func() (gh.Config, error) {