diff --git a/docs/data-sources/stack.md b/docs/data-sources/stack.md index aa8a8196..846e4a80 100644 --- a/docs/data-sources/stack.md +++ b/docs/data-sources/stack.md @@ -54,6 +54,7 @@ data "spacelift_stack" "k8s-core" { - `cloudformation` (List of Object) CloudFormation-specific configuration. Presence means this Stack is a CloudFormation Stack. (see [below for nested schema](#nestedatt--cloudformation)) - `description` (String) free-form stack description for users - `enable_local_preview` (Boolean) Indicates whether local preview runs can be triggered on this Stack. +- `enable_well_known_secret_masking` (Boolean) Indicates whether well-known secret masking is enabled. - `github_enterprise` (List of Object) GitHub Enterprise (self-hosted) VCS settings (see [below for nested schema](#nestedatt--github_enterprise)) - `gitlab` (List of Object) GitLab VCS settings (see [below for nested schema](#nestedatt--gitlab)) - `id` (String) The ID of this resource. diff --git a/docs/data-sources/stacks.md b/docs/data-sources/stacks.md index 2170cbbe..e5d4ba60 100644 --- a/docs/data-sources/stacks.md +++ b/docs/data-sources/stacks.md @@ -151,6 +151,7 @@ Read-Only: - `cloudformation` (List of Object) (see [below for nested schema](#nestedobjatt--stacks--cloudformation)) - `description` (String) - `enable_local_preview` (Boolean) +- `enable_well_known_secret_masking` (Boolean) - `github_enterprise` (List of Object) (see [below for nested schema](#nestedobjatt--stacks--github_enterprise)) - `gitlab` (List of Object) (see [below for nested schema](#nestedobjatt--stacks--gitlab)) - `kubernetes` (List of Object) (see [below for nested schema](#nestedobjatt--stacks--kubernetes)) diff --git a/docs/resources/stack.md b/docs/resources/stack.md index bb5bf5cd..621c9e6c 100644 --- a/docs/resources/stack.md +++ b/docs/resources/stack.md @@ -232,6 +232,7 @@ resource "spacelift_stack" "terragrunt-stack" { - `cloudformation` (Block List, Max: 1) CloudFormation-specific configuration. Presence means this Stack is a CloudFormation Stack. (see [below for nested schema](#nestedblock--cloudformation)) - `description` (String) Free-form stack description for users - `enable_local_preview` (Boolean) Indicates whether local preview runs can be triggered on this Stack. Defaults to `false`. +- `enable_well_known_secret_masking` (Boolean) Indicates whether well-known secret masking is enabled. - `github_action_deploy` (Boolean) Indicates whether GitHub users can deploy from the Checks API. Defaults to `true`. This is called allow run promotion in the UI. - `github_enterprise` (Block List, Max: 1) VCS settings for [GitHub custom application](https://docs.spacelift.io/integrations/source-control/github#setting-up-the-custom-application) (see [below for nested schema](#nestedblock--github_enterprise)) - `gitlab` (Block List, Max: 1) GitLab VCS settings (see [below for nested schema](#nestedblock--gitlab)) diff --git a/spacelift/data_stack.go b/spacelift/data_stack.go index cdaf062e..75e0b74f 100644 --- a/spacelift/data_stack.go +++ b/spacelift/data_stack.go @@ -301,6 +301,11 @@ func dataStack() *schema.Resource { Description: "Indicates whether local preview runs can be triggered on this Stack.", Computed: true, }, + "enable_well_known_secret_masking": { + Type: schema.TypeBool, + Description: "Indicates whether well-known secret masking is enabled.", + Computed: true, + }, "kubernetes": { Type: schema.TypeList, Description: "Kubernetes-specific configuration. Presence means this Stack is a Kubernetes Stack.", @@ -522,6 +527,7 @@ func dataStackRead(ctx context.Context, d *schema.ResourceData, meta interface{} d.Set("branch", stack.Branch) d.Set("description", stack.Description) d.Set("enable_local_preview", stack.LocalPreviewEnabled) + d.Set("enable_well_known_secret_masking", stack.EnableWellKnownSecretMasking) d.Set("manage_state", stack.ManagesStateFile) d.Set("name", stack.Name) d.Set("project_root", stack.ProjectRoot) diff --git a/spacelift/data_stack_test.go b/spacelift/data_stack_test.go index 844e3a12..5688e6e4 100644 --- a/spacelift/data_stack_test.go +++ b/spacelift/data_stack_test.go @@ -42,6 +42,7 @@ func TestStackData(t *testing.T) { terraform_workspace = "bacon" terraform_smart_sanitization = true terraform_external_state_access = true + enable_well_known_secret_masking = true } data "spacelift_stack" "test" { stack_id = spacelift_stack.test.id @@ -90,6 +91,7 @@ func TestStackData(t *testing.T) { Attribute("terraform_workspace", Equals("bacon")), Attribute("terraform_smart_sanitization", Equals("true")), Attribute("terraform_external_state_access", Equals("true")), + Attribute("enable_well_known_secret_masking", Equals("true")), ), }}) }) @@ -310,6 +312,7 @@ func TestStackData(t *testing.T) { Check: Resource( "data.spacelift_stack.test", Attribute("terraform_workflow_tool", Equals("CUSTOM")), + Attribute("enable_well_known_secret_masking", Equals("false")), ), }, }) diff --git a/spacelift/internal/structs/stack.go b/spacelift/internal/structs/stack.go index 53b6b053..ece7317a 100644 --- a/spacelift/internal/structs/stack.go +++ b/spacelift/internal/structs/stack.go @@ -25,42 +25,43 @@ const StackConfigVendorTerragrunt = "StackConfigVendorTerragrunt" // Stack represents the Stack data relevant to the provider. type Stack struct { - ID string `graphql:"id"` - Administrative bool `graphql:"administrative"` - AfterApply []string `graphql:"afterApply"` - AfterDestroy []string `graphql:"afterDestroy"` - AfterInit []string `graphql:"afterInit"` - AfterPerform []string `graphql:"afterPerform"` - AfterPlan []string `graphql:"afterPlan"` - AfterRun []string `graphql:"afterRun"` - Autodeploy bool `graphql:"autodeploy"` - Autoretry bool `graphql:"autoretry"` - BeforeApply []string `graphql:"beforeApply"` - BeforeDestroy []string `graphql:"beforeDestroy"` - BeforeInit []string `graphql:"beforeInit"` - BeforePerform []string `graphql:"beforePerform"` - BeforePlan []string `graphql:"beforePlan"` - Branch string `graphql:"branch"` - Deleting bool `graphql:"deleting"` - Description *string `graphql:"description"` - IsDisabled bool `graphql:"isDisabled"` - GitHubActionDeploy bool `graphql:"githubActionDeploy"` - Integrations *Integrations `graphql:"integrations"` - Labels []string `graphql:"labels"` - LocalPreviewEnabled bool `graphql:"localPreviewEnabled"` - ManagesStateFile bool `graphql:"managesStateFile"` - Name string `graphql:"name"` - Namespace string `graphql:"namespace"` - ProjectRoot *string `graphql:"projectRoot"` - AdditionalProjectGlobs []string `graphql:"additionalProjectGlobs"` - ProtectFromDeletion bool `graphql:"protectFromDeletion"` - Provider VCSProvider `graphql:"provider"` - Repository string `graphql:"repository"` - RepositoryURL *string `graphql:"repositoryURL"` - RunnerImage *string `graphql:"runnerImage"` - Space string `graphql:"space"` - TerraformVersion *string `graphql:"terraformVersion"` - VCSIntegration *struct { + ID string `graphql:"id"` + Administrative bool `graphql:"administrative"` + AfterApply []string `graphql:"afterApply"` + AfterDestroy []string `graphql:"afterDestroy"` + AfterInit []string `graphql:"afterInit"` + AfterPerform []string `graphql:"afterPerform"` + AfterPlan []string `graphql:"afterPlan"` + AfterRun []string `graphql:"afterRun"` + Autodeploy bool `graphql:"autodeploy"` + Autoretry bool `graphql:"autoretry"` + BeforeApply []string `graphql:"beforeApply"` + BeforeDestroy []string `graphql:"beforeDestroy"` + BeforeInit []string `graphql:"beforeInit"` + BeforePerform []string `graphql:"beforePerform"` + BeforePlan []string `graphql:"beforePlan"` + Branch string `graphql:"branch"` + Deleting bool `graphql:"deleting"` + Description *string `graphql:"description"` + IsDisabled bool `graphql:"isDisabled"` + GitHubActionDeploy bool `graphql:"githubActionDeploy"` + Integrations *Integrations `graphql:"integrations"` + Labels []string `graphql:"labels"` + LocalPreviewEnabled bool `graphql:"localPreviewEnabled"` + EnableWellKnownSecretMasking bool `graphql:"enableWellKnownSecretMasking"` + ManagesStateFile bool `graphql:"managesStateFile"` + Name string `graphql:"name"` + Namespace string `graphql:"namespace"` + ProjectRoot *string `graphql:"projectRoot"` + AdditionalProjectGlobs []string `graphql:"additionalProjectGlobs"` + ProtectFromDeletion bool `graphql:"protectFromDeletion"` + Provider VCSProvider `graphql:"provider"` + Repository string `graphql:"repository"` + RepositoryURL *string `graphql:"repositoryURL"` + RunnerImage *string `graphql:"runnerImage"` + Space string `graphql:"space"` + TerraformVersion *string `graphql:"terraformVersion"` + VCSIntegration *struct { ID string `graphql:"id"` IsDefault bool `graphql:"isDefault"` } `graphql:"vcsIntegration"` @@ -232,6 +233,7 @@ func PopulateStack(d *schema.ResourceData, stack *Stack) error { d.Set("branch", stack.Branch) d.Set("description", stack.Description) d.Set("enable_local_preview", stack.LocalPreviewEnabled) + d.Set("enable_well_known_secret_masking", stack.EnableWellKnownSecretMasking) d.Set("github_action_deploy", stack.GitHubActionDeploy) d.Set("manage_state", stack.ManagesStateFile) d.Set("name", stack.Name) diff --git a/spacelift/internal/structs/stack_input.go b/spacelift/internal/structs/stack_input.go index fe8c921e..30a2f2e8 100644 --- a/spacelift/internal/structs/stack_input.go +++ b/spacelift/internal/structs/stack_input.go @@ -4,38 +4,39 @@ import "github.com/shurcooL/graphql" // StackInput represents the input required to create or update a Stack. type StackInput struct { - Administrative graphql.Boolean `json:"administrative"` - AfterApply *[]graphql.String `json:"afterApply"` - AfterDestroy *[]graphql.String `json:"afterDestroy"` - AfterInit *[]graphql.String `json:"afterInit"` - AfterPerform *[]graphql.String `json:"afterPerform"` - AfterPlan *[]graphql.String `json:"afterPlan"` - AfterRun *[]graphql.String `json:"afterRun"` - Autodeploy graphql.Boolean `json:"autodeploy"` - Autoretry graphql.Boolean `json:"autoretry"` - BeforeApply *[]graphql.String `json:"beforeApply"` - BeforeDestroy *[]graphql.String `json:"beforeDestroy"` - BeforeInit *[]graphql.String `json:"beforeInit"` - BeforePerform *[]graphql.String `json:"beforePerform"` - BeforePlan *[]graphql.String `json:"beforePlan"` - Branch graphql.String `json:"branch"` - Description *graphql.String `json:"description"` - GitHubActionDeploy graphql.Boolean `json:"githubActionDeploy"` - Labels *[]graphql.String `json:"labels"` - LocalPreviewEnabled graphql.Boolean `json:"localPreviewEnabled"` - Name graphql.String `json:"name"` - Namespace *graphql.String `json:"namespace"` - ProjectRoot *graphql.String `json:"projectRoot"` - AddditionalProjectGlobs *[]graphql.String `json:"additionalProjectGlobs"` - ProtectFromDeletion graphql.Boolean `json:"protectFromDeletion"` - Provider *graphql.String `json:"provider"` - Repository graphql.String `json:"repository"` - RepositoryURL *graphql.String `json:"repositoryURL"` - RunnerImage *graphql.String `json:"runnerImage"` - Space *graphql.String `json:"space"` - VCSIntegrationID *graphql.ID `json:"vcsIntegrationId"` - VendorConfig *VendorConfigInput `json:"vendorConfig"` - WorkerPool *graphql.ID `json:"workerPool"` + Administrative graphql.Boolean `json:"administrative"` + AfterApply *[]graphql.String `json:"afterApply"` + AfterDestroy *[]graphql.String `json:"afterDestroy"` + AfterInit *[]graphql.String `json:"afterInit"` + AfterPerform *[]graphql.String `json:"afterPerform"` + AfterPlan *[]graphql.String `json:"afterPlan"` + AfterRun *[]graphql.String `json:"afterRun"` + Autodeploy graphql.Boolean `json:"autodeploy"` + Autoretry graphql.Boolean `json:"autoretry"` + BeforeApply *[]graphql.String `json:"beforeApply"` + BeforeDestroy *[]graphql.String `json:"beforeDestroy"` + BeforeInit *[]graphql.String `json:"beforeInit"` + BeforePerform *[]graphql.String `json:"beforePerform"` + BeforePlan *[]graphql.String `json:"beforePlan"` + Branch graphql.String `json:"branch"` + Description *graphql.String `json:"description"` + GitHubActionDeploy graphql.Boolean `json:"githubActionDeploy"` + Labels *[]graphql.String `json:"labels"` + LocalPreviewEnabled graphql.Boolean `json:"localPreviewEnabled"` + EnableWellKnownSecretMasking graphql.Boolean `json:"enableWellKnownSecretMasking"` + Name graphql.String `json:"name"` + Namespace *graphql.String `json:"namespace"` + ProjectRoot *graphql.String `json:"projectRoot"` + AddditionalProjectGlobs *[]graphql.String `json:"additionalProjectGlobs"` + ProtectFromDeletion graphql.Boolean `json:"protectFromDeletion"` + Provider *graphql.String `json:"provider"` + Repository graphql.String `json:"repository"` + RepositoryURL *graphql.String `json:"repositoryURL"` + RunnerImage *graphql.String `json:"runnerImage"` + Space *graphql.String `json:"space"` + VCSIntegrationID *graphql.ID `json:"vcsIntegrationId"` + VendorConfig *VendorConfigInput `json:"vendorConfig"` + WorkerPool *graphql.ID `json:"workerPool"` } // VendorConfigInput represents vendor-specific configuration. diff --git a/spacelift/resource_stack.go b/spacelift/resource_stack.go index 8e809b87..f3fd9726 100644 --- a/spacelift/resource_stack.go +++ b/spacelift/resource_stack.go @@ -322,6 +322,12 @@ func resourceStack() *schema.Resource { Optional: true, Default: false, }, + "enable_well_known_secret_masking": { + Type: schema.TypeBool, + Description: "Indicates whether well-known secret masking is enabled.", + Optional: true, + Default: false, + }, "github_action_deploy": { Type: schema.TypeBool, Description: "Indicates whether GitHub users can deploy from the Checks API. Defaults to `true`. This is called allow run promotion in the UI.", @@ -761,15 +767,16 @@ func resourceStackDelete(ctx context.Context, d *schema.ResourceData, meta inter func stackInput(d *schema.ResourceData) structs.StackInput { ret := structs.StackInput{ - Administrative: graphql.Boolean(d.Get("administrative").(bool)), - Autodeploy: graphql.Boolean(d.Get("autodeploy").(bool)), - Autoretry: graphql.Boolean(d.Get("autoretry").(bool)), - Branch: toString(d.Get("branch")), - GitHubActionDeploy: graphql.Boolean(d.Get("github_action_deploy").(bool)), - LocalPreviewEnabled: graphql.Boolean(d.Get("enable_local_preview").(bool)), - Name: toString(d.Get("name")), - ProtectFromDeletion: graphql.Boolean(d.Get("protect_from_deletion").(bool)), - Repository: toString(d.Get("repository")), + Administrative: graphql.Boolean(d.Get("administrative").(bool)), + Autodeploy: graphql.Boolean(d.Get("autodeploy").(bool)), + Autoretry: graphql.Boolean(d.Get("autoretry").(bool)), + Branch: toString(d.Get("branch")), + GitHubActionDeploy: graphql.Boolean(d.Get("github_action_deploy").(bool)), + LocalPreviewEnabled: graphql.Boolean(d.Get("enable_local_preview").(bool)), + EnableWellKnownSecretMasking: graphql.Boolean(d.Get("enable_well_known_secret_masking").(bool)), + Name: toString(d.Get("name")), + ProtectFromDeletion: graphql.Boolean(d.Get("protect_from_deletion").(bool)), + Repository: toString(d.Get("repository")), } afterApplies := getStrings(d, "after_apply") diff --git a/spacelift/resource_stack_test.go b/spacelift/resource_stack_test.go index f8550465..98950515 100644 --- a/spacelift/resource_stack_test.go +++ b/spacelift/resource_stack_test.go @@ -17,7 +17,7 @@ func TestStackResource(t *testing.T) { t.Run("with GitHub and no state import", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - config := func(description string, protectFromDeletion bool) string { + config := func(description string, protectFromDeletion, enableWellKnownSecretMasking bool) string { return fmt.Sprintf(` resource "spacelift_stack" "test" { administrative = true @@ -44,15 +44,16 @@ func TestStackResource(t *testing.T) { protect_from_deletion = %t repository = "demo" runner_image = "custom_image:runner" + enable_well_known_secret_masking = %t } - `, description, randomID, protectFromDeletion) + `, description, randomID, protectFromDeletion, enableWellKnownSecretMasking) } const resourceName = "spacelift_stack.test" testSteps(t, []resource.TestStep{ { - Config: config("old description", true), + Config: config("old description", true, false), Check: Resource( resourceName, Attribute("id", StartsWith("provider-test-stack-")), @@ -93,6 +94,7 @@ func TestStackResource(t *testing.T) { Attribute("project_root", Equals("root")), SetEquals("additional_project_globs", "/bacon", "/bacon/eggs/*"), Attribute("protect_from_deletion", Equals("true")), + Attribute("enable_well_known_secret_masking", Equals("false")), Attribute("repository", Equals("demo")), Attribute("runner_image", Equals("custom_image:runner")), ), @@ -104,11 +106,12 @@ func TestStackResource(t *testing.T) { ImportStateVerifyIgnore: []string{"import_state"}, }, { - Config: config("new description", false), + Config: config("new description", false, true), Check: Resource( resourceName, Attribute("description", Equals("new description")), Attribute("protect_from_deletion", Equals("false")), + Attribute("enable_well_known_secret_masking", Equals("true")), ), }, }) @@ -194,6 +197,7 @@ func TestStackResource(t *testing.T) { Attribute("project_root", Equals("root")), Attribute("repository", Equals("demo")), Attribute("runner_image", Equals("custom_image:runner")), + Attribute("enable_well_known_secret_masking", Equals("false")), ), }, { diff --git a/spacelift/test_provider.go b/spacelift/test_provider.go index ee66e887..e9fae4f8 100644 --- a/spacelift/test_provider.go +++ b/spacelift/test_provider.go @@ -26,6 +26,7 @@ func testProvider() *schema.Provider { func testSteps(t *testing.T, steps []resource.TestStep) { t.Parallel() + t.Helper() resource.Test(t, resource.TestCase{ IsUnitTest: true,