diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f67945bf..682970b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ENHANCEMENTS: FEATURES: * `r/tfe_notification_configuration`: Optionally set `url` as a write-only (`url_wo`). Adds support for auto-managed (via hash) for `token_wo` param to avoid manually managing `_version` arguments. By @drewmullen [#2028](https://github.com/hashicorp/terraform-provider-tfe/pull/2028) +- `r/tfe_policy_set` and `d/tfe_policy_set`: Add `policy_update_patterns` attribute support for policy sets. By @nithishravindra [#2030](https://github.com/hashicorp/terraform-provider-tfe/pull/2030) ## v0.76.1 diff --git a/go.mod b/go.mod index 9b65a7fb8..360a50495 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-slug v1.0.0 - github.com/hashicorp/go-tfe v1.103.0 + github.com/hashicorp/go-tfe v1.103.1-0.20260408065133-6253066cb49c github.com/hashicorp/go-version v1.8.0 github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl/v2 v2.24.0 // indirect diff --git a/go.sum b/go.sum index fd7138c23..7c9bac67f 100644 --- a/go.sum +++ b/go.sum @@ -76,6 +76,8 @@ github.com/hashicorp/go-slug v1.0.0 h1:aOwhQ1fIbyRAUdBDzXZK2LVmsFFQYuuvJhOM8X9XW github.com/hashicorp/go-slug v1.0.0/go.mod h1:Zxkkl8/LfXmhxZO3fLXQUCy3MVXAJK9pybY8WoDPgvs= github.com/hashicorp/go-tfe v1.103.0 h1:2sx/8733WdFoEhrKbRkVhrlR+Z3Jkv2juFNFvr9AYQs= github.com/hashicorp/go-tfe v1.103.0/go.mod h1:h9zoGyk0+5YCxuahXVppZ5kUNxqHhdZ21jrnLPDPNS4= +github.com/hashicorp/go-tfe v1.103.1-0.20260408065133-6253066cb49c h1:utycJHvvT0anvj/KogSym8qDUiujwtWrNjMNZclwplE= +github.com/hashicorp/go-tfe v1.103.1-0.20260408065133-6253066cb49c/go.mod h1:h9zoGyk0+5YCxuahXVppZ5kUNxqHhdZ21jrnLPDPNS4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= diff --git a/internal/provider/data_source_policy_set.go b/internal/provider/data_source_policy_set.go index a7687e552..af598a07d 100644 --- a/internal/provider/data_source_policy_set.go +++ b/internal/provider/data_source_policy_set.go @@ -70,6 +70,12 @@ func dataSourceTFEPolicySet() *schema.Resource { Computed: true, }, + "policy_update_patterns": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "policy_ids": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, @@ -158,6 +164,7 @@ func dataSourceTFEPolicySetRead(d *schema.ResourceData, meta interface{}) error d.Set("description", policySet.Description) d.Set("global", policySet.Global) d.Set("policies_path", policySet.PoliciesPath) + d.Set("policy_update_patterns", policySet.PolicyUpdatePatterns) d.Set("agent_enabled", policySet.AgentEnabled) if policySet.Kind != "" { diff --git a/internal/provider/data_source_policy_set_test.go b/internal/provider/data_source_policy_set_test.go index 1a910986f..284333afa 100644 --- a/internal/provider/data_source_policy_set_test.go +++ b/internal/provider/data_source_policy_set_test.go @@ -219,6 +219,12 @@ func TestAccTFEPolicySetDataSource_vcs(t *testing.T) { "data.tfe_policy_set.bar", "project_ids.#", "0"), resource.TestCheckResourceAttr( "data.tfe_policy_set.bar", "vcs_repo.#", "1"), + resource.TestCheckResourceAttr( + "data.tfe_policy_set.bar", "policy_update_patterns.#", "2"), + resource.TestCheckResourceAttr( + "data.tfe_policy_set.bar", "policy_update_patterns.0", "**/*.sentinel"), + resource.TestCheckResourceAttr( + "data.tfe_policy_set.bar", "policy_update_patterns.1", "policies/**/*.hcl"), ), }, }, @@ -401,6 +407,7 @@ resource "tfe_policy_set" "foobar" { name = "tst-policy-set-%d" description = "Policy Set" organization = local.organization_name + policy_update_patterns = ["**/*.sentinel", "policies/**/*.hcl"] vcs_repo { identifier = "%s" branch = "main" diff --git a/internal/provider/resource_tfe_policy_set.go b/internal/provider/resource_tfe_policy_set.go index a0dd66c78..09d6295b4 100644 --- a/internal/provider/resource_tfe_policy_set.go +++ b/internal/provider/resource_tfe_policy_set.go @@ -105,6 +105,13 @@ func resourceTFEPolicySet() *schema.Resource { Computed: true, }, + "policy_update_patterns": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Computed: true, + }, + "policies_path": { Type: schema.TypeString, Optional: true, @@ -209,6 +216,12 @@ func resourceTFEPolicySetCreate(d *schema.ResourceData, meta interface{}) error options.PolicyToolVersion = tfe.String(vPolicyToolVersion.(string)) } + if vPolicyUpdatePatterns, ok := d.GetOk("policy_update_patterns"); ok { + for _, pattern := range vPolicyUpdatePatterns.([]interface{}) { + options.PolicyUpdatePatterns = append(options.PolicyUpdatePatterns, pattern.(string)) + } + } + if desc, ok := d.GetOk("description"); ok { options.Description = tfe.String(desc.(string)) } @@ -286,6 +299,7 @@ func resourceTFEPolicySetRead(d *schema.ResourceData, meta interface{}) error { d.Set("description", policySet.Description) d.Set("global", policySet.Global) d.Set("policies_path", policySet.PoliciesPath) + d.Set("policy_update_patterns", policySet.PolicyUpdatePatterns) d.Set("agent_enabled", policySet.AgentEnabled) if policySet.Organization != nil { @@ -383,7 +397,7 @@ func resourceTFEPolicySetUpdate(d *schema.ResourceData, meta interface{}) error } // Don't bother updating the policy set's attributes if they haven't changed - if d.HasChange("name") || d.HasChange("description") || d.HasChange("global") || d.HasChange("vcs_repo") || d.HasChange("overridable") || d.HasChange("agent_enabled") || d.HasChange("policy_tool_version") { + if d.HasChange("name") || d.HasChange("description") || d.HasChange("global") || d.HasChange("vcs_repo") || d.HasChange("overridable") || d.HasChange("agent_enabled") || d.HasChange("policy_tool_version") || d.HasChange("policy_update_patterns") { // Create a new options struct. options := tfe.PolicySetUpdateOptions{ Name: tfe.String(name), @@ -408,6 +422,12 @@ func resourceTFEPolicySetUpdate(d *schema.ResourceData, meta interface{}) error options.PolicyToolVersion = tfe.String(policyToolVersion.(string)) } + if d.HasChange("policy_update_patterns") { + for _, pattern := range d.Get("policy_update_patterns").([]interface{}) { + options.PolicyUpdatePatterns = append(options.PolicyUpdatePatterns, pattern.(string)) + } + } + if v, ok := d.GetOk("vcs_repo"); ok { vcsRepo := v.([]interface{})[0].(map[string]interface{}) diff --git a/internal/provider/resource_tfe_policy_set_test.go b/internal/provider/resource_tfe_policy_set_test.go index 7254707c6..e2d120253 100644 --- a/internal/provider/resource_tfe_policy_set_test.go +++ b/internal/provider/resource_tfe_policy_set_test.go @@ -522,6 +522,12 @@ func TestAccTFEPolicySet_vcs(t *testing.T) { "tfe_policy_set.foobar", "vcs_repo.0.ingress_submodules", "true"), resource.TestCheckResourceAttr( "tfe_policy_set.foobar", "policies_path", envGithubPolicySetPath), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.#", "2"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.0", "**/*.sentinel"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.1", "policies/**/*.hcl"), ), }, }, @@ -577,6 +583,12 @@ func TestAccTFEPolicySet_GithubApp(t *testing.T) { "tfe_policy_set.foobar", "vcs_repo.0.ingress_submodules", "true"), resource.TestCheckResourceAttr( "tfe_policy_set.foobar", "policies_path", envGithubPolicySetPath), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.#", "2"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.0", "**/*.sentinel"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.1", "policies/**/*.hcl"), ), }, }, @@ -632,6 +644,12 @@ func TestAccTFEPolicySet_updateVCSBranch(t *testing.T) { "tfe_policy_set.foobar", "vcs_repo.0.ingress_submodules", "true"), resource.TestCheckResourceAttr( "tfe_policy_set.foobar", "policies_path", envGithubPolicySetPath), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.#", "2"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.0", "**/*.sentinel"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.1", "policies/**/*.hcl"), ), }, @@ -654,6 +672,12 @@ func TestAccTFEPolicySet_updateVCSBranch(t *testing.T) { "tfe_policy_set.foobar", "vcs_repo.0.ingress_submodules", "true"), resource.TestCheckResourceAttr( "tfe_policy_set.foobar", "policies_path", envGithubPolicySetPath), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.#", "2"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.0", "**/*.sentinel"), + resource.TestCheckResourceAttr( + "tfe_policy_set.foobar", "policy_update_patterns.1", "policies/**/*.hcl"), ), }, }, @@ -1258,6 +1282,7 @@ resource "tfe_policy_set" "foobar" { name = "tst-terraform" description = "Policy Set" organization = local.organization_name + policy_update_patterns = ["**/*.sentinel", "policies/**/*.hcl"] vcs_repo { identifier = "%s" branch = "main" @@ -1284,6 +1309,7 @@ resource "tfe_policy_set" "foobar" { name = "tst-terraform" description = "Policy Set" organization = local.organization_name + policy_update_patterns = ["**/*.sentinel", "policies/**/*.hcl"] vcs_repo { identifier = "%s" branch = "main" @@ -1318,6 +1344,7 @@ resource "tfe_policy_set" "foobar" { name = "tst-terraform" description = "Policy Set" organization = local.organization_name + policy_update_patterns = ["**/*.sentinel", "policies/**/*.hcl"] vcs_repo { identifier = "%s" branch = "%s" diff --git a/website/docs/d/policy_set.html.markdown b/website/docs/d/policy_set.html.markdown index ad1c02201..1034bfed1 100644 --- a/website/docs/d/policy_set.html.markdown +++ b/website/docs/d/policy_set.html.markdown @@ -43,6 +43,10 @@ The following arguments are supported: * `project_ids` - IDs of the projects that use the policy set. * `policy_ids` - IDs of the policies attached to the policy set. * `policies_path` - The sub-path within the attached VCS repository when using `vcs_repo`. +* `policy_update_patterns` - Glob patterns specifying which file changes trigger + policy set updates. Patterns are relative to the repository root, and a + maximum of 100 patterns can be returned. This attribute is only valid when + the policy set specifies a VCS repository. * `vcs_repo` - Settings for the workspace's VCS repository. The `vcs_repo` block contains: diff --git a/website/docs/r/policy_set.html.markdown b/website/docs/r/policy_set.html.markdown index f27cdf2da..2802d32a6 100644 --- a/website/docs/r/policy_set.html.markdown +++ b/website/docs/r/policy_set.html.markdown @@ -27,6 +27,8 @@ resource "tfe_policy_set" "test" { kind = "sentinel" agent_enabled = "true" policy_tool_version = "0.24.1" + # Top-level policy set argument that applies when vcs_repo is configured. + policy_update_patterns = ["**/*.sentinel", "policies/**/*.hcl"] policies_path = "policies/my-policy-set" workspace_ids = [tfe_workspace.test.id] @@ -90,6 +92,10 @@ The following arguments are supported: * `policy_tool_version` - (Optional) The policy tool version to run the evaluation against. For both Sentinel and OPA, leaving this argument unspecified results in selecting the latest available version at the time of creation. For "opa" policy sets, 'latest' will not be a valid input. +* `policy_update_patterns` - (Optional) A list of glob patterns specifying which + file changes trigger policy set updates. Patterns are relative to the repository + root, and you can specify a maximum of 100 patterns. This argument is only + valid when you specify a VCS repository for the policy set. * `overridable` - (Optional) Whether or not users can override this policy when it fails during a run. Defaults to `false`. Only valid for OPA policies. * `organization` - (Optional) Name of the organization. If omitted, organization must be defined in the provider config.