Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
87 changes: 79 additions & 8 deletions github/resource_github_actions_organization_permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (

func resourceGithubActionsOrganizationPermissions() *schema.Resource {
return &schema.Resource{
Create: resourceGithubActionsOrganizationPermissionsCreateOrUpdate,
Create: resourceGithubActionsOrganizationPermissionsCreate,
Read: resourceGithubActionsOrganizationPermissionsRead,
Update: resourceGithubActionsOrganizationPermissionsCreateOrUpdate,
Update: resourceGithubActionsOrganizationPermissionsUpdate,
Delete: resourceGithubActionsOrganizationPermissionsDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
Expand Down Expand Up @@ -137,13 +137,10 @@ func resourceGithubActionsEnabledRepositoriesObject(d *schema.ResourceData) ([]i
return enabled, nil
}

func resourceGithubActionsOrganizationPermissionsCreateOrUpdate(d *schema.ResourceData, meta any) error {
func resourceGithubActionsOrganizationPermissionsCreate(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
ctx := context.Background()
if !d.IsNewResource() {
ctx = context.WithValue(ctx, ctxId, d.Id())
}

err := checkOrganization(meta)
if err != nil {
Expand All @@ -158,8 +155,20 @@ func resourceGithubActionsOrganizationPermissionsCreateOrUpdate(d *schema.Resour
EnabledRepositories: &enabledRepositories,
}

if v, ok := d.GetOk("sha_pinning_required"); ok {
actionsPermissions.SHAPinningRequired = new(v.(bool))
// Use `GetOkExists` for `sha_pinning_required` to detect explicit
// `false` values.
//
// The `sha_pinning_required` is an Optional and Computed boolean.
//
// When a user writes `sha_pinning_required = false`,
// `GetOk` returns `(false, false)`. The second `false` argument
// means "not set", which is indistinguishable from the user omitting
// the field entirely. So the explicit false was silently ignored.
//
// `GetOkExists` returns `(false, true)`.
// The `true` value correctly indicates the user did want to set it.
if v, ok := d.GetOkExists("sha_pinning_required"); ok { //nolint:staticcheck
actionsPermissions.SHAPinningRequired = github.Ptr(v.(bool))
}

_, _, err = client.Actions.UpdateActionsPermissions(ctx,
Expand Down Expand Up @@ -201,6 +210,68 @@ func resourceGithubActionsOrganizationPermissionsCreateOrUpdate(d *schema.Resour
return resourceGithubActionsOrganizationPermissionsRead(d, meta)
}

func resourceGithubActionsOrganizationPermissionsUpdate(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
orgName := meta.(*Owner).name
ctx := context.WithValue(context.Background(), ctxId, d.Id())

err := checkOrganization(meta)
if err != nil {
return err
}

allowedActions := d.Get("allowed_actions").(string)
enabledRepositories := d.Get("enabled_repositories").(string)

actionsPermissions := github.ActionsPermissions{
AllowedActions: &allowedActions,
EnabledRepositories: &enabledRepositories,
}

// Use `HasChange` + `Get` for `sha_pinning_required` to send the
// value only when it changes.
if d.HasChange("sha_pinning_required") {
actionsPermissions.SHAPinningRequired = github.Ptr(d.Get("sha_pinning_required").(bool))
}

_, _, err = client.Actions.UpdateActionsPermissions(ctx,
orgName,
actionsPermissions)
if err != nil {
return err
}

if allowedActions == "selected" {
actionsAllowedData := resourceGithubActionsOrganizationAllowedObject(d)
if actionsAllowedData != nil {
log.Printf("[DEBUG] The allowedActions variable is set.")
_, _, err = client.Actions.UpdateActionsAllowed(ctx,
orgName,
*actionsAllowedData)
if err != nil {
return err
}
} else {
log.Printf("[DEBUG] The allowedActions variable is not set, skipping.")
}
}

if enabledRepositories == "selected" {
enabledReposData, err := resourceGithubActionsEnabledRepositoriesObject(d)
if err != nil {
return err
}
_, err = client.Actions.SetEnabledReposInOrg(ctx,
orgName,
enabledReposData)
if err != nil {
return err
}
}

return resourceGithubActionsOrganizationPermissionsRead(d, meta)
}

func resourceGithubActionsOrganizationPermissionsRead(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
ctx := context.Background()
Expand Down
43 changes: 43 additions & 0 deletions github/resource_github_actions_organization_permissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,49 @@ func TestAccGithubActionsOrganizationPermissions(t *testing.T) {
})
})

t.Run("test setting sha_pinning_required to true then updating to false", func(t *testing.T) {
enabledRepositories := "all"

configTrue := fmt.Sprintf(`
resource "github_actions_organization_permissions" "test" {
allowed_actions = "all"
enabled_repositories = "%s"
sha_pinning_required = true
}
`, enabledRepositories)

configFalse := fmt.Sprintf(`
resource "github_actions_organization_permissions" "test" {
allowed_actions = "all"
enabled_repositories = "%s"
sha_pinning_required = false
}
`, enabledRepositories)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessHasOrgs(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: configTrue,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_permissions.test", "sha_pinning_required", "true",
),
),
},
{
Config: configFalse,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_organization_permissions.test", "sha_pinning_required", "false",
),
),
},
},
})
})

t.Run("test setting of organization enabled repositories", func(t *testing.T) {
allowedActions := "all"
enabledRepositories := "selected"
Expand Down
81 changes: 72 additions & 9 deletions github/resource_github_actions_repository_permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (

func resourceGithubActionsRepositoryPermissions() *schema.Resource {
return &schema.Resource{
Create: resourceGithubActionsRepositoryPermissionsCreateOrUpdate,
Create: resourceGithubActionsRepositoryPermissionsCreate,
Read: resourceGithubActionsRepositoryPermissionsRead,
Update: resourceGithubActionsRepositoryPermissionsCreateOrUpdate,
Update: resourceGithubActionsRepositoryPermissionsUpdate,
Delete: resourceGithubActionsRepositoryPermissionsDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
Expand Down Expand Up @@ -108,15 +108,12 @@ func resourceGithubActionsRepositoryAllowedObject(d *schema.ResourceData) *githu
return allowed
}

func resourceGithubActionsRepositoryPermissionsCreateOrUpdate(d *schema.ResourceData, meta any) error {
func resourceGithubActionsRepositoryPermissionsCreate(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client

owner := meta.(*Owner).name
repoName := d.Get("repository").(string)
ctx := context.Background()
if !d.IsNewResource() {
ctx = context.WithValue(ctx, ctxId, d.Id())
}

allowedActions := d.Get("allowed_actions").(string)
enabled := d.Get("enabled").(bool)
Expand All @@ -126,13 +123,25 @@ func resourceGithubActionsRepositoryPermissionsCreateOrUpdate(d *schema.Resource
Enabled: &enabled,
}

// Only specify `allowed_actions` if actions are enabled
// Only specify `allowed_actions` if actions are enabled.
if enabled {
repoActionPermissions.AllowedActions = &allowedActions
}

if v, ok := d.GetOk("sha_pinning_required"); ok {
repoActionPermissions.SHAPinningRequired = new(v.(bool))
// Use `GetOkExists` for `sha_pinning_required` to detect explicit
// `false` values.
//
// The `sha_pinning_required` is an Optional and Computed boolean.
//
// When a user writes `sha_pinning_required = false`,
// `GetOk` returns `(false, false)`. The second `false` argument
// means "not set", which is indistinguishable from the user omitting
// the field entirely. So the explicit false was silently ignored.
//
// `GetOkExists` returns `(false, true)`.
// The `true` value correctly indicates the user did want to set it.
if v, ok := d.GetOkExists("sha_pinning_required"); ok { //nolint:staticcheck
repoActionPermissions.SHAPinningRequired = github.Ptr(v.(bool))
}

_, _, err := client.Repositories.UpdateActionsPermissions(ctx,
Expand Down Expand Up @@ -164,6 +173,60 @@ func resourceGithubActionsRepositoryPermissionsCreateOrUpdate(d *schema.Resource
return resourceGithubActionsRepositoryPermissionsRead(d, meta)
}

func resourceGithubActionsRepositoryPermissionsUpdate(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client

owner := meta.(*Owner).name
repoName := d.Get("repository").(string)
ctx := context.WithValue(context.Background(), ctxId, d.Id())

allowedActions := d.Get("allowed_actions").(string)
enabled := d.Get("enabled").(bool)
log.Printf("[DEBUG] Actions enabled: %t", enabled)

repoActionPermissions := github.ActionsPermissionsRepository{
Enabled: &enabled,
}

// Only specify `allowed_actions` if actions are enabled.
if enabled {
repoActionPermissions.AllowedActions = &allowedActions
}

// Use `HasChange` + `Get` for `sha_pinning_required` to send the
// value only when it changes.
if d.HasChange("sha_pinning_required") {
repoActionPermissions.SHAPinningRequired = github.Ptr(d.Get("sha_pinning_required").(bool))
}

_, _, err := client.Repositories.UpdateActionsPermissions(ctx,
owner,
repoName,
repoActionPermissions,
)
if err != nil {
return err
}

if allowedActions == "selected" {
actionsAllowedData := resourceGithubActionsRepositoryAllowedObject(d)
if actionsAllowedData != nil {
log.Printf("[DEBUG] The allowedActions variable is set.")
_, _, err = client.Repositories.EditActionsAllowed(ctx,
owner,
repoName,
*actionsAllowedData)
if err != nil {
return err
}
} else {
log.Printf("[DEBUG] The allowedActions variable is not set, skipping.")
}
}

return resourceGithubActionsRepositoryPermissionsRead(d, meta)
}

func resourceGithubActionsRepositoryPermissionsRead(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client

Expand Down
56 changes: 56 additions & 0 deletions github/resource_github_actions_repository_permissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,62 @@ func TestAccGithubActionsRepositoryPermissions(t *testing.T) {
})
})

t.Run("test setting sha_pinning_required to true then updating to false", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
repoName := fmt.Sprintf("%srepo-act-perms-%s", testResourcePrefix, randomID)

configTrue := fmt.Sprintf(`
resource "github_repository" "test" {
name = "%[1]s"
description = "Terraform acceptance tests %[1]s"
topics = ["terraform", "testing"]
}

resource "github_actions_repository_permissions" "test" {
allowed_actions = "all"
repository = github_repository.test.name
sha_pinning_required = true
}
`, repoName)

configFalse := fmt.Sprintf(`
resource "github_repository" "test" {
name = "%[1]s"
description = "Terraform acceptance tests %[1]s"
topics = ["terraform", "testing"]
}

resource "github_actions_repository_permissions" "test" {
allowed_actions = "all"
repository = github_repository.test.name
sha_pinning_required = false
}
`, repoName)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnauthenticated(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: configTrue,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_repository_permissions.test", "sha_pinning_required", "true",
),
),
},
{
Config: configFalse,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_actions_repository_permissions.test", "sha_pinning_required", "false",
),
),
},
},
})
})

t.Run("test disabling actions on a repository", func(t *testing.T) {
actionsEnabled := false
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
Expand Down