From da61765469fb9481574dec8439d05bc39675f626 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Thu, 7 Sep 2023 04:59:08 -0400 Subject: [PATCH] DXCDT-506: Improved Resource Name Sanitation (#837) Tweaking sanitize regex, modifying unit tests Co-authored-by: Will Vedder --- internal/cli/terraform.go | 24 +++++ internal/cli/terraform_fetcher.go | 28 +----- internal/cli/terraform_fetcher_test.go | 124 ++++++++++--------------- internal/cli/terraform_test.go | 30 ++++++ 4 files changed, 106 insertions(+), 100 deletions(-) diff --git a/internal/cli/terraform.go b/internal/cli/terraform.go index 4a5229c1f..27d2d6857 100644 --- a/internal/cli/terraform.go +++ b/internal/cli/terraform.go @@ -8,6 +8,8 @@ import ( "os/exec" "path" "path/filepath" + "regexp" + "strings" "text/template" "github.com/hashicorp/go-version" @@ -397,3 +399,25 @@ func cleanOutputDirectory(outputDIR string) error { return joinedErrors } + +// sanitizeResourceName will return a valid terraform resource name. +// +// A name must start with a letter or underscore and may +// contain only letters, digits, underscores, and dashes. +func sanitizeResourceName(name string) string { + // Regular expression pattern to remove invalid characters. + namePattern := "[^a-zA-Z0-9_]+" + re := regexp.MustCompile(namePattern) + + sanitizedName := re.ReplaceAllString(name, "_") + + // Regular expression pattern to remove leading digits or dashes. + namePattern = "^[0-9-]+" + re = regexp.MustCompile(namePattern) + + sanitizedName = re.ReplaceAllString(sanitizedName, "") + sanitizedName = strings.Trim(sanitizedName, "_") + sanitizedName = strings.ToLower(sanitizedName) + + return sanitizedName +} diff --git a/internal/cli/terraform_fetcher.go b/internal/cli/terraform_fetcher.go index 2c25676ac..126718b01 100644 --- a/internal/cli/terraform_fetcher.go +++ b/internal/cli/terraform_fetcher.go @@ -2,8 +2,6 @@ package cli import ( "context" - "fmt" - "regexp" "github.com/auth0/go-auth0/management" "github.com/google/uuid" @@ -147,7 +145,7 @@ func (f *clientGrantResourceFetcher) FetchData(ctx context.Context) (importDataL for _, grant := range grants.ClientGrants { data = append(data, importDataItem{ - ResourceName: "auth0_client_grant." + grant.GetClientID() + "_" + sanitizeResourceName(grant.GetAudience()), + ResourceName: "auth0_client_grant." + sanitizeResourceName(grant.GetClientID()+"_"+grant.GetAudience()), ImportID: grant.GetID(), }) } @@ -326,7 +324,7 @@ func (f *promptCustomTextResourceFetcherResourceFetcher) FetchData(ctx context.C for _, language := range tenant.GetEnabledLocales() { for _, promptType := range promptTypes { data = append(data, importDataItem{ - ResourceName: fmt.Sprintf("auth0_prompt_custom_text.%s-%s", language, promptType), + ResourceName: "auth0_prompt_custom_text." + sanitizeResourceName(language+"_"+promptType), ImportID: promptType + "::" + language, }) } @@ -436,7 +434,7 @@ func (f *triggerActionsResourceFetcher) FetchData(ctx context.Context) (importDa } if len(res.Bindings) > 0 { data = append(data, importDataItem{ - ResourceName: "auth0_trigger_actions." + trigger, + ResourceName: "auth0_trigger_actions." + sanitizeResourceName(trigger), ImportID: trigger, }) } @@ -474,23 +472,3 @@ func (f *actionResourceFetcher) FetchData(ctx context.Context) (importDataList, return data, nil } - -// sanitizeResourceName will return a valid terraform resource name. -// -// A name must start with a letter or underscore and may -// contain only letters, digits, underscores, and dashes. -func sanitizeResourceName(name string) string { - // Regular expression pattern to remove invalid characters. - namePattern := "[^a-zA-Z0-9_-]+" - re := regexp.MustCompile(namePattern) - - sanitizedName := re.ReplaceAllString(name, "") - - // Regular expression pattern to remove leading digits or dashes. - namePattern = "^[0-9-]+" - re = regexp.MustCompile(namePattern) - - sanitizedName = re.ReplaceAllString(sanitizedName, "") - - return sanitizedName -} diff --git a/internal/cli/terraform_fetcher_test.go b/internal/cli/terraform_fetcher_test.go index 50a68ee6a..4888033c0 100644 --- a/internal/cli/terraform_fetcher_test.go +++ b/internal/cli/terraform_fetcher_test.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "strings" "testing" "github.com/auth0/go-auth0/management" @@ -13,33 +14,6 @@ import ( "github.com/auth0/auth0-cli/internal/auth0/mock" ) -func TestSanitizeResourceName(t *testing.T) { - testCases := []struct { - input string - expected string - }{ - // Test cases with valid names - {"ValidName123", "ValidName123"}, - {"_Another_Valid-Name", "_Another_Valid-Name"}, - {"name_with_123", "name_with_123"}, - {"_start_with_underscore", "_start_with_underscore"}, - - // Test cases with invalid names to be sanitized - {"Invalid@Name", "InvalidName"}, - {"Invalid Name", "InvalidName"}, - {"123StartWithNumber", "StartWithNumber"}, - {"-StartWithDash", "StartWithDash"}, - {"", ""}, - } - - for _, testCase := range testCases { - t.Run(testCase.input, func(t *testing.T) { - sanitized := sanitizeResourceName(testCase.input) - assert.Equal(t, testCase.expected, sanitized) - }) - } -} - func TestActionResourceFetcher_FetchData(t *testing.T) { t.Run("it successfully retrieves actions data", func(t *testing.T) { ctrl := gomock.NewController(t) @@ -99,19 +73,19 @@ func TestActionResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_action.Action1", + ResourceName: "auth0_action.action_1", ImportID: "07898b80-02ba-42ee-82ad-e5b224a9b450", }, { - ResourceName: "auth0_action.Action2", + ResourceName: "auth0_action.action_2", ImportID: "24118aae-8022-4b94-80c1-e8e28511eb92", }, { - ResourceName: "auth0_action.Action3", + ResourceName: "auth0_action.action_3", ImportID: "fa04d1ff-fe8d-4662-b7c2-32d212719876", }, { - ResourceName: "auth0_action.Action4", + ResourceName: "auth0_action.action_4", ImportID: "9cb897b9-c25c-47be-b5aa-e03e31af2e44", }, } @@ -224,19 +198,19 @@ func TestClientResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_client.MyTestClient1", + ResourceName: "auth0_client.my_test_client_1", ImportID: "clientID_1", }, { - ResourceName: "auth0_client.MyTestClient2", + ResourceName: "auth0_client.my_test_client_2", ImportID: "clientID_2", }, { - ResourceName: "auth0_client.MyTestClient3", + ResourceName: "auth0_client.my_test_client_3", ImportID: "clientID_3", }, { - ResourceName: "auth0_client.MyTestClient4", + ResourceName: "auth0_client.my_test_client_4", ImportID: "clientID_4", }, } @@ -329,19 +303,19 @@ func TestClientGrantResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_client_grant.client-id-1_httpstravel0comapi", + ResourceName: "auth0_client_grant.client_id_1_https_travel0_com_api", ImportID: "cgr_1", }, { - ResourceName: "auth0_client_grant.client-id-2_httpstravel0comapi", + ResourceName: "auth0_client_grant.client_id_2_https_travel0_com_api", ImportID: "cgr_2", }, { - ResourceName: "auth0_client_grant.client-id-1_httpstravel0usauth0comapiv2", + ResourceName: "auth0_client_grant.client_id_1_https_travel0_us_auth0_com_api_v2", ImportID: "cgr_3", }, { - ResourceName: "auth0_client_grant.client-id-2_httpstravel0usauth0comapiv2", + ResourceName: "auth0_client_grant.client_id_2_https_travel0_us_auth0_com_api_v2", ImportID: "cgr_4", }, } @@ -430,35 +404,35 @@ func TestConnectionResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_connection.Connection1", + ResourceName: "auth0_connection.connection_1", ImportID: "con_id1", }, { - ResourceName: "auth0_connection_clients.Connection1", + ResourceName: "auth0_connection_clients.connection_1", ImportID: "con_id1", }, { - ResourceName: "auth0_connection.Connection2", + ResourceName: "auth0_connection.connection_2", ImportID: "con_id2", }, { - ResourceName: "auth0_connection_clients.Connection2", + ResourceName: "auth0_connection_clients.connection_2", ImportID: "con_id2", }, { - ResourceName: "auth0_connection.Connection3", + ResourceName: "auth0_connection.connection_3", ImportID: "con_id3", }, { - ResourceName: "auth0_connection_clients.Connection3", + ResourceName: "auth0_connection_clients.connection_3", ImportID: "con_id3", }, { - ResourceName: "auth0_connection.Connection4", + ResourceName: "auth0_connection.connection_4", ImportID: "con_id4", }, { - ResourceName: "auth0_connection_clients.Connection4", + ResourceName: "auth0_connection_clients.connection_4", ImportID: "con_id4", }, } @@ -518,11 +492,11 @@ func TestCustomDomainResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_custom_domain.travel0com", + ResourceName: "auth0_custom_domain.travel0_com", ImportID: "cd_XDVfBNsfL2vj7Wm1", }, { - ResourceName: "auth0_custom_domain.enterprisetravel0com", + ResourceName: "auth0_custom_domain.enterprise_travel0_com", ImportID: "cd_XDVfBNsfL2vj7Wm1", }, } @@ -606,11 +580,11 @@ func TestLogStreamResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_log_stream.DataDog", + ResourceName: "auth0_log_stream.datadog", ImportID: "lst_0000000000014444", }, { - ResourceName: "auth0_log_stream.HTTPLogs", + ResourceName: "auth0_log_stream.http_logs", ImportID: "lst_0000000000015555", }, } @@ -743,31 +717,31 @@ func TestOrganizationResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_organization.Organization1", + ResourceName: "auth0_organization.organization_1", ImportID: "org_1", }, { - ResourceName: "auth0_organization_connections.Organization1", + ResourceName: "auth0_organization_connections.organization_1", ImportID: "org_1", }, { - ResourceName: "auth0_organization.Organization2", + ResourceName: "auth0_organization.organization_2", ImportID: "org_2", }, { - ResourceName: "auth0_organization_connections.Organization2", + ResourceName: "auth0_organization_connections.organization_2", ImportID: "org_2", }, { - ResourceName: "auth0_organization.Organization3", + ResourceName: "auth0_organization.organization_3", ImportID: "org_3", }, { - ResourceName: "auth0_organization_connections.Organization3", + ResourceName: "auth0_organization_connections.organization_3", ImportID: "org_3", }, { - ResourceName: "auth0_organization.Organization4-NOCONNECTIONS", + ResourceName: "auth0_organization.organization_4_no_connections", ImportID: "org_4", }, } @@ -850,7 +824,7 @@ func TestPromptCustomTextResourceFetcher_FetchData(t *testing.T) { for _, enabledLocale := range mockEnabledLocales { for _, promptType := range promptTypes { expectedData = append(expectedData, importDataItem{ - ResourceName: fmt.Sprintf("auth0_prompt_custom_text.%s-%s", enabledLocale, promptType), + ResourceName: fmt.Sprintf("auth0_prompt_custom_text.%s_%s", enabledLocale, strings.ReplaceAll(promptType, "-", "_")), ImportID: fmt.Sprintf("%s::%s", promptType, enabledLocale), }) } @@ -940,35 +914,35 @@ func TestResourceServerResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_resource_server.Auth0ManagementAPI", + ResourceName: "auth0_resource_server.auth0_management_api", ImportID: "610e04b71f71b9003a7eb3df", }, { - ResourceName: "auth0_resource_server_scopes.Auth0ManagementAPI", + ResourceName: "auth0_resource_server_scopes.auth0_management_api", ImportID: "610e04b71f71b9003a7eb3df", }, { - ResourceName: "auth0_resource_server.PaymentsAPI", + ResourceName: "auth0_resource_server.payments_api", ImportID: "6358fed7b77d3c391dd78a40", }, { - ResourceName: "auth0_resource_server_scopes.PaymentsAPI", + ResourceName: "auth0_resource_server_scopes.payments_api", ImportID: "6358fed7b77d3c391dd78a40", }, { - ResourceName: "auth0_resource_server.BlogAPI", + ResourceName: "auth0_resource_server.blog_api", ImportID: "66ef6f9c435cab03def5fa16", }, { - ResourceName: "auth0_resource_server_scopes.BlogAPI", + ResourceName: "auth0_resource_server_scopes.blog_api", ImportID: "66ef6f9c435cab03def5fa16", }, { - ResourceName: "auth0_resource_server.UserAPI", + ResourceName: "auth0_resource_server.user_api", ImportID: "63bf6f9b0e025715cb91ce7c", }, { - ResourceName: "auth0_resource_server_scopes.UserAPI", + ResourceName: "auth0_resource_server_scopes.user_api", ImportID: "63bf6f9b0e025715cb91ce7c", }, } @@ -1113,31 +1087,31 @@ func TestRoleResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_role.Role1-NoPermissions", + ResourceName: "auth0_role.role_1_no_permissions", ImportID: "rol_1", }, { - ResourceName: "auth0_role.Role2", + ResourceName: "auth0_role.role_2", ImportID: "rol_2", }, { - ResourceName: "auth0_role_permissions.Role2", + ResourceName: "auth0_role_permissions.role_2", ImportID: "rol_2", }, { - ResourceName: "auth0_role.Role3", + ResourceName: "auth0_role.role_3", ImportID: "rol_3", }, { - ResourceName: "auth0_role_permissions.Role3", + ResourceName: "auth0_role_permissions.role_3", ImportID: "rol_3", }, { - ResourceName: "auth0_role.Role4", + ResourceName: "auth0_role.role_4", ImportID: "rol_4", }, { - ResourceName: "auth0_role_permissions.Role4", + ResourceName: "auth0_role_permissions.role_4", ImportID: "rol_4", }, } @@ -1217,7 +1191,7 @@ func TestTriggerActionsResourceFetcher_FetchData(t *testing.T) { expectedData := importDataList{ { - ResourceName: "auth0_trigger_actions.pre-user-registration", + ResourceName: "auth0_trigger_actions.pre_user_registration", ImportID: "pre-user-registration", }, } diff --git a/internal/cli/terraform_test.go b/internal/cli/terraform_test.go index 224f59baf..cfd0324fc 100644 --- a/internal/cli/terraform_test.go +++ b/internal/cli/terraform_test.go @@ -488,3 +488,33 @@ func TestTerraformInputs_ParseResourceFetchers(t *testing.T) { }) } } + +func TestSanitizeResourceName(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + // Test cases with valid names + {"ValidName123", "validname123"}, + {"_Another_Valid-Name", "another_valid_name"}, + {"name_with_123", "name_with_123"}, + {"name-with-dashes", "name_with_dashes"}, + {"_starts_and_ends_with_underscore_", "starts_and_ends_with_underscore"}, + {"multiple spaces between", "multiple_spaces_between"}, + {"https://travel0.us.auth0.com/api/v2/", "https_travel0_us_auth0_com_api_v2"}, + + // Test cases with invalid names to be sanitized + {"Invalid@Name", "invalid_name"}, + {"Invalid Name", "invalid_name"}, + {"123 Starts With Number", "starts_with_number"}, + {"-Starts With Dash", "starts_with_dash"}, + {"", ""}, + } + + for _, testCase := range testCases { + t.Run(testCase.input, func(t *testing.T) { + sanitized := sanitizeResourceName(testCase.input) + assert.Equal(t, testCase.expected, sanitized) + }) + } +}