Skip to content

Commit f1b749d

Browse files
j-nixJeremy Udit
andauthored
New resource: github_actions_organization_permissions (#920)
* Issue 489: Support Actions Organization Permissions This commit adds the following new resource for modifying Actions permissions within a GitHub organization: Resource: `github_actions_organization_permissions` Optional blocks `allowed_actions_config` and `selected_actions_config` are only available when `allowed_actions` and/or `enabled_repositories` are set to `selected`, respectively. Default behaviour of the API when initializing the resource is to set `actions_allowed` and `enabled_repositories` to `all`, this behaviour is taken into account for destroy actions. * Issue 489: Add documentation for actions_organization_permissions Documentation added with examples for the new resource `github_actions_organization_permissions`. * Remove side note leftover from development * Remove unnecessary skipped tests * Add link to website page tree * Remove unnecessary conversion as per golangci-lint * Update github/resource_github_actions_organization_permissions.go Bump to latest version of github go-sdk Co-authored-by: Jeremy Udit <[email protected]> Co-authored-by: Jeremy Udit <[email protected]>
1 parent 7d686eb commit f1b749d

File tree

5 files changed

+575
-0
lines changed

5 files changed

+575
-0
lines changed

github/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func Provider() terraform.ResourceProvider {
8585
"github_actions_environment_secret": resourceGithubActionsEnvironmentSecret(),
8686
"github_actions_organization_secret": resourceGithubActionsOrganizationSecret(),
8787
"github_actions_organization_secret_repositories": resourceGithubActionsOrganizationSecretRepositories(),
88+
"github_actions_organization_permissions": resourceGithubActionsOrganizationPermissions(),
8889
"github_actions_runner_group": resourceGithubActionsRunnerGroup(),
8990
"github_actions_secret": resourceGithubActionsSecret(),
9091
"github_app_installation_repository": resourceGithubAppInstallationRepository(),
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"errors"
6+
"log"
7+
8+
"github.com/google/go-github/v39/github"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
11+
)
12+
13+
func resourceGithubActionsOrganizationPermissions() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceGithubActionsOrganizationPermissionsCreateOrUpdate,
16+
Read: resourceGithubActionsOrganizationPermissionsRead,
17+
Update: resourceGithubActionsOrganizationPermissionsCreateOrUpdate,
18+
Delete: resourceGithubActionsOrganizationPermissionsDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
23+
Schema: map[string]*schema.Schema{
24+
"allowed_actions": {
25+
Type: schema.TypeString,
26+
Optional: true,
27+
ValidateFunc: validation.StringInSlice([]string{"all", "local_only", "selected"}, false),
28+
},
29+
"enabled_repositories": {
30+
Type: schema.TypeString,
31+
Required: true,
32+
ValidateFunc: validation.StringInSlice([]string{"all", "none", "selected"}, false),
33+
},
34+
"allowed_actions_config": {
35+
Type: schema.TypeList,
36+
Optional: true,
37+
MaxItems: 1,
38+
Elem: &schema.Resource{
39+
Schema: map[string]*schema.Schema{
40+
"github_owned_allowed": {
41+
Type: schema.TypeBool,
42+
Required: true,
43+
},
44+
"patterns_allowed": {
45+
Type: schema.TypeSet,
46+
Optional: true,
47+
Elem: &schema.Schema{Type: schema.TypeString},
48+
Set: schema.HashString,
49+
},
50+
"verified_allowed": {
51+
Type: schema.TypeBool,
52+
Optional: true,
53+
},
54+
},
55+
},
56+
},
57+
"enabled_repositories_config": {
58+
Type: schema.TypeList,
59+
Optional: true,
60+
MaxItems: 1,
61+
Elem: &schema.Resource{
62+
Schema: map[string]*schema.Schema{
63+
"repository_ids": {
64+
Type: schema.TypeSet,
65+
Elem: &schema.Schema{Type: schema.TypeInt},
66+
Required: true,
67+
},
68+
},
69+
},
70+
},
71+
},
72+
}
73+
}
74+
75+
func resourceGithubActionsOrganizationAllowedObject(d *schema.ResourceData) (*github.ActionsAllowed, error) {
76+
allowed := &github.ActionsAllowed{}
77+
78+
config := d.Get("allowed_actions_config").([]interface{})
79+
if len(config) > 0 {
80+
data := config[0].(map[string]interface{})
81+
switch x := data["github_owned_allowed"].(type) {
82+
case bool:
83+
allowed.GithubOwnedAllowed = &x
84+
}
85+
86+
switch x := data["verified_allowed"].(type) {
87+
case bool:
88+
allowed.VerifiedAllowed = &x
89+
}
90+
91+
patternsAllowed := []string{}
92+
93+
switch t := data["patterns_allowed"].(type) {
94+
case *schema.Set:
95+
for _, value := range t.List() {
96+
patternsAllowed = append(patternsAllowed, value.(string))
97+
}
98+
}
99+
100+
allowed.PatternsAllowed = patternsAllowed
101+
} else {
102+
return &github.ActionsAllowed{},
103+
errors.New("The allowed_actions_config {} block must be specified if allowed_actions == 'selected'.")
104+
}
105+
106+
return allowed, nil
107+
}
108+
109+
func resourceGithubActionsEnabledRepositoriesObject(d *schema.ResourceData) ([]int64, error) {
110+
var enabled []int64
111+
112+
config := d.Get("enabled_repositories_config").([]interface{})
113+
log.Printf("[help] length of config in actopms enabled is %v", len(config))
114+
if len(config) > 0 {
115+
data := config[0].(map[string]interface{})
116+
switch x := data["repository_ids"].(type) {
117+
case *schema.Set:
118+
for _, value := range x.List() {
119+
enabled = append(enabled, int64(value.(int)))
120+
}
121+
}
122+
} else {
123+
return nil, errors.New("The enabled_repositories_config {} block must be specified if enabled_repositories == 'selected'.")
124+
}
125+
return enabled, nil
126+
}
127+
128+
func resourceGithubActionsOrganizationPermissionsCreateOrUpdate(d *schema.ResourceData, meta interface{}) error {
129+
client := meta.(*Owner).v3client
130+
orgName := meta.(*Owner).name
131+
ctx := context.Background()
132+
if !d.IsNewResource() {
133+
ctx = context.WithValue(ctx, ctxId, d.Id())
134+
}
135+
136+
err := checkOrganization(meta)
137+
if err != nil {
138+
return err
139+
}
140+
141+
allowedActions := d.Get("allowed_actions").(string)
142+
enabledRepositories := d.Get("enabled_repositories").(string)
143+
144+
_, _, err = client.Organizations.EditActionsPermissions(ctx,
145+
orgName,
146+
github.ActionsPermissions{
147+
AllowedActions: &allowedActions,
148+
EnabledRepositories: &enabledRepositories,
149+
})
150+
if err != nil {
151+
return err
152+
}
153+
154+
if allowedActions == "selected" {
155+
actionsAllowedData, err := resourceGithubActionsOrganizationAllowedObject(d)
156+
if err != nil {
157+
return err
158+
}
159+
_, _, err = client.Organizations.EditActionsAllowed(ctx,
160+
orgName,
161+
*actionsAllowedData)
162+
if err != nil {
163+
return err
164+
}
165+
}
166+
167+
if enabledRepositories == "selected" {
168+
enabledReposData, err := resourceGithubActionsEnabledRepositoriesObject(d)
169+
if err != nil {
170+
return err
171+
}
172+
_, err = client.Actions.SetEnabledReposInOrg(ctx,
173+
orgName,
174+
enabledReposData)
175+
if err != nil {
176+
return err
177+
}
178+
}
179+
180+
d.SetId(orgName)
181+
return resourceGithubActionsOrganizationPermissionsRead(d, meta)
182+
}
183+
184+
func resourceGithubActionsOrganizationPermissionsRead(d *schema.ResourceData, meta interface{}) error {
185+
client := meta.(*Owner).v3client
186+
ctx := context.Background()
187+
188+
err := checkOrganization(meta)
189+
if err != nil {
190+
return err
191+
}
192+
193+
actionsPermissions, _, err := client.Organizations.GetActionsPermissions(ctx, d.Id())
194+
if err != nil {
195+
return err
196+
}
197+
198+
if actionsPermissions.GetAllowedActions() == "selected" {
199+
actionsAllowed, _, err := client.Organizations.GetActionsAllowed(ctx, d.Id())
200+
if err != nil {
201+
return err
202+
}
203+
204+
// If actionsAllowed set to local/all by removing all actions config settings, the response will be empty
205+
if actionsAllowed != nil {
206+
d.Set("allowed_actions_config", []interface{}{
207+
map[string]interface{}{
208+
"github_owned_allowed": actionsAllowed.GetGithubOwnedAllowed(),
209+
"patterns_allowed": actionsAllowed.PatternsAllowed,
210+
"verified_allowed": actionsAllowed.GetVerifiedAllowed(),
211+
},
212+
})
213+
}
214+
} else {
215+
d.Set("allowed_actions_config", []interface{}{})
216+
}
217+
218+
if actionsPermissions.GetEnabledRepositories() == "selected" {
219+
opts := github.ListOptions{PerPage: 10, Page: 1}
220+
var repoList []int64
221+
var allRepos []*github.Repository
222+
223+
for {
224+
enabledRepos, resp, err := client.Actions.ListEnabledReposInOrg(ctx, d.Id(), &opts)
225+
if err != nil {
226+
return err
227+
}
228+
allRepos = append(allRepos, enabledRepos.Repositories...)
229+
230+
opts.Page = resp.NextPage
231+
232+
if resp.NextPage == 0 {
233+
break
234+
}
235+
}
236+
for index := range allRepos {
237+
repoList = append(repoList, *allRepos[index].ID)
238+
}
239+
if allRepos != nil {
240+
d.Set("enabled_repositories_config", []interface{}{
241+
map[string]interface{}{
242+
"repository_ids": repoList,
243+
},
244+
})
245+
} else {
246+
d.Set("enabled_repositories_config", []interface{}{})
247+
}
248+
}
249+
250+
d.Set("allowed_actions", actionsPermissions.GetAllowedActions())
251+
d.Set("enabled_repositories", actionsPermissions.GetEnabledRepositories())
252+
253+
return nil
254+
}
255+
256+
func resourceGithubActionsOrganizationPermissionsDelete(d *schema.ResourceData, meta interface{}) error {
257+
client := meta.(*Owner).v3client
258+
orgName := meta.(*Owner).name
259+
ctx := context.WithValue(context.Background(), ctxId, d.Id())
260+
261+
err := checkOrganization(meta)
262+
if err != nil {
263+
return err
264+
}
265+
266+
// This will nullify any allowedActions elements
267+
_, _, err = client.Organizations.EditActionsPermissions(ctx,
268+
orgName,
269+
github.ActionsPermissions{
270+
AllowedActions: github.String("all"),
271+
EnabledRepositories: github.String("all"),
272+
})
273+
if err != nil {
274+
return err
275+
}
276+
277+
return nil
278+
}

0 commit comments

Comments
 (0)