Skip to content

Commit dead927

Browse files
authored
Update organization security manager resource to use operations that are not deprecated (#2533)
* Change how the organization security manager resource uses the GitHub client to use non-deprecated operations * Add example for creating an organization security manager team * Update contributing documentation to correct build command
1 parent 061b2f5 commit dead927

File tree

7 files changed

+119
-22
lines changed

7 files changed

+119
-22
lines changed

CONTRIBUTING.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Setting a `processId` of 0 allows a dropdown to select the process of the provid
8181

8282
0. Add a sleep call (e.g. `time.Sleep(10 * time.Second)`) in the [`func providerConfigure(p *schema.Provider) schema.ConfigureFunc`](https://github.com/integrations/terraform-provider-github/blob/cec7e175c50bb091feecdc96ba117067c35ee351/github/provider.go#L274C1-L274C64) before the immediate `return` call. This will allow time to connect the debugger while the provider is initializing, before any critical logic happens.
8383

84-
0. Build the terraform provider with debug flags enabled and copy it to the appropriate bin folder with a command like `go build -gcflags="all=-N -l" -o ~/go/bin`.
84+
0. Build the terraform provider with debug flags enabled and copy it to the appropriate bin folder with a command like `go build -gcflags="all=-N -l" -o ~/go/bin/`.
8585

8686
0. Create or edit a `dev.tfrc` that points toward the newly-built binary, and export the `TF_CLI_CONFIG_FILE` variable to point to it. Further instructions on this process may be found in the [Building the provider](#using-a-local-version-of-the-provider) section.
8787

@@ -99,7 +99,7 @@ Manual testing should be performed on each PR opened in order to validate the pr
9999
Build the provider and specify the output directory:
100100

101101
```sh
102-
$ go build -gcflags="all=-N -l" -o ~/go/bin
102+
$ go build -gcflags="all=-N -l" -o ~/go/bin/
103103
```
104104

105105
This enables verifying your locally built provider using examples available in the `examples/` directory.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Organization Security Manager Example
2+
3+
This example demonstrates creating an organization security manager team.
4+
5+
It will:
6+
- Create a team with the specified `team_name` in the specified `owner` organization
7+
- Assign the organization security manager role to the team
8+
9+
The GitHub token must have the `admin:org` scope.
10+
11+
```console
12+
export GITHUB_OWNER=my-organization
13+
export GITHUB_TOKEN=ghp_###
14+
export GITHUB_TEAM_NAME="My Security Manager Team"
15+
```
16+
17+
```console
18+
terraform apply \
19+
-var "owner=${GITHUB_OWNER}" \
20+
-var "github_token=${GITHUB_TOKEN}" \
21+
-var "team_name=${GITHUB_TEAM_NAME}"
22+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
resource "github_team" "security_managers" {
2+
name = var.team_name
3+
description = "A team of organization security managers"
4+
}
5+
6+
resource "github_organization_security_manager" "security_managers" {
7+
team_slug = github_team.security_managers.slug
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output "github_security_managers_team" {
2+
description = "The organization security managers team"
3+
value = github_organization_security_manager.security_managers
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
provider "github" {
2+
owner = var.owner
3+
token = var.github_token
4+
}
5+
6+
terraform {
7+
required_providers {
8+
github = {
9+
source = "integrations/github"
10+
}
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
variable "github_token" {
2+
description = "GitHub access token used to configure the provider"
3+
type = string
4+
}
5+
6+
variable "owner" {
7+
description = "GitHub owner used to configure the provider"
8+
type = string
9+
}
10+
11+
variable "team_name" {
12+
description = "The name to use for the GitHub team"
13+
type = string
14+
}

github/resource_github_organization_security_manager.go

+57-20
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package github
22

33
import (
44
"context"
5+
"errors"
56
"log"
6-
"net/http"
77
"strconv"
88

99
"github.com/google/go-github/v66/github"
@@ -30,6 +30,21 @@ func resourceGithubOrganizationSecurityManager() *schema.Resource {
3030
}
3131
}
3232

33+
func getSecurityManagerRole(client *github.Client, ctx context.Context, orgName string) (*github.CustomOrgRoles, error) {
34+
roles, _, err := client.Organizations.ListRoles(ctx, orgName)
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
for _, role := range roles.CustomRepoRoles {
40+
if *role.Name == "security_manager" {
41+
return role, nil
42+
}
43+
}
44+
45+
return nil, errors.New("security manager role not found")
46+
}
47+
3348
func resourceGithubOrganizationSecurityManagerCreate(d *schema.ResourceData, meta interface{}) error {
3449
err := checkOrganization(meta)
3550
if err != nil {
@@ -44,18 +59,16 @@ func resourceGithubOrganizationSecurityManagerCreate(d *schema.ResourceData, met
4459

4560
team, _, err := client.Teams.GetTeamBySlug(ctx, orgName, teamSlug)
4661
if err != nil {
47-
log.Printf("[INFO] Team %s/%s was not found in GitHub", orgName, teamSlug)
4862
return err
4963
}
5064

51-
_, err = client.Organizations.AddSecurityManagerTeam(ctx, orgName, teamSlug)
65+
smRole, err := getSecurityManagerRole(client, ctx, orgName)
66+
if err != nil {
67+
return err
68+
}
69+
70+
_, err = client.Organizations.AssignOrgRoleToTeam(ctx, orgName, teamSlug, smRole.GetID())
5271
if err != nil {
53-
if ghErr, ok := err.(*github.ErrorResponse); ok {
54-
if ghErr.Response.StatusCode == http.StatusConflict {
55-
log.Printf("[WARN] Organization %s has reached the maximum number of security manager teams", orgName)
56-
return nil
57-
}
58-
}
5972
return err
6073
}
6174

@@ -79,28 +92,42 @@ func resourceGithubOrganizationSecurityManagerRead(d *schema.ResourceData, meta
7992
client := meta.(*Owner).v3client
8093
ctx := context.WithValue(context.Background(), ctxId, d.Id())
8194

82-
// There is no endpoint for getting a single security manager team, so get the list and filter.
83-
// There is a maximum number of security manager teams (currently 10), so this should be fine.
84-
teams, _, err := client.Organizations.ListSecurityManagerTeams(ctx, orgName)
95+
smRole, err := getSecurityManagerRole(client, ctx, orgName)
8596
if err != nil {
8697
return err
8798
}
8899

89-
var team *github.Team
90-
for _, t := range teams {
91-
if t.GetID() == teamId {
92-
team = t
100+
// There is no endpoint for getting a single security manager team, so get the list and filter.
101+
options := &github.ListOptions{PerPage: 100}
102+
var smTeam *github.Team = nil
103+
for {
104+
smTeams, resp, err := client.Organizations.ListTeamsAssignedToOrgRole(ctx, orgName, smRole.GetID(), options)
105+
if err != nil {
106+
return err
107+
}
108+
109+
for _, t := range smTeams {
110+
if t.GetID() == teamId {
111+
smTeam = t
112+
break
113+
}
114+
}
115+
116+
// Break when we've found the team or there are no more pages.
117+
if smTeam != nil || resp.NextPage == 0 {
93118
break
94119
}
120+
121+
options.Page = resp.NextPage
95122
}
96123

97-
if team == nil {
124+
if smTeam == nil {
98125
log.Printf("[WARN] Removing organization security manager team %s from state because it no longer exists in GitHub", d.Id())
99126
d.SetId("")
100127
return nil
101128
}
102129

103-
if err = d.Set("team_slug", team.GetSlug()); err != nil {
130+
if err = d.Set("team_slug", smTeam.GetSlug()); err != nil {
104131
return err
105132
}
106133

@@ -128,8 +155,13 @@ func resourceGithubOrganizationSecurityManagerUpdate(d *schema.ResourceData, met
128155
return err
129156
}
130157

158+
smRole, err := getSecurityManagerRole(client, ctx, orgName)
159+
if err != nil {
160+
return err
161+
}
162+
131163
// Adding the same team is a no-op.
132-
_, err = client.Organizations.AddSecurityManagerTeam(ctx, orgName, team.GetSlug())
164+
_, err = client.Organizations.AssignOrgRoleToTeam(ctx, orgName, team.GetSlug(), smRole.GetID())
133165
if err != nil {
134166
return err
135167
}
@@ -149,6 +181,11 @@ func resourceGithubOrganizationSecurityManagerDelete(d *schema.ResourceData, met
149181
client := meta.(*Owner).v3client
150182
ctx := context.WithValue(context.Background(), ctxId, d.Id())
151183

152-
_, err = client.Organizations.RemoveSecurityManagerTeam(ctx, orgName, teamSlug)
184+
smRole, err := getSecurityManagerRole(client, ctx, orgName)
185+
if err != nil {
186+
return err
187+
}
188+
189+
_, err = client.Organizations.RemoveOrgRoleFromTeam(ctx, orgName, teamSlug, smRole.GetID())
153190
return err
154191
}

0 commit comments

Comments
 (0)