From 4fc1ffe5537bb5f9799a20952605ba973a63a045 Mon Sep 17 00:00:00 2001 From: Maksim Zuev Date: Fri, 30 Oct 2026 15:10:34 +0000 Subject: [PATCH 1/4] Do not write a dotted profile's keys into its parent section go-ini treats [team.prod] as a child of [team], and Section.Key returns the parent's key when the child doesn't have it. So saving host to a new [team.prod] next to an existing [team] rewrote [team]'s host and left [team.prod] without it. SaveResourcesToProfile had the same problem. Section.NewKey only looks at the section's own keys. Co-authored-by: Isaac --- libs/databrickscfg/ops.go | 13 +++++++++---- libs/databrickscfg/ops_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/libs/databrickscfg/ops.go b/libs/databrickscfg/ops.go index 6358c5ba49d..c017dd06a67 100644 --- a/libs/databrickscfg/ops.go +++ b/libs/databrickscfg/ops.go @@ -278,8 +278,9 @@ func SaveResourcesToProfile(ctx context.Context, profileName, configFilePath str } if len(resources) == 0 { section.DeleteKey("resources") - } else { - section.Key("resources").SetValue(strings.Join(resources, ",")) + } else if _, err := section.NewKey("resources", strings.Join(resources, ",")); err != nil { + // See SaveToProfile for why this is not Section.Key. + return err } return writeConfigFile(ctx, configFile) } @@ -461,8 +462,12 @@ func SaveToProfile(ctx context.Context, cfg *config.Config, clearKeys ...string) if attr.IsZero(cfg) { continue } - key := section.Key(attr.Name) - key.SetValue(attr.GetString(cfg)) + // Section.Key falls back to the parent section for dotted names + // ([team] for [team.prod]), so it would overwrite the parent's value. + // NewKey only looks at the section's own keys. + if _, err := section.NewKey(attr.Name, attr.GetString(cfg)); err != nil { + return err + } } // Auto-set default profile when saving the first profile to the config file. diff --git a/libs/databrickscfg/ops_test.go b/libs/databrickscfg/ops_test.go index 8fe1956a81f..ff3680b7498 100644 --- a/libs/databrickscfg/ops_test.go +++ b/libs/databrickscfg/ops_test.go @@ -212,6 +212,38 @@ func TestSaveResourcesToProfile(t *testing.T) { assert.NotContains(t, string(contents), "resources") } +func TestSaveToProfile_DottedNameDoesNotWriteParentSection(t *testing.T) { + ctx := t.Context() + path := filepath.Join(t.TempDir(), "databrickscfg") + err := os.WriteFile(path, []byte("[team]\nhost = https://team\ntoken = xyz\nresources = https://team/a\n"), 0o600) + require.NoError(t, err) + + require.NoError(t, SaveToProfile(ctx, &config.Config{ + ConfigFile: path, + Profile: "team.prod", + Host: "https://prod", + AuthType: "databricks-cli", + })) + require.NoError(t, SaveResourcesToProfile(ctx, "team.prod", path, []string{"https://prod/b"})) + + file, err := loadConfigFile(ctx, path) + require.NoError(t, err) + parent, err := file.GetSection("team") + require.NoError(t, err) + assert.Equal(t, map[string]string{ + "host": "https://team", + "token": "xyz", + "resources": "https://team/a", + }, parent.KeysHash()) + child, err := file.GetSection("team.prod") + require.NoError(t, err) + assert.Equal(t, map[string]string{ + "host": "https://prod", + "auth_type": "databricks-cli", + "resources": "https://prod/b", + }, child.KeysHash()) +} + func TestSaveResourcesToProfile_MissingProfile(t *testing.T) { ctx := t.Context() path := filepath.Join(t.TempDir(), "databrickscfg") From 3b5684da0666acd30e566387569b3c9d21b2368a Mon Sep 17 00:00:00 2001 From: Maksim Zuev Date: Fri, 30 Oct 2026 15:48:11 +0000 Subject: [PATCH 2/4] Add a changelog fragment for the dotted profile fix Co-authored-by: Isaac --- .nextchanges/cli/dotted-profile-parent-section.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nextchanges/cli/dotted-profile-parent-section.md diff --git a/.nextchanges/cli/dotted-profile-parent-section.md b/.nextchanges/cli/dotted-profile-parent-section.md new file mode 100644 index 00000000000..065a0e0fdc7 --- /dev/null +++ b/.nextchanges/cli/dotted-profile-parent-section.md @@ -0,0 +1 @@ +* Fix `databricks auth login` overwriting the parent profile when saving a profile with a dotted name such as `team.prod` next to an existing `[team]`. ([#7266](https://github.com/databricks/cli/pull/7266)) From 6ccc40a16022ae0d9709533da247445394d1ca3f Mon Sep 17 00:00:00 2001 From: Maksim Zuev Date: Mon, 2 Nov 2026 11:44:45 +0000 Subject: [PATCH 3/4] Mention databricks configure in the dotted profile changelog fragment Co-authored-by: Isaac --- .nextchanges/cli/dotted-profile-parent-section.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nextchanges/cli/dotted-profile-parent-section.md b/.nextchanges/cli/dotted-profile-parent-section.md index 065a0e0fdc7..bc0b308217f 100644 --- a/.nextchanges/cli/dotted-profile-parent-section.md +++ b/.nextchanges/cli/dotted-profile-parent-section.md @@ -1 +1 @@ -* Fix `databricks auth login` overwriting the parent profile when saving a profile with a dotted name such as `team.prod` next to an existing `[team]`. ([#7266](https://github.com/databricks/cli/pull/7266)) +* Fix `databricks auth login` and `databricks configure` overwriting the parent profile's host and token when saving a profile with a dotted name such as `team.prod` next to an existing `[team]`. ([#7266](https://github.com/databricks/cli/pull/7266)) From 11832c891de65d1e9ac91031874221b95135739e Mon Sep 17 00:00:00 2001 From: Maksim Zuev Date: Tue, 3 Nov 2026 11:26:06 +0000 Subject: [PATCH 4/4] Use a reserved .test domain in the dotted profile test fixture Co-authored-by: Isaac --- libs/databrickscfg/ops_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/databrickscfg/ops_test.go b/libs/databrickscfg/ops_test.go index ff3680b7498..49fa1bd1458 100644 --- a/libs/databrickscfg/ops_test.go +++ b/libs/databrickscfg/ops_test.go @@ -215,32 +215,32 @@ func TestSaveResourcesToProfile(t *testing.T) { func TestSaveToProfile_DottedNameDoesNotWriteParentSection(t *testing.T) { ctx := t.Context() path := filepath.Join(t.TempDir(), "databrickscfg") - err := os.WriteFile(path, []byte("[team]\nhost = https://team\ntoken = xyz\nresources = https://team/a\n"), 0o600) + err := os.WriteFile(path, []byte("[team]\nhost = https://team.test\ntoken = xyz\nresources = https://team.test/a\n"), 0o600) require.NoError(t, err) require.NoError(t, SaveToProfile(ctx, &config.Config{ ConfigFile: path, Profile: "team.prod", - Host: "https://prod", + Host: "https://prod.test", AuthType: "databricks-cli", })) - require.NoError(t, SaveResourcesToProfile(ctx, "team.prod", path, []string{"https://prod/b"})) + require.NoError(t, SaveResourcesToProfile(ctx, "team.prod", path, []string{"https://prod.test/b"})) file, err := loadConfigFile(ctx, path) require.NoError(t, err) parent, err := file.GetSection("team") require.NoError(t, err) assert.Equal(t, map[string]string{ - "host": "https://team", + "host": "https://team.test", "token": "xyz", - "resources": "https://team/a", + "resources": "https://team.test/a", }, parent.KeysHash()) child, err := file.GetSection("team.prod") require.NoError(t, err) assert.Equal(t, map[string]string{ - "host": "https://prod", + "host": "https://prod.test", "auth_type": "databricks-cli", - "resources": "https://prod/b", + "resources": "https://prod.test/b", }, child.KeysHash()) }