Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions providers/azure/services/synapse/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ func NewClient(cred azcore.TokenCredential, subscriptionID, region string) *Syna
}

// NewClientWithHTTP creates a new Azure Synapse client with a custom HTTP client (for testing).
// If httpClient is nil, http.DefaultClient is used.
// When httpClient is nil, the SSRF-hardened httpclient.New() is used so the nil
// fallback also blocks IMDS connections.
func NewClientWithHTTP(cred azcore.TokenCredential, subscriptionID, region string, httpClient HTTPClient) *SynapseClient {
if httpClient == nil {
httpClient = http.DefaultClient
httpClient = httpclient.New()
}
return &SynapseClient{
cred: cred,
Expand Down Expand Up @@ -344,7 +345,7 @@ func (c *SynapseClient) GetOfferingDetails(ctx context.Context, rec common.Recom
upfrontCost = 0
recurringCost = totalCost / (float64(termYears) * 12)
default:
// Fail loud on an unrecognised payment option rather than silently
// Fail loud on an unrecognized payment option rather than silently
// billing it as all-upfront (owner policy: no silent fallbacks on
// money-affecting fields).
return nil, fmt.Errorf("unsupported payment option for Azure Synapse offering details: %q", rec.PaymentOption)
Expand Down
21 changes: 21 additions & 0 deletions providers/azure/services/synapse/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,24 @@ func TestGetOfferingDetails_noReservationPrice(t *testing.T) {
// helper's contract is now exercised in providers/azure/services/internal/reservations
// package tests; the synapse-side coverage is via the executor-level
// PurchaseCommitment tests above.

// ---- nil HTTP client fallback ----------------------------------------------

// TestNewClientWithHTTP_NilFallbackIsHardened is a regression test for the
// codebase-review finding SEC-03 (issue #1143): when httpClient is nil, the
// httpClient falls back to httpclient.New() (SSRF-hardened), not
// http.DefaultClient, so the fallback also rejects IMDS connections.
func TestNewClientWithHTTP_NilFallbackIsHardened(t *testing.T) {
c := NewClientWithHTTP(nil, "sub-123", "eastus", nil)
require.NotNil(t, c.httpClient)
require.NotEqual(t, http.DefaultClient, c.httpClient,
"nil fallback must never be http.DefaultClient")
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://169.254.169.254/metadata/instance", nil)
require.NoError(t, err)
resp, err := c.httpClient.Do(req)
if resp != nil {
defer resp.Body.Close()
}
require.Error(t, err, "nil-fallback client must reject IMDS connections")
assert.Contains(t, err.Error(), "blocked")
}
Loading