diff --git a/provider/go.mod b/provider/go.mod index 9fac7b2e..c2cd4a72 100644 --- a/provider/go.mod +++ b/provider/go.mod @@ -1,6 +1,8 @@ module github.com/pulumi/pulumi-auth0/provider/v3 -go 1.21 +go 1.21.0 + +toolchain go1.21.5 replace ( github.com/auth0/terraform-provider-auth0 => ../upstream @@ -10,8 +12,10 @@ replace ( require ( github.com/auth0/terraform-provider-auth0 v0.50.2 + github.com/pulumi/providertest v0.0.7 github.com/pulumi/pulumi-terraform-bridge/v3 v3.70.0 github.com/pulumi/pulumi/sdk/v3 v3.99.0 + github.com/stretchr/testify v1.8.4 ) require ( @@ -199,7 +203,6 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.8.4 // indirect github.com/texttheater/golang-levenshtein v1.0.1 // indirect github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect diff --git a/provider/go.sum b/provider/go.sum index 11045ae8..a897eae0 100644 --- a/provider/go.sum +++ b/provider/go.sum @@ -2188,6 +2188,8 @@ github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435 github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE= github.com/pulumi/esc v0.6.2 h1:+z+l8cuwIauLSwXQS0uoI3rqB+YG4SzsZYtHfNoXBvw= github.com/pulumi/esc v0.6.2/go.mod h1:jNnYNjzsOgVTjCp0LL24NsCk8ZJxq4IoLQdCT0X7l8k= +github.com/pulumi/providertest v0.0.7 h1:5vP4HZgKGsLXTXUt9Qdu821QH+YWHcsrjdbWppw1haM= +github.com/pulumi/providertest v0.0.7/go.mod h1:fwGDI/khKruoumzTOisCLooJwJT20OvYHcKMkIsfTCk= github.com/pulumi/pulumi-java/pkg v0.9.8 h1:c8mYsalnRXA2Ibgvv6scefOn6mW1Vb0UT0mcDqjsivQ= github.com/pulumi/pulumi-java/pkg v0.9.8/go.mod h1:c6rSw/+q4O0IImgJ9axxoC6QesbPYWBaG5gimbHouUQ= github.com/pulumi/pulumi-terraform-bridge/testing v0.0.1 h1:SCg1gjfY9N4yn8U8peIUYATifjoDABkyR7H9lmefsfc= diff --git a/provider/provider_test.go b/provider/provider_test.go new file mode 100644 index 00000000..cf147079 --- /dev/null +++ b/provider/provider_test.go @@ -0,0 +1,489 @@ +// Copyright 2016-2023, Pulumi Corporation. All rights reserved. +package auth0_test + +import ( + "context" + "testing" + + testutils "github.com/pulumi/providertest/replay" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" + + auth0 "github.com/pulumi/pulumi-auth0/provider/v3" + "github.com/pulumi/pulumi-auth0/provider/v3/pkg/version" +) + +func server() pulumirpc.ResourceProviderServer { + ctx := context.Background() + version.Version = "0.0.1" + info := auth0.Provider() + return tfbridge.NewProvider(ctx, nil, info.Name, version.Version, info.P, info, + /* + * We leave the schema blank. This will result in incorrect calls to + * GetSchema, but otherwise does not effect the provider. It reduces the + * time to test start by minutes. + */ + []byte("{}"), + ) +} + +func TestConnectionMigration(t *testing.T) { + testutils.ReplaySequence(t, server(), `[ + { + "method": "/pulumirpc.ResourceProvider/Diff", + "request": { + "id": "con_28GC8g8h3O4RUSSM", + "urn": "urn:pulumi:dev::dev-yaml::auth0:index/connection:Connection::googleOauth2", + "olds": { + "__meta": "{\"schema_version\":\"2\"}", + "displayName": "", + "enabledClients": [], + "id": "con_28GC8g8h3O4RUSSM", + "isDomainConnection": false, + "name": "googleOauth2-b68d006", + "options": { + "adfsServer": "", + "allowedAudiences": [ + "api.example.com", + "example.com" + ], + "apiEnableUsers": false, + "appDomain": "", + "appId": "", + "authorizationEndpoint": "", + "bruteForceProtection": false, + "clientId": "", + "clientSecret": "", + "communityBaseUrl": "", + "configuration": {}, + "customScripts": {}, + "debug": false, + "digestAlgorithm": "", + "disableCache": false, + "disableSignup": false, + "discoveryUrl": "", + "domain": "", + "domainAliases": [], + "enabledDatabaseCustomization": false, + "entityId": "", + "fieldsMap": {}, + "forwardRequestInfo": false, + "from": "", + "gatewayAuthentication": null, + "gatewayUrl": "", + "iconUrl": "", + "identityApi": "", + "idpInitiated": null, + "importMode": false, + "ips": [], + "issuer": "", + "jwksUri": "", + "keyId": "", + "maxGroupsToRetrieve": "", + "messagingServiceSid": "", + "mfa": null, + "name": "", + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "passwordComplexityOptions": null, + "passwordDictionary": null, + "passwordHistories": [], + "passwordNoPersonalInfo": null, + "passwordPolicy": "", + "protocolBinding": "", + "provider": "", + "requestTemplate": "", + "requiresUsername": false, + "scopes": [ + "youtube", + "gmail", + "profile", + "email" + ], + "scripts": {}, + "setUserRootAttributes": "on_each_login", + "shouldTrustEmailVerifiedConnection": "", + "signInEndpoint": "", + "signOutEndpoint": "", + "signSamlRequest": false, + "signatureAlgorithm": "", + "signingCert": "", + "strategyVersion": 0, + "subject": "", + "syntax": "", + "teamId": "", + "template": "", + "tenantDomain": "", + "tokenEndpoint": "", + "totp": null, + "twilioSid": "", + "twilioToken": "", + "type": "", + "useCertAuth": false, + "useKerberos": false, + "useWsfed": false, + "userIdAttribute": "", + "userinfoEndpoint": "", + "validation": null, + "waadCommonEndpoint": false, + "waadProtocol": "" + }, + "realms": [ + "googleOauth2-b68d006" + ], + "strategy": "google-oauth2" + }, + "news": { + "__defaults": [ + "name" + ], + "name": "googleOauth2-b68d006", + "options": { + "__defaults": [], + "allowedAudiences": [ + "example.com", + "api.example.com" + ], + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "scopes": [ + "email", + "profile", + "gmail", + "youtube" + ], + "setUserRootAttributes": "on_each_login" + }, + "strategy": "google-oauth2" + }, + "oldInputs": { + "__defaults": [ + "name" + ], + "name": "googleOauth2-b68d006", + "options": { + "__defaults": [], + "allowedAudiences": [ + "example.com", + "api.example.com" + ], + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "scopes": [ + "email", + "profile", + "gmail", + "youtube" + ], + "setUserRootAttributes": "on_each_login" + }, + "strategy": "google-oauth2" + } + }, + "response": { + "stables": "*", + "changes": "DIFF_SOME", + "diffs": [ + "options" + ], + "detailedDiff": { + "options.fieldsMap": { + "kind": "DELETE" + } + }, + "hasDetailedDiff": true + }, + "metadata": { + "kind": "resource", + "mode": "client", + "name": "auth0" + } + }, + { + "method": "/pulumirpc.ResourceProvider/Update", + "request": { + "id": "con_28GC8g8h3O4RUSSM", + "urn": "urn:pulumi:dev::dev-yaml::auth0:index/connection:Connection::googleOauth2", + "olds": { + "__meta": "{\"schema_version\":\"2\"}", + "displayName": "", + "enabledClients": [], + "id": "con_28GC8g8h3O4RUSSM", + "isDomainConnection": false, + "name": "googleOauth2-b68d006", + "options": { + "adfsServer": "", + "allowedAudiences": [ + "api.example.com", + "example.com" + ], + "apiEnableUsers": false, + "appDomain": "", + "appId": "", + "authorizationEndpoint": "", + "bruteForceProtection": false, + "clientId": "", + "clientSecret": "", + "communityBaseUrl": "", + "configuration": {}, + "customScripts": {}, + "debug": false, + "digestAlgorithm": "", + "disableCache": false, + "disableSignup": false, + "discoveryUrl": "", + "domain": "", + "domainAliases": [], + "enabledDatabaseCustomization": false, + "entityId": "", + "fieldsMap": {}, + "forwardRequestInfo": false, + "from": "", + "gatewayAuthentication": null, + "gatewayUrl": "", + "iconUrl": "", + "identityApi": "", + "idpInitiated": null, + "importMode": false, + "ips": [], + "issuer": "", + "jwksUri": "", + "keyId": "", + "maxGroupsToRetrieve": "", + "messagingServiceSid": "", + "mfa": null, + "name": "", + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "passwordComplexityOptions": null, + "passwordDictionary": null, + "passwordHistories": [], + "passwordNoPersonalInfo": null, + "passwordPolicy": "", + "protocolBinding": "", + "provider": "", + "requestTemplate": "", + "requiresUsername": false, + "scopes": [ + "youtube", + "gmail", + "profile", + "email" + ], + "scripts": {}, + "setUserRootAttributes": "on_each_login", + "shouldTrustEmailVerifiedConnection": "", + "signInEndpoint": "", + "signOutEndpoint": "", + "signSamlRequest": false, + "signatureAlgorithm": "", + "signingCert": "", + "strategyVersion": 0, + "subject": "", + "syntax": "", + "teamId": "", + "template": "", + "tenantDomain": "", + "tokenEndpoint": "", + "totp": null, + "twilioSid": "", + "twilioToken": "", + "type": "", + "useCertAuth": false, + "useKerberos": false, + "useWsfed": false, + "userIdAttribute": "", + "userinfoEndpoint": "", + "validation": null, + "waadCommonEndpoint": false, + "waadProtocol": "" + }, + "realms": [ + "googleOauth2-b68d006" + ], + "strategy": "google-oauth2" + }, + "news": { + "__defaults": [ + "name" + ], + "name": "googleOauth2-b68d006", + "options": { + "__defaults": [], + "allowedAudiences": [ + "example.com", + "api.example.com" + ], + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "scopes": [ + "email", + "profile", + "gmail", + "youtube" + ], + "setUserRootAttributes": "on_each_login" + }, + "strategy": "google-oauth2" + }, + "preview": true, + "oldInputs": { + "__defaults": [ + "name" + ], + "name": "googleOauth2-b68d006", + "options": { + "__defaults": [], + "allowedAudiences": [ + "example.com", + "api.example.com" + ], + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "scopes": [ + "email", + "profile", + "gmail", + "youtube" + ], + "setUserRootAttributes": "on_each_login" + }, + "strategy": "google-oauth2" + } + }, + "response": { + "properties": { + "__meta": "{\"schema_version\":\"2\"}", + "displayName": "", + "id": "con_28GC8g8h3O4RUSSM", + "isDomainConnection": false, + "name": "googleOauth2-b68d006", + "options": { + "adfsServer": "", + "allowedAudiences": [ + "api.example.com", + "example.com" + ], + "apiEnableUsers": false, + "appId": "", + "attributeMap": null, + "authParams": {}, + "authorizationEndpoint": "", + "bruteForceProtection": false, + "clientId": "", + "clientSecret": "", + "communityBaseUrl": "", + "configuration": {}, + "connectionSettings": null, + "customScripts": {}, + "debug": false, + "decryptionKey": null, + "digestAlgorithm": "", + "disableCache": false, + "disableSelfServiceChangePassword": false, + "disableSignOut": false, + "disableSignup": false, + "discoveryUrl": "", + "domain": "", + "domainAliases": [], + "enableScriptContext": false, + "enabledDatabaseCustomization": false, + "entityId": "", + "fedMetadataXml": "", + "fieldsMap": "", + "forwardRequestInfo": false, + "from": "", + "gatewayAuthentication": null, + "gatewayUrl": "", + "iconUrl": "", + "identityApi": "", + "idpInitiated": null, + "importMode": false, + "ips": [], + "issuer": "", + "jwksUri": "", + "keyId": "", + "mapUserIdToId": false, + "maxGroupsToRetrieve": "", + "messagingServiceSid": "", + "metadataUrl": "", + "metadataXml": "", + "mfa": null, + "name": "", + "nonPersistentAttrs": [ + "ethnicity", + "gender" + ], + "passwordComplexityOptions": null, + "passwordDictionary": null, + "passwordHistories": [], + "passwordNoPersonalInfo": null, + "passwordPolicy": "", + "pingFederateBaseUrl": "", + "pkceEnabled": false, + "protocolBinding": "", + "provider": "", + "requestTemplate": "", + "requiresUsername": false, + "scopes": [ + "youtube", + "gmail", + "profile", + "email" + ], + "scripts": {}, + "setUserRootAttributes": "on_each_login", + "shouldTrustEmailVerifiedConnection": "", + "signInEndpoint": "", + "signOutEndpoint": "", + "signSamlRequest": false, + "signatureAlgorithm": "", + "signingCert": "", + "signingKey": null, + "strategyVersion": 0, + "subject": "", + "syntax": "", + "teamId": "", + "template": "", + "tenantDomain": "", + "tokenEndpoint": "", + "totp": null, + "twilioSid": "", + "twilioToken": "", + "type": "", + "upstreamParams": "", + "useCertAuth": false, + "useKerberos": false, + "useWsfed": false, + "userIdAttribute": "", + "userinfoEndpoint": "", + "validation": null, + "waadCommonEndpoint": false, + "waadProtocol": "" + }, + "realms": [ + "googleOauth2-b68d006" + ], + "strategy": "google-oauth2" + } + }, + "metadata": { + "kind": "resource", + "mode": "client", + "name": "auth0" + } + } + ]`) +} diff --git a/provider/resources.go b/provider/resources.go index 3bb5c8ca..4160d69c 100644 --- a/provider/resources.go +++ b/provider/resources.go @@ -15,8 +15,10 @@ package auth0 import ( + "context" + "encoding/json" "fmt" - "path/filepath" + "path" // embed is used to store bridge-metadata.json in the compiled binary _ "embed" @@ -26,7 +28,7 @@ import ( "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" tks "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens" shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2" - "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi-auth0/provider/v3/pkg/version" ) @@ -39,13 +41,6 @@ const ( mainMod = "index" // the y module ) -// makeResource manufactures a standard resource token given a module and resource name. It -// automatically uses the main package and names the file by simply lower casing the resource's -// first character. -func makeResource(mod string, res string) tokens.Type { - return tfbridge.MakeResource(mainPkg, mod, res) -} - var managedByPulumi = &tfbridge.DefaultInfo{Value: "Managed by Pulumi"} //go:embed cmd/pulumi-resource-auth0/bridge-metadata.json @@ -74,21 +69,18 @@ func Provider() tfbridge.ProviderInfo { }, Resources: map[string]*tfbridge.ResourceInfo{ "auth0_client": { - Tok: makeResource(mainMod, "Client"), Fields: map[string]*tfbridge.SchemaInfo{ - "description": { - Default: managedByPulumi, - }, + "description": {Default: managedByPulumi}, }, }, "auth0_role": { - Tok: makeResource(mainMod, "Role"), Fields: map[string]*tfbridge.SchemaInfo{ - "description": { - Default: managedByPulumi, - }, + "description": {Default: managedByPulumi}, }, }, + "auth0_connection": { + TransformFromState: connectionMigration, + }, }, JavaScript: &tfbridge.JavaScriptInfo{ Dependencies: map[string]string{ @@ -109,7 +101,7 @@ func Provider() tfbridge.ProviderInfo { })(), Golang: &tfbridge.GolangInfo{ - ImportBasePath: filepath.Join( + ImportBasePath: path.Join( fmt.Sprintf("github.com/pulumi/pulumi-%[1]s/sdk/", mainPkg), tfbridge.GetModuleMajorVersion(version.Version), "go", @@ -132,3 +124,41 @@ func Provider() tfbridge.ProviderInfo { return prov } + +// connectionMigration migrates options.fieldsMap from a map to a JSON encoded string. +// +// This migration handles the general case where options.fieldsMap is a simple +// map[string]string by encoding the map to JSON. +// +// See https://github.com/pulumi/pulumi-auth0/issues/398 for why this is necessary. +func connectionMigration(ctx context.Context, state resource.PropertyMap) (resource.PropertyMap, error) { + if state == nil { + return state, nil + } + const ( + optionsKey = "options" + fieldMapKey = "fieldsMap" + ) + if !state[optionsKey].IsObject() { + return state, nil + } + options := state[optionsKey].ObjectValue() + + fieldMap, ok := options[fieldMapKey] + if !ok || !fieldMap.IsObject() { + return state, nil + } + + if fieldMap.ContainsSecrets() || fieldMap.ContainsUnknowns() { + return state, nil + } + + jsonValue, err := json.Marshal(fieldMap.Mappable()) + if err != nil { + tfbridge.GetLogger(ctx).Warn(fmt.Sprintf("Unable to convert %s.%s into a string.", optionsKey, fieldMapKey)) + return state, nil + } + options[fieldMapKey] = resource.NewProperty(string(jsonValue)) + + return state, nil +}