Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OPA support for policy sets #691

Merged
merged 10 commits into from Nov 28, 2022
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

FEATURES:
* r/tfe_organization: Add `allow_force_delete_workspaces` attribute to set whether admins are permitted to delete workspaces with resource under management. ([#661](https://github.com/hashicorp/terraform-provider-tfe/pull/661))
* 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.38.0 (October 24, 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.0
github.com/hashicorp/go-tfe v1.12.0
github.com/hashicorp/go-tfe v1.13.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.0 h1:mh4DDkBJTh9BuEjY/cv8PTo7k9OjT4PcW8PgZnJ4jTY=
github.com/hashicorp/go-slug v0.10.0/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4=
github.com/hashicorp/go-tfe v1.12.0 h1:2l7emKW8rNTTbnxYHNVj6b46iJzOEp2G/3xIHfGSDnc=
github.com/hashicorp/go-tfe v1.12.0/go.mod h1:thYtIxtgBpDDNdf/2yYPdBJ94Fz5yT5XCNZvGtTGHAU=
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-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
20 changes: 20 additions & 0 deletions tfe/data_source_policy_set.go
Expand Up @@ -33,6 +33,17 @@ func dataSourceTFEPolicySet() *schema.Resource {
Computed: true,
},

"kind": {
mrinalirao marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Optional: true,
},

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

"policies_path": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -100,6 +111,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 +122,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
34 changes: 34 additions & 0 deletions tfe/resource_tfe_policy_set.go
Expand Up @@ -46,6 +46,23 @@ func resourceTFEPolicySet() *schema.Resource {
ConflictsWith: []string{"workspace_ids"},
},

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

"overridable": {
Type: schema.TypeBool,
Optional: true,
Default: false,
mrinalirao marked this conversation as resolved.
Show resolved Hide resolved
},

"policies_path": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -123,6 +140,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 +224,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
63 changes: 63 additions & 0 deletions tfe/resource_tfe_policy_set_test.go
Expand Up @@ -46,6 +46,44 @@ func TestAccTFEPolicySet_basic(t *testing.T) {
})
}

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

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

policySet := &tfe.PolicySet{}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEPolicySetDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEPolicySetOPA_basic(org.Name),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEPolicySetExists("tfe_policy_set.foobar", policySet),
testAccCheckTFEPolicySetAttributes(policySet),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "name", "tst-terraform"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "opa"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "overridable", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
),
},
},
})
}

func TestAccTFEPolicySet_update(t *testing.T) {
tfeClient, err := getClientUsingEnv()
if err != nil {
Expand Down Expand Up @@ -87,6 +125,8 @@ func TestAccTFEPolicySet_update(t *testing.T) {
"tfe_policy_set.foobar", "name", "terraform-populated"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "policy_ids.#", "1"),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -189,6 +229,8 @@ func TestAccTFEPolicySet_updatePopulated(t *testing.T) {
"tfe_policy_set.foobar", "name", "terraform-populated-updated"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "policy_ids.#", "1"),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -240,6 +282,8 @@ func TestAccTFEPolicySet_updateToGlobal(t *testing.T) {
"tfe_policy_set.foobar", "name", "terraform-global"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "true"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "policy_ids.#", "1"),
),
Expand Down Expand Up @@ -338,6 +382,8 @@ func TestAccTFEPolicySet_vcs(t *testing.T) {
"tfe_policy_set.foobar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "vcs_repo.0.identifier", GITHUB_POLICY_SET_IDENTIFIER),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -393,6 +439,8 @@ func TestAccTFEPolicySet_updateVCSBranch(t *testing.T) {
"tfe_policy_set.foobar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "vcs_repo.0.identifier", GITHUB_POLICY_SET_IDENTIFIER),
resource.TestCheckResourceAttr(
Expand All @@ -415,6 +463,8 @@ func TestAccTFEPolicySet_updateVCSBranch(t *testing.T) {
"tfe_policy_set.foobar", "description", "Policy Set"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "global", "false"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "kind", "sentinel"),
resource.TestCheckResourceAttr(
"tfe_policy_set.foobar", "vcs_repo.0.identifier", GITHUB_POLICY_SET_IDENTIFIER),
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -628,6 +678,9 @@ func TestAccTFEPolicySetImport(t *testing.T) {
ResourceName: "tfe_policy_set.foobar",
ImportState: true,
ImportStateVerify: true,
// Note: We ignore the optional fields below, since the old API endpoints send empty values
// and the results may vary depending on the API version
ImportStateVerifyIgnore: []string{"kind", "overridable"},
},
},
})
Expand Down Expand Up @@ -819,6 +872,16 @@ resource "tfe_policy_set" "foobar" {
}`, organization, organization)
}

func testAccTFEPolicySetOPA_basic(organization string) string {
return fmt.Sprintf(`
resource "tfe_policy_set" "foobar" {
name = "tst-terraform"
description = "Policy Set"
organization = "%s"
kind = "opa"
}`, organization)
}

func testAccTFEPolicySet_empty(organization string) string {
return fmt.Sprintf(`
resource "tfe_policy_set" "foobar" {
Expand Down