diff --git a/auth0/resource_auth0_action.go b/auth0/resource_auth0_action.go index cca93376..c3e70898 100644 --- a/auth0/resource_auth0_action.go +++ b/auth0/resource_auth0_action.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/auth0/go-auth0/management" + "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -153,18 +154,26 @@ func readAction(ctx context.Context, d *schema.ResourceData, m interface{}) diag return diag.FromErr(err) } - result := multierror.Append( + var result *multierror.Error + if action.DeployedVersion != nil { + result = multierror.Append(result, d.Set("version_id", action.DeployedVersion.GetID())) + } + + result = multierror.Append( + result, d.Set("name", action.Name), d.Set("supported_triggers", flattenActionTriggers(action.SupportedTriggers)), d.Set("code", action.Code), d.Set("dependencies", flattenActionDependencies(action.Dependencies)), d.Set("runtime", action.Runtime), ) - if action.DeployedVersion != nil { - result = multierror.Append(result, d.Set("version_id", action.DeployedVersion.GetID())) + + diagnostics := checkForUntrackedActionSecrets(List(d, "secrets").List(), action.Secrets) + if err = result.ErrorOrNil(); err != nil { + diagnostics = append(diagnostics, diag.FromErr(err)...) } - return diag.FromErr(result.ErrorOrNil()) + return diagnostics } func updateAction(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { @@ -251,6 +260,33 @@ func deployAction(ctx context.Context, d *schema.ResourceData, m interface{}) di return diag.FromErr(d.Set("version_id", actionVersion.GetID())) } +func checkForUntrackedActionSecrets( + secretsFromConfig []interface{}, + secretsFromAPI []*management.ActionSecret, +) diag.Diagnostics { + secretKeysInConfigMap := make(map[string]bool, len(secretsFromAPI)) + for _, configSecret := range secretsFromConfig { + secretKeyName := configSecret.(map[string]string)["name"] + secretKeysInConfigMap[secretKeyName] = true + } + + var warnings diag.Diagnostics + for _, secret := range secretsFromAPI { + if _, ok := secretKeysInConfigMap[secret.GetName()]; !ok { + warnings = append(warnings, diag.Diagnostic{ + Severity: diag.Warning, + Summary: "Unexpected Action Secrets", + Detail: fmt.Sprintf("Found unexpected action secrets with key: %s. ", secret.GetName()) + + "To prevent issues, manage them through terraform. If you've just imported this resource " + + "(and your secretsFromAPI match), to make this warning disappear, run a terraform apply.", + AttributePath: cty.Path{cty.GetAttrStep{Name: "secrets"}}, + }) + } + } + + return warnings +} + func expandAction(d *schema.ResourceData) *management.Action { action := &management.Action{ Name: String(d, "name"), diff --git a/auth0/resource_auth0_action_test.go b/auth0/resource_auth0_action_test.go index 7a4846bd..19e2b82d 100644 --- a/auth0/resource_auth0_action_test.go +++ b/auth0/resource_auth0_action_test.go @@ -5,7 +5,12 @@ import ( "regexp" "testing" + "github.com/auth0/go-auth0" + "github.com/auth0/go-auth0/management" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/stretchr/testify/assert" "github.com/auth0/terraform-provider-auth0/auth0/internal/template" ) @@ -19,6 +24,11 @@ resource auth0_action my_action { id = "post-login" version = "v3" } + + secrets { + name = "foo" + value = "111111" + } } ` @@ -43,6 +53,11 @@ resource auth0_action my_action { name = "foo" value = "123456" } + + secrets { + name = "bar" + value = "654321" + } } ` @@ -79,7 +94,9 @@ func TestAccAction(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("auth0_action.my_action", "name", fmt.Sprintf("Test Action %s", t.Name())), resource.TestCheckResourceAttr("auth0_action.my_action", "code", "exports.onExecutePostLogin = async (event, api) => {};"), - resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.#", "0"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.#", "1"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.0.name", "foo"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.0.value", "111111"), resource.TestCheckResourceAttr("auth0_action.my_action", "dependencies.#", "0"), resource.TestCheckResourceAttr("auth0_action.my_action", "runtime", "node16"), resource.TestCheckResourceAttr("auth0_action.my_action", "deploy", "false"), @@ -103,9 +120,11 @@ func TestAccAction(t *testing.T) { resource.TestCheckResourceAttr("auth0_action.my_action", "dependencies.#", "1"), resource.TestCheckResourceAttr("auth0_action.my_action", "dependencies.0.name", "auth0"), resource.TestCheckResourceAttr("auth0_action.my_action", "dependencies.0.version", "2.41.0"), - resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.#", "1"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.#", "2"), resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.0.name", "foo"), resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.0.value", "123456"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.1.name", "bar"), + resource.TestCheckResourceAttr("auth0_action.my_action", "secrets.1.value", "654321"), ), }, { @@ -179,3 +198,72 @@ resource auth0_action my_action { } } ` + +func TestCheckForUntrackedActionSecrets(t *testing.T) { + var testCases = []struct { + name string + givenSecretsConfig []interface{} + givenActionSecrets []*management.ActionSecret + expectedDiagnostics diag.Diagnostics + }{ + { + name: "action has no secrets", + givenSecretsConfig: []interface{}{}, + givenActionSecrets: []*management.ActionSecret{}, + expectedDiagnostics: diag.Diagnostics(nil), + }, + { + name: "action has no untracked secrets", + givenSecretsConfig: []interface{}{ + map[string]string{ + "name": "secretName", + "value": "secretValue", + }, + }, + givenActionSecrets: []*management.ActionSecret{ + { + Name: auth0.String("secretName"), + }, + }, + expectedDiagnostics: diag.Diagnostics(nil), + }, + { + name: "action has untracked secrets", + givenSecretsConfig: []interface{}{ + map[string]string{ + "name": "secretName", + "value": "secretValue", + }, + }, + givenActionSecrets: []*management.ActionSecret{ + { + Name: auth0.String("secretName"), + }, + { + Name: auth0.String("anotherSecretName"), + }, + }, + expectedDiagnostics: diag.Diagnostics{ + { + Severity: diag.Warning, + Summary: "Unexpected Action Secrets", + Detail: "Found unexpected action secrets with key: anotherSecretName. To prevent issues, " + + "manage them through terraform. If you've just imported this resource " + + "(and your secretsFromAPI match), to make this warning disappear, run a terraform apply.", + AttributePath: cty.Path{cty.GetAttrStep{Name: "secrets"}}, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actualDiagnostics := checkForUntrackedActionSecrets( + testCase.givenSecretsConfig, + testCase.givenActionSecrets, + ) + + assert.Equal(t, testCase.expectedDiagnostics, actualDiagnostics) + }) + } +}