From 1e8ec002e7cb7efa2ebe13d54e863433c66a7ada Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Sat, 24 Aug 2024 21:05:44 +0200 Subject: [PATCH 1/3] Shorten service principal names based on their friendly name --- .../config/mutator/populate_current_user.go | 2 +- internal/init_test.go | 2 +- libs/auth/user.go | 12 +++- libs/auth/user_test.go | 71 +++++++++++++++---- libs/template/helpers.go | 2 +- 5 files changed, 69 insertions(+), 20 deletions(-) diff --git a/bundle/config/mutator/populate_current_user.go b/bundle/config/mutator/populate_current_user.go index b5e0bd4374..1e99b327c7 100644 --- a/bundle/config/mutator/populate_current_user.go +++ b/bundle/config/mutator/populate_current_user.go @@ -33,7 +33,7 @@ func (m *populateCurrentUser) Apply(ctx context.Context, b *bundle.Bundle) diag. } b.Config.Workspace.CurrentUser = &config.User{ - ShortName: auth.GetShortUserName(me.UserName), + ShortName: auth.GetShortUserName(me), User: me, } diff --git a/internal/init_test.go b/internal/init_test.go index c3cb0127e3..d1a89f7b7b 100644 --- a/internal/init_test.go +++ b/internal/init_test.go @@ -126,7 +126,7 @@ func TestAccBundleInitHelpers(t *testing.T) { }{ { funcName: "{{short_name}}", - expected: auth.GetShortUserName(me.UserName), + expected: auth.GetShortUserName(me), }, { funcName: "{{user_name}}", diff --git a/libs/auth/user.go b/libs/auth/user.go index 8eaa876339..48204d0d4e 100644 --- a/libs/auth/user.go +++ b/libs/auth/user.go @@ -4,12 +4,20 @@ import ( "strings" "github.com/databricks/cli/libs/textutil" + "github.com/databricks/databricks-sdk-go/service/iam" ) // Get a short-form username, based on the user's primary email address. // We leave the full range of unicode letters in tact, but remove all "special" characters, // including dots, which are not supported in e.g. experiment names. -func GetShortUserName(emailAddress string) string { - local, _, _ := strings.Cut(emailAddress, "@") +func GetShortUserName(user *iam.User) string { + var name string + if IsServicePrincipal(user.UserName) { + name = user.DisplayName + } + if name == "" { + name = user.UserName + } + local, _, _ := strings.Cut(name, "@") return textutil.NormalizeString(local) } diff --git a/libs/auth/user_test.go b/libs/auth/user_test.go index 62b2d29ac6..e62f307455 100644 --- a/libs/auth/user_test.go +++ b/libs/auth/user_test.go @@ -3,70 +3,111 @@ package auth import ( "testing" + "github.com/databricks/databricks-sdk-go/service/iam" "github.com/stretchr/testify/assert" ) func TestGetShortUserName(t *testing.T) { tests := []struct { name string - email string + user *iam.User expected string }{ { - email: "test.user.1234@example.com", + user: &iam.User{ + UserName: "test.user.1234@example.com", + }, expected: "test_user_1234", }, { - email: "tést.üser@example.com", + user: &iam.User{ + UserName: "tést.üser@example.com", + }, expected: "tést_üser", }, { - email: "test$.user@example.com", + user: &iam.User{ + UserName: "test$.user@example.com", + }, expected: "test_user", }, { - email: `jöhn.dœ@domain.com`, // Using non-ASCII characters. + user: &iam.User{ + UserName: `jöhn.dœ@domain.com`, // Using non-ASCII characters. + }, expected: "jöhn_dœ", }, { - email: `first+tag@email.com`, // The plus (+) sign is used for "sub-addressing" in some email services. + user: &iam.User{ + UserName: `first+tag@email.com`, // The plus (+) sign is used for "sub-addressing" in some email services. + }, expected: "first_tag", }, { - email: `email@sub.domain.com`, // Using a sub-domain. + user: &iam.User{ + UserName: `email@sub.domain.com`, // Using a sub-domain. + }, expected: "email", }, { - email: `"_quoted"@domain.com`, // Quoted strings can be part of the local-part. + user: &iam.User{ + UserName: `"_quoted"@domain.com`, // Quoted strings can be part of the local-part. + }, expected: "quoted", }, { - email: `name-o'mally@website.org`, // Single quote in the local-part. + user: &iam.User{ + UserName: `name-o'mally@website.org`, // Single quote in the local-part. + }, expected: "name_o_mally", }, { - email: `user%domain@external.com`, // Percent sign can be used for email routing in legacy systems. + user: &iam.User{ + UserName: `user%domain@external.com`, // Percent sign can be used for email routing in legacy systems. + }, expected: "user_domain", }, { - email: `long.name.with.dots@domain.net`, // Multiple dots in the local-part. + user: &iam.User{ + UserName: `long.name.with.dots@domain.net`, // Multiple dots in the local-part. + }, expected: "long_name_with_dots", }, { - email: `me&you@together.com`, // Using an ampersand (&) in the local-part. + user: &iam.User{ + UserName: `me&you@together.com`, // Using an ampersand (&) in the local-part. + }, expected: "me_you", }, { - email: `user!def!xyz@domain.org`, // The exclamation mark can be valid in some legacy systems. + user: &iam.User{ + UserName: `user!def!xyz@domain.org`, // The exclamation mark can be valid in some legacy systems. + }, expected: "user_def_xyz", }, { - email: `admin@ιντερνετ.com`, // Domain in non-ASCII characters (IDN or Internationalized Domain Name). + user: &iam.User{ + UserName: `admin@ιντερνετ.com`, // Domain in non-ASCII characters (IDN or Internationalized Domain Name). + }, expected: "admin", }, + { + user: &iam.User{ + UserName: `1706906c-c0a2-4c25-9f57-3a7aa3cb8123`, + DisplayName: "my-service-principal", + }, + expected: "my_service_principal", + }, + { + user: &iam.User{ + UserName: `1706906c-c0a2-4c25-9f57-3a7aa3cb8123`, + // No DisplayName + }, + expected: "1706906c_c0a2_4c25_9f57_3a7aa3cb8123", + }, } for _, tt := range tests { - assert.Equal(t, tt.expected, GetShortUserName(tt.email)) + assert.Equal(t, tt.expected, GetShortUserName(tt.user)) } } diff --git a/libs/template/helpers.go b/libs/template/helpers.go index 1dfe74d736..88c73cc479 100644 --- a/libs/template/helpers.go +++ b/libs/template/helpers.go @@ -119,7 +119,7 @@ func loadHelpers(ctx context.Context) template.FuncMap { return "", err } } - return auth.GetShortUserName(cachedUser.UserName), nil + return auth.GetShortUserName(cachedUser), nil }, // Get the default workspace catalog. If there is no default, or if // Unity Catalog is not enabled, return an empty string. From fcabb88e5eb05ab1f3b004ca9447a79f5c58ea4d Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Fri, 13 Sep 2024 09:30:10 +0200 Subject: [PATCH 2/3] Add clarification --- libs/auth/user.go | 1 + libs/auth/user_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/auth/user.go b/libs/auth/user.go index 48204d0d4e..4d89eeb317 100644 --- a/libs/auth/user.go +++ b/libs/auth/user.go @@ -13,6 +13,7 @@ import ( func GetShortUserName(user *iam.User) string { var name string if IsServicePrincipal(user.UserName) { + // Try use the display name of the principal (if it has one) name = user.DisplayName } if name == "" { diff --git a/libs/auth/user_test.go b/libs/auth/user_test.go index e62f307455..24b61464bc 100644 --- a/libs/auth/user_test.go +++ b/libs/auth/user_test.go @@ -101,7 +101,7 @@ func TestGetShortUserName(t *testing.T) { { user: &iam.User{ UserName: `1706906c-c0a2-4c25-9f57-3a7aa3cb8123`, - // No DisplayName + // This service princpal has DisplayName (it's an optional property) }, expected: "1706906c_c0a2_4c25_9f57_3a7aa3cb8123", }, From 260f445f8e8b930528e16f966b5d040b35a820a3 Mon Sep 17 00:00:00 2001 From: Lennart Kats Date: Fri, 13 Sep 2024 10:59:51 +0200 Subject: [PATCH 3/3] Rework conditionals --- libs/auth/user.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/auth/user.go b/libs/auth/user.go index 4d89eeb317..c6aa974f3f 100644 --- a/libs/auth/user.go +++ b/libs/auth/user.go @@ -11,14 +11,10 @@ import ( // We leave the full range of unicode letters in tact, but remove all "special" characters, // including dots, which are not supported in e.g. experiment names. func GetShortUserName(user *iam.User) string { - var name string - if IsServicePrincipal(user.UserName) { - // Try use the display name of the principal (if it has one) + name := user.UserName + if IsServicePrincipal(user.UserName) && user.DisplayName != "" { name = user.DisplayName } - if name == "" { - name = user.UserName - } local, _, _ := strings.Cut(name, "@") return textutil.NormalizeString(local) }