Skip to content

Commit

Permalink
Add run_tasks permission to Team Access
Browse files Browse the repository at this point in the history
Run Tasks has added a new `run_tasks` custom permission to Team
Workspace access.  This commit adds this new permission to the
Team Access object (both resource and data) and adds acceptance
tests for both objects.
  • Loading branch information
glennsarti committed Jun 16, 2022
1 parent a5f8efe commit 4bc5ff4
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 9 deletions.
15 changes: 7 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

BREAKING CHANGES:
* **Removed Authentication Method**: Host-specific TF_TOKEN_... environment variable can no longer be used for token authentication. This method of authentication is incompatible with the Terraform Cloud remote execution model. Please use the TFE_TOKEN environment variable.
* r/tfe_workspace: Default value of the `file_triggers_enabled` field is changed to `false`. This will align the
`file_triggers_enabled` field default value with the default value for the same field in the
[TFC API](https://www.terraform.io/cloud-docs/api-docs/workspaces).
If the value of the `file_triggers_enabled` field was not explicitly set and either of the fields `working_directory`
(not an empty string) or `trigger_prefixes` was used - to keep the behavior unchanged, the `file_trigger_enabled`
field should now explicitly be set to `true`. ([#510](https://github.com/hashicorp/terraform-provider-tfe/pull/510/files))
* r/tfe_team_access: The `permissions` attribute requires `run_tasks` in the block. ([#487](https://github.com/hashicorp/terraform-provider-tfe/pull/487))

BUG FIXES:
* Prevent overwriting `vcs_repo` attributes in `r/tfe_workspace` when update API call fails ([#498](https://github.com/hashicorp/terraform-provider-tfe/pull/498))
Expand All @@ -14,14 +21,6 @@ FEATURES:
* **New Data Source**: d/tfe_workspace_run_task ([#488](https://github.com/hashicorp/terraform-provider-tfe/pull/488))
* r/tfe_notification_configuration: Add Microsoft Teams notification type ([#484](https://github.com/hashicorp/terraform-provider-tfe/pull/484))

BREAKING CHANGES:
* r/tfe_workspace: Default value of the `file_triggers_enabled` field is changed to `false`. This will align the
`file_triggers_enabled` field default value with the default value for the same field in the
[TFC API](https://www.terraform.io/cloud-docs/api-docs/workspaces).
If the value of the `file_triggers_enabled` field was not explicitly set and either of the fields `working_directory`
(not an empty string) or `trigger_prefixes` was used - to keep the behavior unchanged, the `file_trigger_enabled`
field should now explicitly be set to `true`. ([#510](https://github.com/hashicorp/terraform-provider-tfe/pull/510/files))

## 0.31.0 (April 21, 2022)

BUG FIXES:
Expand Down
5 changes: 5 additions & 0 deletions tfe/data_source_team_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func dataSourceTFETeamAccess() *schema.Resource {
Type: schema.TypeBool,
Computed: true,
},

"run_tasks": {
Type: schema.TypeBool,
Computed: true,
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions tfe/data_source_team_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ func TestAccTFETeamAccessDataSource_basic(t *testing.T) {
"data.tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"),
resource.TestCheckResourceAttr(
"data.tfe_team_access.foobar", "permissions.0.workspace_locking", "true"),
resource.TestCheckResourceAttr(
"data.tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "id"),
resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "team_id"),
resource.TestCheckResourceAttrSet("data.tfe_team_access.foobar", "workspace_id"),
Expand Down
28 changes: 27 additions & 1 deletion tfe/resource_tfe_team_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ func resourceTFETeamAccess() *schema.Resource {
Type: schema.TypeBool,
Required: true,
},

"run_tasks": {
Type: schema.TypeBool,
Required: true,
},
},
},
},
Expand Down Expand Up @@ -193,6 +198,12 @@ func resourceTFETeamAccessCreate(d *schema.ResourceData, meta interface{}) error
}
}

if d.HasChange("permissions.0.run_tasks") {
if v, ok := d.GetOkExists("permissions.0.run_tasks"); ok {
options.RunTasks = tfe.Bool(v.(bool))
}
}

log.Printf("[DEBUG] Give team %s %s access to workspace: %s", tm.Name, access, ws.Name)
tmAccess, err := tfeClient.TeamAccess.Add(ctx, options)
if err != nil {
Expand Down Expand Up @@ -227,6 +238,7 @@ func resourceTFETeamAccessRead(d *schema.ResourceData, meta interface{}) error {
"state_versions": tmAccess.StateVersions,
"sentinel_mocks": tmAccess.SentinelMocks,
"workspace_locking": tmAccess.WorkspaceLocking,
"run_tasks": tmAccess.RunTasks,
}}
if err := d.Set("permissions", permissions); err != nil {
return fmt.Errorf("error setting permissions for team access %s: %w", d.Id(), err)
Expand Down Expand Up @@ -281,6 +293,12 @@ func resourceTFETeamAccessUpdate(d *schema.ResourceData, meta interface{}) error
}
}

if d.HasChange("permissions.0.run_tasks") {
if v, ok := d.GetOkExists("permissions.0.run_tasks"); ok {
options.RunTasks = tfe.Bool(v.(bool))
}
}

log.Printf("[DEBUG] Update team access: %s", d.Id())
tmAccess, err := tfeClient.TeamAccess.Update(ctx, d.Id(), options)
if err != nil {
Expand All @@ -295,6 +313,7 @@ func resourceTFETeamAccessUpdate(d *schema.ResourceData, meta interface{}) error
"state_versions": tmAccess.StateVersions,
"sentinel_mocks": tmAccess.SentinelMocks,
"workspace_locking": tmAccess.WorkspaceLocking,
"run_tasks": tmAccess.RunTasks,
}}
if err := d.Set("permissions", permissions); err != nil {
return fmt.Errorf("error setting permissions for team access %s: %w", d.Id(), err)
Expand Down Expand Up @@ -397,7 +416,14 @@ func setCustomAccess(d *schema.ResourceDiff) error {
// Interpolated values not known at plan time are not allowed because we cannot re-check
// for a change in permissions later - when the plan is expanded for new values learned during
// an apply. This creates an inconsistent final plan and causes an error.
for _, permission := range []string{"permissions.0.runs", "permissions.0.variables", "permissions.0.state_versions", "permissions.0.sentinel_mocks", "permissions.0.workspace_locking"} {
for _, permission := range []string{
"permissions.0.runs",
"permissions.0.variables",
"permissions.0.state_versions",
"permissions.0.sentinel_mocks",
"permissions.0.workspace_locking",
"permissions.0.run_tasks",
} {
if !d.NewValueKnown(permission) {
return fmt.Errorf("'%q' cannot be derived from a value that is unknown during planning", permission)
}
Expand Down
78 changes: 78 additions & 0 deletions tfe/resource_tfe_team_access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,44 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccTFETeamAccess_admin(t *testing.T) {
tmAccess := &tfe.TeamAccess{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

expectedPermissions := map[string]interface{}{
"runs": tfe.RunsPermissionApply,
"variables": tfe.VariablesPermissionWrite,
"state_versions": tfe.StateVersionsPermissionWrite,
"sentinel_mocks": tfe.SentinelMocksPermissionRead,
"workspace_locking": true,
"run_tasks": true,
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFETeamAccessDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFETeamAccess_admin(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFETeamAccessExists(
"tfe_team_access.foobar", tmAccess),
testAccCheckTFETeamAccessAttributesAccessIs(tmAccess, tfe.AccessAdmin),
testAccCheckTFETeamAccessAttributesPermissionsAre(tmAccess, expectedPermissions),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "admin"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.runs", "apply"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.variables", "write"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "true"),
),
},
},
})
}

func TestAccTFETeamAccess_write(t *testing.T) {
tmAccess := &tfe.TeamAccess{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
Expand All @@ -21,6 +59,7 @@ func TestAccTFETeamAccess_write(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionWrite,
"sentinel_mocks": tfe.SentinelMocksPermissionRead,
"workspace_locking": true,
"run_tasks": false,
}

resource.Test(t, resource.TestCase{
Expand All @@ -41,6 +80,7 @@ func TestAccTFETeamAccess_write(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
},
Expand Down Expand Up @@ -70,6 +110,7 @@ func TestAccTFETeamAccess_custom(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionReadOutputs,
"sentinel_mocks": tfe.SentinelMocksPermissionNone,
"workspace_locking": false,
"run_tasks": false,
},
),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"),
Expand All @@ -78,6 +119,7 @@ func TestAccTFETeamAccess_custom(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
},
Expand Down Expand Up @@ -107,6 +149,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionWrite,
"sentinel_mocks": tfe.SentinelMocksPermissionRead,
"workspace_locking": true,
"run_tasks": false,
},
),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "write"),
Expand All @@ -115,6 +158,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "write"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "read"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "true"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
{
Expand All @@ -131,6 +175,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionReadOutputs,
"sentinel_mocks": tfe.SentinelMocksPermissionNone,
"workspace_locking": false,
"run_tasks": false,
},
),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"),
Expand All @@ -139,6 +184,7 @@ func TestAccTFETeamAccess_updateToCustom(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
},
Expand Down Expand Up @@ -168,6 +214,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionReadOutputs,
"sentinel_mocks": tfe.SentinelMocksPermissionNone,
"workspace_locking": false,
"run_tasks": false,
},
),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "custom"),
Expand All @@ -176,6 +223,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read-outputs"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
{
Expand All @@ -192,6 +240,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) {
"state_versions": tfe.StateVersionsPermissionRead,
"sentinel_mocks": tfe.SentinelMocksPermissionNone,
"workspace_locking": false,
"run_tasks": false,
},
),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "access", "plan"),
Expand All @@ -200,6 +249,7 @@ func TestAccTFETeamAccess_updateFromCustom(t *testing.T) {
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.state_versions", "read"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.sentinel_mocks", "none"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.workspace_locking", "false"),
resource.TestCheckResourceAttr("tfe_team_access.foobar", "permissions.0.run_tasks", "false"),
),
},
},
Expand Down Expand Up @@ -283,6 +333,9 @@ func testAccCheckTFETeamAccessAttributesPermissionsAre(tmAccess *tfe.TeamAccess,
if tmAccess.WorkspaceLocking != expectedPermissions["workspace_locking"].(bool) {
return fmt.Errorf("Bad workspace-locking permission: Expected %s, Received %t", expectedPermissions["workspace_locking"], tmAccess.WorkspaceLocking)
}
if tmAccess.RunTasks != expectedPermissions["run_tasks"].(bool) {
return fmt.Errorf("Bad run_tasks permission: Expected %s, Received %t", expectedPermissions["run_tasks"], tmAccess.RunTasks)
}
return nil
}
}
Expand All @@ -308,6 +361,30 @@ func testAccCheckTFETeamAccessDestroy(s *terraform.State) error {
return nil
}

func testAccTFETeamAccess_admin(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "admin@company.com"
}
resource "tfe_team" "foobar" {
name = "team-test"
organization = tfe_organization.foobar.id
}
resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}
resource "tfe_team_access" "foobar" {
access = "admin"
team_id = tfe_team.foobar.id
workspace_id = tfe_workspace.foobar.id
}`, rInt)
}

func testAccTFETeamAccess_write(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
Expand Down Expand Up @@ -380,6 +457,7 @@ resource "tfe_team_access" "foobar" {
state_versions = "read-outputs"
sentinel_mocks = "none"
workspace_locking = false
run_tasks = false
}
team_id = tfe_team.foobar.id
workspace_id = tfe_workspace.foobar.id
Expand Down
1 change: 1 addition & 0 deletions website/docs/d/team_access.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ The `permissions` block contains:
* `state_versions` - The permissions granted to state versions. Valid values are `none`, `read-outputs`, `read`, or `write`
* `sentinel_mocks` - The permissions granted to Sentinel mocks. Valid values are `none` or `read`
* `workspace_locking` - Whether permission is granted to manually lock the workspace or not.
* `run_tasks` - Whether permission is granted to manage workspace run tasks or not.
1 change: 1 addition & 0 deletions website/docs/r/team_access.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The `permissions` block supports:
* `state_versions` - (Required) The permission to grant the team on the workspace's state versions. Valid values are `none`, `read`, `read-outputs`, or `write`.
* `sentinel_mocks` - (Required) The permission to grant the team on the workspace's generated Sentinel mocks, Valid values are `none` or `read`.
* `workspace_locking` - (Required) Boolean determining whether or not to grant the team permission to manually lock/unlock the workspace.
* `run_tasks` - (Required) Whether permission is granted to manage workspace run tasks or not.

-> **Note:** At least one of `access` or `permissions` _must_ be provided, but not both. Whichever is omitted will automatically reflect the state of the other.

Expand Down

0 comments on commit 4bc5ff4

Please sign in to comment.