Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect mismatch between host defined in config and env variable #2549

Merged
merged 12 commits into from
Mar 25, 2025
Merged
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
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
* Added support for volumes in deployment bind/unbind commands ([#2527](https://github.com/databricks/cli/pull/2527))
* Added support for dashboards in deployment bind/unbind commands ([#2516](https://github.com/databricks/cli/pull/2516))
* Added support for registered models in deployment bind/unbind commands ([#2556](https://github.com/databricks/cli/pull/2556))
* Added a mismatch check when host is defined in config and as an env variable ([#2549](https://github.com/databricks/cli/pull/2549))

### API Changes
5 changes: 5 additions & 0 deletions acceptance/auth/bundle_and_env/.databrickscfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[DEFAULT]
host = https://bar.com

[profile_with_matching_host]
host = $DATABRICKS_HOST
11 changes: 11 additions & 0 deletions acceptance/auth/bundle_and_env/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
bundle:
name: test-auth

targets:
match:
default: true
workspace:
host: $DATABRICKS_HOST
not_match:
workspace:
host: https://foo.com
35 changes: 35 additions & 0 deletions acceptance/auth/bundle_and_env/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

=== Bundle commands load bundle configuration with DATABRICKS_HOST defined, validation not OK (env-defined host doesn't match bundle host)
>>> errcode [CLI] bundle validate -t not_match
Error: cannot resolve bundle auth configuration: config host mismatch: DATABRICKS_HOST is defined as [DATABRICKS_HOST], but CLI configured to use https://foo.com

Name: test-auth
Target: not_match
Workspace:
Host: https://foo.com

Found 1 error

Exit code: 1

=== Bundle commands load bundle configuration with DATABRICKS_HOST defined, validation OK (env-defined host matches bundle host)
>>> errcode [CLI] bundle validate -t match
Name: test-auth
Target: match
Workspace:
Host: [DATABRICKS_HOST]
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-auth/match

Validation OK!

=== Bundle commands load bundle configuration with -p flag with DATABRICKS_HOST defined, host in profile matches bundle host but env-defined host doesn't
>>> errcode [CLI] bundle validate -t match -p profile_with_matching_host
Name: test-auth
Target: match
Workspace:
Host: [DATABRICKS_HOST]
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-auth/match

Validation OK!
15 changes: 15 additions & 0 deletions acceptance/auth/bundle_and_env/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Replace placeholder with an actual host URL
envsubst < databricks.yml > out.yml && mv out.yml databricks.yml
envsubst < .databrickscfg > out && mv out .databrickscfg

export DATABRICKS_CONFIG_FILE=.databrickscfg

title "Bundle commands load bundle configuration with DATABRICKS_HOST defined, validation not OK (env-defined host doesn't match bundle host)"
trace errcode $CLI bundle validate -t not_match

title "Bundle commands load bundle configuration with DATABRICKS_HOST defined, validation OK (env-defined host matches bundle host)"
trace errcode $CLI bundle validate -t match

export DATABRICKS_HOST="https://baz.com"
title "Bundle commands load bundle configuration with -p flag with DATABRICKS_HOST defined, host in profile matches bundle host but env-defined host doesn't"
trace errcode $CLI bundle validate -t match -p profile_with_matching_host
5 changes: 5 additions & 0 deletions acceptance/auth/bundle_and_env/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Some of the clouds have DATABRICKS_HOST variable setup without https:// prefix
# In the result, output is replaced with DATABRICKS_URL variable instead of DATABRICKS_HOST
[[Repls]]
Old='DATABRICKS_URL'
New='DATABRICKS_HOST'
1 change: 0 additions & 1 deletion acceptance/bundle/debug/out.stderr.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
10:07:59 Debug: Apply pid=12345 mutator=<func>
10:07:59 Info: Phase: initialize pid=12345
10:07:59 Debug: Apply pid=12345 mutator=validate:AllResourcesHaveValues
10:07:59 Debug: Apply pid=12345 mutator=validate:interpolation_in_auth_config
10:07:59 Debug: Apply pid=12345 mutator=RewriteSyncPaths
10:07:59 Debug: Apply pid=12345 mutator=SyncDefaultPath
10:07:59 Debug: Apply pid=12345 mutator=SyncInferRoot
Expand Down
9 changes: 2 additions & 7 deletions acceptance/bundle/variables/host/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@ Warning: Variable interpolation is not supported for fields that configure authe
Interpolation is not supported for the field workspace.host. Please set
the DATABRICKS_HOST environment variable if you wish to configure this field at runtime.

Error: failed during request visitor: parse "https://${var.host}": invalid character "{" in host name
Error: cannot resolve bundle auth configuration: config host mismatch: DATABRICKS_HOST is defined as [DATABRICKS_URL], but CLI configured to use ${var.host}
Copy link
Contributor Author

@ilyakuz-db ilyakuz-db Mar 22, 2025

Choose a reason for hiding this comment

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

Just in case - we have a warning displayed above that explains incorrect usage of variables in auth-related fields


{
"bundle": {
"environment": "default",
"name": "host",
"target": "default"
},
"sync": {
"paths": [
"."
]
},
"targets": null,
"variables": {
"host": {
Expand All @@ -41,7 +36,7 @@ Warning: Variable interpolation is not supported for fields that configure authe
Interpolation is not supported for the field workspace.host. Please set
the DATABRICKS_HOST environment variable if you wish to configure this field at runtime.

Error: failed during request visitor: parse "https://${var.host}": invalid character "{" in host name
Error: cannot resolve bundle auth configuration: config host mismatch: DATABRICKS_HOST is defined as [DATABRICKS_URL], but CLI configured to use ${var.host}

Name: host
Target: default
Expand Down
83 changes: 0 additions & 83 deletions bundle/config/validate/interpolation_in_auth_config.go

This file was deleted.

27 changes: 27 additions & 0 deletions bundle/config/workspace.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package config

import (
"fmt"
"os"
"path/filepath"

"github.com/databricks/cli/libs/databrickscfg"
"github.com/databricks/cli/libs/workspace"
"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/config"
"github.com/databricks/databricks-sdk-go/marshal"
Expand Down Expand Up @@ -148,9 +150,34 @@ func (w *Workspace) Client() (*databricks.WorkspaceClient, error) {
}
}

if w.Host != "" && w.Profile == "" {
err := validateConfigAndEnvHost(cfg)
if err != nil {
return nil, err
}
}

return databricks.NewWorkspaceClient((*databricks.Config)(cfg))
}

func validateConfigAndEnvHost(cfg *config.Config) error {
var hostEnvName, hostEnvVal string
for _, attr := range config.ConfigAttributes {
if attr.Name == "host" {
hostEnvVal, hostEnvName = attr.ReadEnv()
break
}
}
if hostEnvName == "" || hostEnvVal == "" {
return nil
}

if !workspace.MatchHost(hostEnvVal, cfg.Host) {
return fmt.Errorf("config host mismatch: %s is defined as %s, but CLI configured to use %s", hostEnvName, hostEnvVal, cfg.Host)
}
return nil
}

func init() {
arg0 := os.Args[0]

Expand Down
1 change: 0 additions & 1 deletion bundle/phases/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ func Initialize(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {

return bundle.ApplySeq(ctx, b,
validate.AllResourcesHaveValues(),
validate.NoInterpolationInAuthConfig(),

// Update all path fields in the sync block to be relative to the bundle root path.
mutator.RewriteSyncPaths(),
Expand Down
67 changes: 67 additions & 0 deletions cmd/root/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package root

import (
"context"
"fmt"

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/env"
"github.com/databricks/cli/bundle/phases"
"github.com/databricks/cli/libs/auth"
"github.com/databricks/cli/libs/cmdctx"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
"github.com/databricks/cli/libs/dyn/dynvar"
envlib "github.com/databricks/cli/libs/env"
"github.com/spf13/cobra"
"golang.org/x/exp/maps"
Expand Down Expand Up @@ -94,6 +98,8 @@ func configureBundle(cmd *cobra.Command, b *bundle.Bundle) (*bundle.Bundle, diag
return b, diags
}

diags = diags.Extend(checkVariablesInAuthFields(b))

// Set the auth configuration in the command context. This can be used
// downstream to initialize a API client.
//
Expand Down Expand Up @@ -181,3 +187,64 @@ func initEnvironmentFlag(cmd *cobra.Command) {
cmd.PersistentFlags().MarkDeprecated("environment", "use --target flag instead")
cmd.RegisterFlagCompletionFunc("environment", targetCompletion)
}

func checkVariablesInAuthFields(b *bundle.Bundle) diag.Diagnostics {
authFields := []string{
// Generic attributes.
"host",
"profile",
"auth_type",
"metadata_service_url",

// OAuth specific attributes.
"client_id",

// Google specific attributes.
"google_service_account",

// Azure specific attributes.
"azure_resource_id",
"azure_use_msi",
"azure_client_id",
"azure_tenant_id",
"azure_environment",
"azure_login_app_id",
}

diags := diag.Diagnostics{}

for _, fieldName := range authFields {
p := dyn.NewPath(dyn.Key("workspace"), dyn.Key(fieldName))
v, err := dyn.GetByPath(b.Config.Value(), p)
if dyn.IsNoSuchKeyError(err) {
continue
}
if err != nil {
return diag.FromErr(err)
}

vv, ok := v.AsString()
if !ok {
continue
}

// Check if the field contains interpolation.
if dynvar.ContainsVariableReference(vv) {
envVar, ok := auth.GetEnvFor(fieldName)
if !ok {
continue
}

diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Variable interpolation is not supported for fields that configure authentication",
Detail: fmt.Sprintf(`Interpolation is not supported for the field %s. Please set
the %s environment variable if you wish to configure this field at runtime.`, p.String(), envVar),
Locations: v.Locations(),
Paths: []dyn.Path{p},
})
}
}

return diags
}
22 changes: 0 additions & 22 deletions libs/databrickscfg/host.go

This file was deleted.

Loading
Loading