From 3067dd7a2124d6b9dfa75a1a0a391faa004614b5 Mon Sep 17 00:00:00 2001 From: Leonard Sheng Sheng Lee <305414+sheeeng@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:32:14 +0100 Subject: [PATCH] fix: handle sha_pinning_required=false Replace d.GetOk() with d.HasChange() || d.IsNewResource() to properly handle boolean false values. The GetOk() method returns ok=false for zero-value booleans, causing sha_pinning_required=false to be silently ignored and never sent to the GitHub API. This fix ensures both true and false values are correctly applied, eliminating perpetual drift when disabling SHA pinning enforcement. Affects github_actions_organization_permissions and github_actions_repository_permissions resources. Fix https://github.com/integrations/terraform-provider-github/issues/3223. --- ...github_actions_organization_permissions.go | 4 +- ...b_actions_organization_permissions_test.go | 70 +++++++++++++++ ...e_github_actions_repository_permissions.go | 4 +- ...hub_actions_repository_permissions_test.go | 90 +++++++++++++++++++ 4 files changed, 164 insertions(+), 4 deletions(-) diff --git a/github/resource_github_actions_organization_permissions.go b/github/resource_github_actions_organization_permissions.go index e17d9c6a8e..9cdda7c561 100644 --- a/github/resource_github_actions_organization_permissions.go +++ b/github/resource_github_actions_organization_permissions.go @@ -158,8 +158,8 @@ func resourceGithubActionsOrganizationPermissionsCreateOrUpdate(d *schema.Resour EnabledRepositories: &enabledRepositories, } - if v, ok := d.GetOk("sha_pinning_required"); ok { - actionsPermissions.SHAPinningRequired = github.Ptr(v.(bool)) + if d.HasChange("sha_pinning_required") || d.IsNewResource() { + actionsPermissions.SHAPinningRequired = github.Ptr(d.Get("sha_pinning_required").(bool)) } _, _, err = client.Actions.UpdateActionsPermissions(ctx, diff --git a/github/resource_github_actions_organization_permissions_test.go b/github/resource_github_actions_organization_permissions_test.go index 8aa3b9516e..de95032492 100644 --- a/github/resource_github_actions_organization_permissions_test.go +++ b/github/resource_github_actions_organization_permissions_test.go @@ -104,6 +104,76 @@ func TestAccGithubActionsOrganizationPermissions(t *testing.T) { }) }) + t.Run("test setting sha_pinning_required to true", func(t *testing.T) { + enabledRepositories := "all" + + config := fmt.Sprintf(` + resource "github_actions_organization_permissions" "test" { + allowed_actions = "all" + enabled_repositories = "%s" + sha_pinning_required = true + } + `, enabledRepositories) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessHasOrgs(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_actions_organization_permissions.test", "sha_pinning_required", "true", + ), + ), + }, + }, + }) + }) + + t.Run("test setting sha_pinning_required 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 allowed actions", func(t *testing.T) { allowedActions := "selected" enabledRepositories := "all" diff --git a/github/resource_github_actions_repository_permissions.go b/github/resource_github_actions_repository_permissions.go index d5f4ef9868..a1fcf64561 100644 --- a/github/resource_github_actions_repository_permissions.go +++ b/github/resource_github_actions_repository_permissions.go @@ -131,8 +131,8 @@ func resourceGithubActionsRepositoryPermissionsCreateOrUpdate(d *schema.Resource repoActionPermissions.AllowedActions = &allowedActions } - if v, ok := d.GetOk("sha_pinning_required"); ok { - repoActionPermissions.SHAPinningRequired = github.Ptr(v.(bool)) + if d.HasChange("sha_pinning_required") || d.IsNewResource() { + repoActionPermissions.SHAPinningRequired = github.Ptr(d.Get("sha_pinning_required").(bool)) } _, _, err := client.Repositories.UpdateActionsPermissions(ctx, diff --git a/github/resource_github_actions_repository_permissions_test.go b/github/resource_github_actions_repository_permissions_test.go index a64352a57c..eb6e1f79a5 100644 --- a/github/resource_github_actions_repository_permissions_test.go +++ b/github/resource_github_actions_repository_permissions_test.go @@ -98,6 +98,96 @@ func TestAccGithubActionsRepositoryPermissions(t *testing.T) { }) }) + t.Run("test setting sha_pinning_required to true", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + repoName := fmt.Sprintf("%srepo-act-perms-%s", testResourcePrefix, randomID) + + config := 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) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_actions_repository_permissions.test", "sha_pinning_required", "true", + ), + ), + }, + }, + }) + }) + + t.Run("test setting sha_pinning_required 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 setting of repository allowed actions", func(t *testing.T) { allowedActions := "selected" githubOwnedAllowed := true