Skip to content

Commit

Permalink
Merge pull request #691 from hashicorp/mr/TF-1451-policysets
Browse files Browse the repository at this point in the history
Add OPA support for policy sets
  • Loading branch information
mrinalirao committed Nov 28, 2022
2 parents fbeac0f + bb1cef5 commit 1392f4a
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,8 @@
FEATURES:
* r/tfe_workspace: Add preemptive check for resources under management when `force_delete` attribute is false ([#699](https://github.com/hashicorp/terraform-provider-tfe/pull/699))
* r/tfe_policy: Add OPA support for policies. `tfe_policy` is a new resource that supports both Sentinel as well as OPA policies. `tfe_sentinel_policy` now includes a deprecation warning. ([#690](https://github.com/hashicorp/terraform-provider-tfe/pull/690))
* r/tfe_policy_set: Add OPA support for policy sets. ([#691](https://github.com/hashicorp/terraform-provider-tfe/pull/691))
* d/tfe_policy_set: Add optional `kind` and `overridable` fields for OPA policy sets ([#691](https://github.com/hashicorp/terraform-provider-tfe/pull/691))

## v0.39.0 (November 18, 2022)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -12,7 +12,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/hashicorp/go-slug v0.10.1
github.com/hashicorp/go-tfe v1.13.0
github.com/hashicorp/go-tfe v1.14.0
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/hcl/v2 v2.15.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -163,8 +163,8 @@ github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-slug v0.10.1 h1:05SCRWCBpCxOeP7stQHvMgOz0raCBCekaytu8Rg/RZ4=
github.com/hashicorp/go-slug v0.10.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-tfe v1.13.0 h1:Z8pJrmN9BV5EncnFRmQmLjhP7pHMNXkC2VkCQXWxKjM=
github.com/hashicorp/go-tfe v1.13.0/go.mod h1:thYtIxtgBpDDNdf/2yYPdBJ94Fz5yT5XCNZvGtTGHAU=
github.com/hashicorp/go-tfe v1.14.0 h1:FZKKkwlyTxw8/OE3e7NiFQLcgGXTHra9ogGhMTotxh8=
github.com/hashicorp/go-tfe v1.14.0/go.mod h1:77snluBqtTTvMrY0w/mxQA5jlHQ8NT44AqQ8UdrPf0o=
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=
Expand Down
21 changes: 21 additions & 0 deletions tfe/data_source_policy_set.go
Expand Up @@ -33,6 +33,18 @@ func dataSourceTFEPolicySet() *schema.Resource {
Computed: true,
},

"kind": {
Description: "The policy-as-code framework for the policy. Valid values are sentinel and opa",
Type: schema.TypeString,
Optional: true,
},

"overridable": {
Description: "Whether users can override this policy when it fails during a run. Only valid for OPA policies",
Type: schema.TypeBool,
Optional: true,
},

"policies_path": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -100,6 +112,7 @@ func dataSourceTFEPolicySetRead(d *schema.ResourceData, meta interface{}) error
}

for _, policySet := range policySetList.Items {
// nolint: nestif
if policySet.Name == name {
d.Set("name", policySet.Name)
d.Set("description", policySet.Description)
Expand All @@ -110,6 +123,14 @@ func dataSourceTFEPolicySetRead(d *schema.ResourceData, meta interface{}) error
d.Set("organization", policySet.Organization.Name)
}

if policySet.Kind != "" {
d.Set("kind", policySet.Kind)
}

if policySet.Overridable != nil {
d.Set("overridable", policySet.Overridable)
}

var vcsRepo []interface{}
if policySet.VCSRepo != nil {
vcsRepo = append(vcsRepo, map[string]interface{}{
Expand Down
72 changes: 72 additions & 0 deletions tfe/data_source_policy_set_test.go
Expand Up @@ -50,6 +50,49 @@ func TestAccTFEPolicySetDataSource_basic(t *testing.T) {
)
}

func TestAccTFEPolicySetDataSourceOPA_basic(t *testing.T) {
skipUnlessBeta(t)
tfeClient, err := getClientUsingEnv()
if err != nil {
t.Fatal(err)
}

org, orgCleanup := createBusinessOrganization(t, tfeClient)
t.Cleanup(orgCleanup)

rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccTFEPolicySetDataSourceConfigOPA_basic(org.Name, rInt),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet("data.tfe_policy_set.bar", "id"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "name", fmt.Sprintf("tst-policy-set-%d", rInt)),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "global", "false"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "organization", org.Name),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "kind", "opa"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "overridable", "true"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "workspace_ids.#", "1"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "vcs_repo.#", "0"),
),
},
},
},
)
}

func TestAccTFEPolicySetDataSource_vcs(t *testing.T) {
tfeClient, err := getClientUsingEnv()
if err != nil {
Expand Down Expand Up @@ -90,6 +133,8 @@ func TestAccTFEPolicySetDataSource_vcs(t *testing.T) {
"data.tfe_policy_set.bar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "global", "false"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"data.tfe_policy_set.bar", "organization", org.Name),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -152,6 +197,33 @@ data "tfe_policy_set" "bar" {
}`, organization, rInt, rInt)
}

func testAccTFEPolicySetDataSourceConfigOPA_basic(organization string, rInt int) string {
return fmt.Sprintf(`
locals {
organization_name = "%s"
}
resource "tfe_workspace" "foobar" {
name = "workspace-foo-%d"
organization = local.organization_name
}
resource "tfe_policy_set" "foobar" {
name = "tst-policy-set-%d"
description = "Policy Set"
organization = local.organization_name
kind = "opa"
overridable = true
workspace_ids = [tfe_workspace.foobar.id]
}
data "tfe_policy_set" "bar" {
name = tfe_policy_set.foobar.name
organization = local.organization_name
kind = "opa"
}`, organization, rInt, rInt)
}

func testAccTFEPolicySetDataSourceConfig_vcs(organization string, rInt int) string {
return fmt.Sprintf(`
locals {
Expand Down
42 changes: 41 additions & 1 deletion tfe/resource_tfe_policy_set.go
Expand Up @@ -46,6 +46,24 @@ func resourceTFEPolicySet() *schema.Resource {
ConflictsWith: []string{"workspace_ids"},
},

"kind": {
Type: schema.TypeString,
Optional: true,
Default: string(tfe.Sentinel),
ForceNew: true,
ValidateFunc: validation.StringInSlice(
[]string{
string(tfe.OPA),
string(tfe.Sentinel),
}, false),
},

"overridable": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"policies_path": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -123,6 +141,14 @@ func resourceTFEPolicySetCreate(d *schema.ResourceData, meta interface{}) error
}

// Process all configured options.
if vKind, ok := d.GetOk("kind"); ok {
options.Kind = tfe.PolicyKind(vKind.(string))
}

if vOverridable, ok := d.GetOk("overridable"); ok {
options.Overridable = tfe.Bool(vOverridable.(bool))
}

if desc, ok := d.GetOk("description"); ok {
options.Description = tfe.String(desc.(string))
}
Expand Down Expand Up @@ -199,6 +225,15 @@ func resourceTFEPolicySetRead(d *schema.ResourceData, meta interface{}) error {
d.Set("organization", policySet.Organization.Name)
}

// Note: Old API endpoints return an empty string, so use the default in the schema
if policySet.Kind != "" {
d.Set("kind", policySet.Kind)
}

if policySet.Overridable != nil {
d.Set("overridable", policySet.Overridable)
}

// Set VCS policy set options.
var vcsRepo []interface{}
if policySet.VCSRepo != nil {
Expand Down Expand Up @@ -271,7 +306,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") {
if d.HasChange("name") || d.HasChange("description") || d.HasChange("global") || d.HasChange("vcs_repo") || d.HasChange("overridable") {
// Create a new options struct.
options := tfe.PolicySetUpdateOptions{
Name: tfe.String(name),
Expand All @@ -282,6 +317,11 @@ func resourceTFEPolicySetUpdate(d *schema.ResourceData, meta interface{}) error
options.Description = tfe.String(desc.(string))
}

if d.HasChange("overridable") {
o := d.Get("overridable").(bool)
options.Overridable = tfe.Bool(o)
}

if v, ok := d.GetOk("vcs_repo"); ok {
vcsRepo := v.([]interface{})[0].(map[string]interface{})

Expand Down

0 comments on commit 1392f4a

Please sign in to comment.