Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
## Enhancements
* Adds the `ProviderType` field to `AdminSAMLSetting` and `AdminSAMLSettingsUpdateOptions` to support the `provider-type` SAML setting by @skj-skj [#1303](https://github.com/hashicorp/go-tfe/pull/1303)
* Adds `AdminSCIMSetting` to support managing site-level SCIM settings by @skj-skj [#1307](https://github.com/hashicorp/go-tfe/pull/1307)
* Adds BETA support for delegating policy overrides on teams by @jbonhag [#1301](https://github.com/hashicorp/go-tfe/pull/1301)

# v1.103.0

Expand Down
9 changes: 5 additions & 4 deletions helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2425,10 +2425,11 @@ func createTeam(t *testing.T, client *Client, org *Organization) (*Team, func())
tm, err := client.Teams.Create(ctx, org.Name, TeamCreateOptions{
Name: String(randomString(t)),
OrganizationAccess: &OrganizationAccessOptions{
ManagePolicies: Bool(true),
ManagePolicyOverrides: Bool(true),
ManageProviders: Bool(true),
ManageModules: Bool(true),
ManagePolicies: Bool(true),
ManagePolicyOverrides: Bool(true),
DelegatePolicyOverrides: Bool(true),
ManageProviders: Bool(true),
ManageModules: Bool(true),
},
})
if err != nil {
Expand Down
12 changes: 8 additions & 4 deletions team.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ type Team struct {

// OrganizationAccess represents the team's permissions on its organization
type OrganizationAccess struct {
ManagePolicies bool `jsonapi:"attr,manage-policies"`
ManagePolicyOverrides bool `jsonapi:"attr,manage-policy-overrides"`
ManagePolicies bool `jsonapi:"attr,manage-policies"`
ManagePolicyOverrides bool `jsonapi:"attr,manage-policy-overrides"`
// **Note: This API is still in BETA and subject to change.**
DelegatePolicyOverrides bool `jsonapi:"attr,delegate-policy-overrides"`
ManageWorkspaces bool `jsonapi:"attr,manage-workspaces"`
ManageVCSSettings bool `jsonapi:"attr,manage-vcs-settings"`
ManageProviders bool `jsonapi:"attr,manage-providers"`
Expand Down Expand Up @@ -160,8 +162,10 @@ type TeamUpdateOptions struct {

// OrganizationAccessOptions represents the organization access options of a team.
type OrganizationAccessOptions struct {
ManagePolicies *bool `json:"manage-policies,omitempty"`
ManagePolicyOverrides *bool `json:"manage-policy-overrides,omitempty"`
ManagePolicies *bool `json:"manage-policies,omitempty"`
ManagePolicyOverrides *bool `json:"manage-policy-overrides,omitempty"`
// **Note: This API is still in BETA and subject to change.**
DelegatePolicyOverrides *bool `json:"delegate-policy-overrides,omitempty"`
ManageWorkspaces *bool `json:"manage-workspaces,omitempty"`
ManageVCSSettings *bool `json:"manage-vcs-settings,omitempty"`
ManageProviders *bool `json:"manage-providers,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions team_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ type TeamAccess struct {
SentinelMocks SentinelMocksPermissionType `jsonapi:"attr,sentinel-mocks"`
WorkspaceLocking bool `jsonapi:"attr,workspace-locking"`
RunTasks bool `jsonapi:"attr,run-tasks"`
// **Note: This API is still in BETA and subject to change.**
PolicyOverrides bool `jsonapi:"attr,policy-overrides"`

// Relations
Team *Team `jsonapi:"relation,team"`
Expand Down Expand Up @@ -133,6 +135,8 @@ type TeamAccessAddOptions struct {
SentinelMocks *SentinelMocksPermissionType `jsonapi:"attr,sentinel-mocks,omitempty"`
WorkspaceLocking *bool `jsonapi:"attr,workspace-locking,omitempty"`
RunTasks *bool `jsonapi:"attr,run-tasks,omitempty"`
// **Note: This API is still in BETA and subject to change.**
PolicyOverrides *bool `jsonapi:"attr,policy-overrides,omitempty"`

// The team to add to the workspace
Team *Team `jsonapi:"relation,team"`
Expand Down Expand Up @@ -160,6 +164,8 @@ type TeamAccessUpdateOptions struct {
SentinelMocks *SentinelMocksPermissionType `jsonapi:"attr,sentinel-mocks,omitempty"`
WorkspaceLocking *bool `jsonapi:"attr,workspace-locking,omitempty"`
RunTasks *bool `jsonapi:"attr,run-tasks,omitempty"`
// **Note: This API is still in BETA and subject to change.**
PolicyOverrides *bool `jsonapi:"attr,policy-overrides,omitempty"`
}

// List all the team accesses for a given workspace.
Expand Down
48 changes: 48 additions & 0 deletions team_access_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,51 @@ func TestTeamAccessesUpdateRunTasks(t *testing.T) {
assert.Equal(t, newAccess, ta.RunTasks)
})
}

func TestTeamAccessesAddPolicyOverrides(t *testing.T) {
skipUnlessBeta(t)
t.Parallel()

client := testClient(t)
ctx := context.Background()

orgTest, orgTestCleanup := createOrganization(t, client)
defer orgTestCleanup()

wTest, wTestCleanup := createWorkspace(t, client, orgTest)
defer wTestCleanup()

tmTest, tmTestCleanup := createTeam(t, client, orgTest)
defer tmTestCleanup()

t.Run("with valid custom options", func(t *testing.T) {
options := TeamAccessAddOptions{
Access: Access(AccessCustom),
PolicyOverrides: Bool(true),
Team: tmTest,
Workspace: wTest,
}

ta, err := client.TeamAccess.Add(ctx, options)
defer func() {
err := client.TeamAccess.Remove(ctx, ta.ID)
if err != nil {
t.Logf("error removing team access (%s): %s", ta.ID, err)
}
}()

require.NoError(t, err)

refreshed, err := client.TeamAccess.Read(ctx, ta.ID)
require.NoError(t, err)

for _, item := range []*TeamAccess{
ta,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Access, item.Access)
assert.Equal(t, true, item.PolicyOverrides)
}
})
}
62 changes: 59 additions & 3 deletions team_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,45 @@ func TestTeamsCreate(t *testing.T) {
}
})

t.Run("with beta delegate-policy-overrides", func(t *testing.T) {
skipUnlessBeta(t)

options := TeamCreateOptions{
Name: String("delegate-policy-overrides"),
OrganizationAccess: &OrganizationAccessOptions{
DelegatePolicyOverrides: Bool(true),
},
}

team, err := client.Teams.Create(ctx, orgTest.Name, options)
require.NoError(t, err)
defer func() {
err := client.Teams.Delete(ctx, team.ID)
require.NoError(t, err)
}()

refreshed, err := client.Teams.Read(ctx, team.ID)
require.NoError(t, err)

for _, item := range []*Team{
team,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, *options.Name, item.Name)
assert.Equal(t, *options.OrganizationAccess.DelegatePolicyOverrides, item.OrganizationAccess.DelegatePolicyOverrides)
}
})

t.Run("with sso-team-id", func(t *testing.T) {
options := TeamCreateOptions{
Name: String("rockettes"),
SSOTeamID: String("7dddb675-73e0-4858-a8ad-0e597064301b"),
}
team, err := client.Teams.Create(ctx, orgTest.Name, options)
require.NoError(t, err)

assert.Nil(t, err)
assert.Equal(t, *options.Name, team.Name)

assert.NotNil(t, team.SSOTeamID)
assert.Equal(t, *options.SSOTeamID, team.SSOTeamID)
})
Expand Down Expand Up @@ -174,7 +203,8 @@ func TestTeamsRead(t *testing.T) {
t.Run("when the team exists", func(t *testing.T) {
tm, err := client.Teams.Read(ctx, tmTest.ID)
require.NoError(t, err)
assert.Equal(t, tmTest, tm)
assert.Equal(t, tmTest.ID, tm.ID)
assert.Equal(t, tmTest.Name, tm.Name)

t.Run("visibility is returned", func(t *testing.T) {
assert.Equal(t, "secret", tm.Visibility)
Expand Down Expand Up @@ -278,6 +308,32 @@ func TestTeamsUpdate(t *testing.T) {
}
})

t.Run("with beta delegate policy overrides", func(t *testing.T) {
skipUnlessBeta(t)

team, err := client.Teams.Create(ctx, orgTest.Name, TeamCreateOptions{
Name: String(randomString(t)),
})
require.NoError(t, err)
defer func() {
err := client.Teams.Delete(ctx, team.ID)
require.NoError(t, err)
}()

updated, err := client.Teams.Update(ctx, team.ID, TeamUpdateOptions{
OrganizationAccess: &OrganizationAccessOptions{
DelegatePolicyOverrides: Bool(true),
},
})
require.NoError(t, err)

refreshed, err := client.Teams.Read(ctx, team.ID)
require.NoError(t, err)

assert.True(t, updated.OrganizationAccess.DelegatePolicyOverrides)
assert.True(t, refreshed.OrganizationAccess.DelegatePolicyOverrides)
})

t.Run("when the team does not exist", func(t *testing.T) {
tm, err := client.Teams.Update(ctx, "nonexisting", TeamUpdateOptions{
Name: String("foo bar"),
Expand Down
4 changes: 4 additions & 0 deletions team_project_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ type TeamProjectAccessWorkspacePermissions struct {
WorkspaceMovePermission bool `jsonapi:"attr,move"`
WorkspaceDeletePermission bool `jsonapi:"attr,delete"`
WorkspaceRunTasksPermission bool `jsonapi:"attr,run-tasks"`
// **Note: This API is still in BETA and subject to change.**
WorkspacePolicyOverridesPermission bool `jsonapi:"attr,policy-overrides"`
}

// ProjectSettingsPermissionType represents the permissiontype to a project's settings
Expand Down Expand Up @@ -167,6 +169,8 @@ type TeamProjectAccessWorkspacePermissionsOptions struct {
Move *bool `json:"move,omitempty"`
Delete *bool `json:"delete,omitempty"`
RunTasks *bool `json:"run-tasks,omitempty"`
// **Note: This API is still in BETA and subject to change.**
PolicyOverrides *bool `json:"policy-overrides,omitempty"`
}

// TeamProjectAccessListOptions represents the options for listing team project accesses
Expand Down
38 changes: 38 additions & 0 deletions team_project_access_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,44 @@ func TestTeamProjectAccessesAdd(t *testing.T) {
}
})

t.Run("with valid options for custom workspace policy overrides permission", func(t *testing.T) {
skipUnlessBeta(t)

options := TeamProjectAccessAddOptions{
Access: *ProjectAccess(TeamProjectAccessCustom),
Team: tmTest,
Project: pTest,
WorkspaceAccess: &TeamProjectAccessWorkspacePermissionsOptions{
Runs: WorkspaceRunsPermission(WorkspaceRunsPermissionApply),
PolicyOverrides: Bool(true),
},
}

tpa, err := client.TeamProjectAccess.Add(ctx, options)
t.Cleanup(func() {
err := client.TeamProjectAccess.Remove(ctx, tpa.ID)
if err != nil {
t.Logf("error removing team access (%s): %s", tpa.ID, err)
}
})

require.NoError(t, err)

// Get a refreshed view from the API.
refreshed, err := client.TeamProjectAccess.Read(ctx, tpa.ID)
require.NoError(t, err)

for _, item := range []*TeamProjectAccess{
tpa,
refreshed,
} {
assert.NotEmpty(t, item.ID)
assert.Equal(t, options.Access, item.Access)
assert.Equal(t, *options.WorkspaceAccess.Runs, item.WorkspaceAccess.WorkspaceRunsPermission)
assert.Equal(t, true, item.WorkspaceAccess.WorkspacePolicyOverridesPermission)
}
})

t.Run("when the team already has access to the project", func(t *testing.T) {
_, tpaTestCleanup := createTeamProjectAccess(t, client, tmTest, pTest, nil)
defer tpaTestCleanup()
Expand Down
Loading