Skip to content

Commit d3d7ee5

Browse files
hectorcast-dbclaude
andcommitted
Restore NewCredentialsChain interface and add NewCredentialsChainWithCloudRequirements
PR #1505 changed NewCredentialsChain to return *credentialsChain (unexported) to enable WithCloudRequirements chaining. This broke the public API. Restore the return type to CredentialsStrategy and introduce NewCredentialsChainWithCloudRequirements for callers that need cloud-based filtering. DefaultCredentials now uses the new constructor directly. The WithCloudRequirements method is removed as it is no longer needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Hector Castejon Diaz <hector.castejon@databricks.com>
1 parent 32dc67e commit d3d7ee5

10 files changed

Lines changed: 65 additions & 49 deletions

NEXT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bug Fixes
1010

11+
* Restore `NewCredentialsChain` return type to `CredentialsStrategy` interface ([#XXXX](https://github.com/databricks/databricks-sdk-go/pull/XXXX)).
12+
1113
### Documentation
1214

1315
### Internal Changes

config/auth_azure_cli.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"golang.org/x/oauth2"
1313

14+
"github.com/databricks/databricks-sdk-go/common/environment"
1415
"github.com/databricks/databricks-sdk-go/config/credentials"
1516
"github.com/databricks/databricks-sdk-go/logger"
1617
)
@@ -28,6 +29,11 @@ func (c AzureCliCredentials) Name() string {
2829
return "azure-cli"
2930
}
3031

32+
// Cloud implements [CloudScoped.Cloud].
33+
func (c AzureCliCredentials) Cloud() environment.Cloud {
34+
return environment.CloudAzure
35+
}
36+
3137
// implementing azureHostResolver for ensureWorkspaceUrl to work
3238
func (c AzureCliCredentials) tokenSourceFor(
3339
ctx context.Context, cfg *Config, _, resource string) oauth2.TokenSource {

config/auth_azure_client_secret.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"golang.org/x/oauth2"
99
"golang.org/x/oauth2/clientcredentials"
1010

11+
"github.com/databricks/databricks-sdk-go/common/environment"
1112
"github.com/databricks/databricks-sdk-go/config/credentials"
1213
"github.com/databricks/databricks-sdk-go/logger"
1314
)
@@ -19,6 +20,11 @@ func (c AzureClientSecretCredentials) Name() string {
1920
return "azure-client-secret"
2021
}
2122

23+
// Cloud implements [CloudScoped.Cloud].
24+
func (c AzureClientSecretCredentials) Cloud() environment.Cloud {
25+
return environment.CloudAzure
26+
}
27+
2228
func (c AzureClientSecretCredentials) tokenSourceFor(
2329
ctx context.Context, cfg *Config, aadEndpoint, resource string) oauth2.TokenSource {
2430
return (&clientcredentials.Config{

config/auth_azure_github_oidc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"time"
88

9+
"github.com/databricks/databricks-sdk-go/common/environment"
910
"github.com/databricks/databricks-sdk-go/config/credentials"
1011
"github.com/databricks/databricks-sdk-go/config/experimental/auth"
1112
"github.com/databricks/databricks-sdk-go/config/experimental/auth/oidc"
@@ -22,6 +23,11 @@ func (c AzureGithubOIDCCredentials) Name() string {
2223
return "github-oidc-azure"
2324
}
2425

26+
// Cloud implements [CloudScoped.Cloud].
27+
func (c AzureGithubOIDCCredentials) Cloud() environment.Cloud {
28+
return environment.CloudAzure
29+
}
30+
2531
// Configure implements [CredentialsStrategy.Configure].
2632
func (c AzureGithubOIDCCredentials) Configure(ctx context.Context, cfg *Config) (credentials.CredentialsProvider, error) {
2733
if cfg.AzureClientID == "" || cfg.Host == "" || cfg.AzureTenantID == "" || cfg.ActionsIDTokenRequestURL == "" || cfg.ActionsIDTokenRequestToken == "" {

config/auth_azure_msi.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"time"
1010

11+
"github.com/databricks/databricks-sdk-go/common/environment"
1112
"github.com/databricks/databricks-sdk-go/config/credentials"
1213
"github.com/databricks/databricks-sdk-go/httpclient"
1314
"github.com/databricks/databricks-sdk-go/logger"
@@ -31,6 +32,11 @@ func (c AzureMsiCredentials) Name() string {
3132
return "azure-msi"
3233
}
3334

35+
// Cloud implements [CloudScoped.Cloud].
36+
func (c AzureMsiCredentials) Cloud() environment.Cloud {
37+
return environment.CloudAzure
38+
}
39+
3440
func (c AzureMsiCredentials) Configure(ctx context.Context, cfg *Config) (credentials.CredentialsProvider, error) {
3541
if !cfg.AzureUseMSI || (cfg.AzureResourceID == "" && cfg.ConfigType() == WorkspaceConfig) {
3642
return nil, nil

config/auth_default.go

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"net/http"
77

8-
"github.com/databricks/databricks-sdk-go/common/environment"
98
"github.com/databricks/databricks-sdk-go/config/credentials"
109
"github.com/databricks/databricks-sdk-go/logger"
1110
)
@@ -23,25 +22,13 @@ var ErrCannotConfigureDefault = fmt.Errorf("cannot configure default credentials
2322
// INTERNAL: This function is not part of the public API and is subject to
2423
// change. Users are encouraged to use an explicit credentials strategy rather
2524
// than relying on a custom credentials chain.
26-
func NewCredentialsChain(strategies ...CredentialsStrategy) *credentialsChain {
25+
func NewCredentialsChain(strategies ...CredentialsStrategy) CredentialsStrategy {
2726
return &credentialsChain{strategies: strategies}
2827
}
2928

3029
type credentialsChain struct {
3130
strategies []CredentialsStrategy
32-
// cloudRequirements maps a strategy name to the cloud it requires. When
33-
// set, the auto-detect loop skips strategies whose required cloud does not
34-
// match the configured host. The map is not consulted when AuthType is
35-
// explicitly set — in that case the named strategy is always attempted.
36-
cloudRequirements map[string]environment.Cloud
37-
name string
38-
}
39-
40-
// WithCloudRequirements sets the cloud requirements for the chain and returns
41-
// the chain for method chaining.
42-
func (c *credentialsChain) WithCloudRequirements(m map[string]environment.Cloud) *credentialsChain {
43-
c.cloudRequirements = m
44-
return c
31+
name string
4532
}
4633

4734
func (c *credentialsChain) Name() string {
@@ -76,9 +63,9 @@ func (c *credentialsChain) Configure(ctx context.Context, cfg *Config) (credenti
7663
// In auto-detect mode, skip cloud-specific strategies that don't match
7764
// the detected cloud. This prevents Azure strategies from being
7865
// attempted silently on GCP hosts and vice-versa.
79-
if requiredCloud, ok := c.cloudRequirements[s.Name()]; ok {
80-
if cfg.Environment().Cloud != requiredCloud {
81-
logger.Debugf(ctx, "Skipping %q: not configured for %s", s.Name(), requiredCloud)
66+
if cs, ok := s.(CloudScoped); ok {
67+
if cs.Cloud() != cfg.Environment().Cloud {
68+
logger.Debugf(ctx, "Skipping %q: not configured for %s", s.Name(), cfg.Environment().Cloud)
8269
continue
8370
}
8471
}
@@ -144,18 +131,7 @@ func (c *DefaultCredentials) Configure(ctx context.Context, cfg *Config) (creden
144131
// Google strategies.
145132
GoogleCredentials{},
146133
GoogleDefaultCredentials{},
147-
).WithCloudRequirements(map[string]environment.Cloud{
148-
// cloudRequirements declares the cloud each strategy requires.
149-
// DefaultCredentials uses this to skip cloud-specific strategies in
150-
// auto-detect mode when the host cloud does not match. Cloud filtering
151-
// is bypassed when AuthType is explicitly set.
152-
"github-oidc-azure": environment.CloudAzure,
153-
"azure-msi": environment.CloudAzure,
154-
"azure-client-secret": environment.CloudAzure,
155-
"azure-cli": environment.CloudAzure,
156-
"google-credentials": environment.CloudGCP,
157-
"google-id": environment.CloudGCP,
158-
})
134+
)
159135
cp, err := chain.Configure(ctx, cfg)
160136
if err != nil {
161137
return nil, err

config/auth_default_test.go

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,27 @@ import (
1010
"github.com/databricks/databricks-sdk-go/config/credentials"
1111
)
1212

13-
// recordingStrategy is a test helper that records whether Configure was called.
14-
type recordingStrategy struct {
13+
// cloudScopedStrategy is a test helper that implements both [CredentialsStrategy]
14+
// and [CloudScoped], recording whether Configure was called.
15+
type cloudScopedStrategy struct {
1516
name string
1617
called bool
18+
cloud environment.Cloud
1719
}
1820

19-
func (r *recordingStrategy) Name() string { return r.name }
20-
func (r *recordingStrategy) Configure(_ context.Context, _ *Config) (credentials.CredentialsProvider, error) {
21-
r.called = true
21+
func (s *cloudScopedStrategy) Name() string { return s.name }
22+
func (s *cloudScopedStrategy) Cloud() environment.Cloud { return s.cloud }
23+
func (s *cloudScopedStrategy) Configure(_ context.Context, _ *Config) (credentials.CredentialsProvider, error) {
24+
s.called = true
2225
return nil, nil
2326
}
2427

2528
// TestCredentialsChain_CloudFiltering_SkipsOnCloudMismatch verifies that the
2629
// chain skips a cloud-specific strategy in auto-detect mode when the detected
2730
// cloud does not match the strategy's required cloud.
2831
func TestCredentialsChain_CloudFiltering_SkipsOnCloudMismatch(t *testing.T) {
29-
azureStrategy := &recordingStrategy{name: "azure-cli"}
30-
chain := &credentialsChain{
31-
strategies: []CredentialsStrategy{azureStrategy},
32-
cloudRequirements: map[string]environment.Cloud{
33-
"azure-cli": environment.CloudAzure,
34-
},
35-
}
32+
azureStrategy := &cloudScopedStrategy{name: "azure-cli", cloud: environment.CloudAzure}
33+
chain := &credentialsChain{strategies: []CredentialsStrategy{azureStrategy}}
3634

3735
// GCP host: azure-cli must be skipped in auto-detect mode.
3836
cfg := &Config{Host: "https://xyz.gcp.databricks.com/", resolved: true}
@@ -47,13 +45,8 @@ func TestCredentialsChain_CloudFiltering_SkipsOnCloudMismatch(t *testing.T) {
4745
// the cloud filter is bypassed when AuthType is explicitly set, so that a user
4846
// can request "azure-cli" even on a GCP host.
4947
func TestCredentialsChain_CloudFiltering_BypassesOnExplicitAuthType(t *testing.T) {
50-
azureStrategy := &recordingStrategy{name: "azure-cli"}
51-
chain := &credentialsChain{
52-
strategies: []CredentialsStrategy{azureStrategy},
53-
cloudRequirements: map[string]environment.Cloud{
54-
"azure-cli": environment.CloudAzure,
55-
},
56-
}
48+
azureStrategy := &cloudScopedStrategy{name: "azure-cli", cloud: environment.CloudAzure}
49+
chain := &credentialsChain{strategies: []CredentialsStrategy{azureStrategy}}
5750

5851
// GCP host but auth_type is explicitly set: cloud filter must be bypassed.
5952
cfg := &Config{Host: "https://xyz.gcp.databricks.com/", AuthType: "azure-cli", resolved: true}

config/auth_gcp_google_credentials.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io/ioutil"
77
"os"
88

9+
"github.com/databricks/databricks-sdk-go/common/environment"
910
"github.com/databricks/databricks-sdk-go/config/credentials"
1011
"github.com/databricks/databricks-sdk-go/logger"
1112
"golang.org/x/oauth2/google"
@@ -20,6 +21,11 @@ func (c GoogleCredentials) Name() string {
2021
return "google-credentials"
2122
}
2223

24+
// Cloud implements [CloudScoped.Cloud].
25+
func (c GoogleCredentials) Cloud() environment.Cloud {
26+
return environment.CloudGCP
27+
}
28+
2329
func (c GoogleCredentials) Configure(ctx context.Context, cfg *Config) (credentials.CredentialsProvider, error) {
2430
if cfg.GoogleCredentials == "" {
2531
return nil, nil

config/auth_gcp_google_id.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/databricks/databricks-sdk-go/common/environment"
78
"github.com/databricks/databricks-sdk-go/config/credentials"
89
"github.com/databricks/databricks-sdk-go/logger"
910
"golang.org/x/oauth2"
@@ -20,6 +21,11 @@ func (c GoogleDefaultCredentials) Name() string {
2021
return "google-id"
2122
}
2223

24+
// Cloud implements [CloudScoped.Cloud].
25+
func (c GoogleDefaultCredentials) Cloud() environment.Cloud {
26+
return environment.CloudGCP
27+
}
28+
2329
func (c GoogleDefaultCredentials) Configure(ctx context.Context, cfg *Config) (credentials.CredentialsProvider, error) {
2430
if cfg.GoogleServiceAccount == "" {
2531
return nil, nil

config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ type CredentialsStrategy interface {
3434
Configure(context.Context, *Config) (credentials.CredentialsProvider, error)
3535
}
3636

37+
// CloudScoped is an optional interface that a [CredentialsStrategy] can
38+
// implement to declare which cloud it supports. When implemented, the
39+
// credentials chain skips this strategy in auto-detect mode if the configured
40+
// host's cloud does not match. Cloud filtering is bypassed when
41+
// [Config.AuthType] is explicitly set.
42+
type CloudScoped interface {
43+
Cloud() environment.Cloud
44+
}
45+
3746
type Loader interface {
3847
// Name is human-addressable representation of this config resolver
3948
Name() string

0 commit comments

Comments
 (0)