Skip to content

Commit 6e45f0f

Browse files
authored
fix: do not update/create rulesets on archived repository (#2460)
* fix: do not update/create rulesets on archived repository At the moment, provider would attempt to update `github_repository_ruleset` on archived repository resulting in 403 from GitHub API. Provider should not attempt updating this attribute when repository is archived (read-only). * Align with upstream * Fix linter * Cleanup * Actually skip ruleset create/update attempt * Add tests for resource_github_repository_ruleset * fmt fmt
1 parent 891b28e commit 6e45f0f

File tree

2 files changed

+77
-2
lines changed

2 files changed

+77
-2
lines changed

github/resource_github_repository_ruleset.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,8 +604,16 @@ func resourceGithubRepositoryRulesetCreate(d *schema.ResourceData, meta any) err
604604
repoName := d.Get("repository").(string)
605605
ctx := context.Background()
606606

607+
// Check if repository is archived - cannot create rulesets on archived repos (attempts PUT on read-only resource)
608+
repo, _, err := client.Repositories.Get(ctx, owner, repoName)
609+
if err != nil {
610+
return err
611+
}
612+
if repo.GetArchived() {
613+
return fmt.Errorf("cannot create ruleset on archived repository %s/%s", owner, repoName)
614+
}
615+
607616
var ruleset *github.Ruleset
608-
var err error
609617

610618
ruleset, _, err = client.Repositories.CreateRuleset(ctx, owner, repoName, rulesetReq)
611619
if err != nil {
@@ -687,6 +695,16 @@ func resourceGithubRepositoryRulesetUpdate(d *schema.ResourceData, meta any) err
687695

688696
ctx := context.WithValue(context.Background(), ctxId, rulesetID)
689697

698+
// Check if repository is archived - skip update if it is
699+
repo, _, err := client.Repositories.Get(ctx, owner, repoName)
700+
if err != nil {
701+
return err
702+
}
703+
if repo.GetArchived() {
704+
log.Printf("[INFO] Repository %s/%s is archived, skipping ruleset update", owner, repoName)
705+
return nil
706+
}
707+
690708
var ruleset *github.Ruleset
691709
// Use UpdateRulesetNoBypassActor here instead of UpdateRuleset *if* bypass_actors has changed.
692710
// UpdateRuleset uses `omitempty` on BypassActors, causing empty arrays to be omitted from the JSON.
@@ -718,7 +736,7 @@ func resourceGithubRepositoryRulesetDelete(d *schema.ResourceData, meta any) err
718736

719737
log.Printf("[DEBUG] Deleting repository ruleset: %s/%s: %d", owner, repoName, rulesetID)
720738
_, err = client.Repositories.DeleteRuleset(ctx, owner, repoName, rulesetID)
721-
return err
739+
return handleArchivedRepoDelete(err, "repository ruleset", fmt.Sprintf("%d", rulesetID), owner, repoName)
722740
}
723741

724742
func resourceGithubRepositoryRulesetImport(d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {

github/resource_github_repository_ruleset_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package github
33
import (
44
"fmt"
55
"log"
6+
"regexp"
67
"strings"
78
"testing"
89

@@ -1085,6 +1086,62 @@ func TestGithubRepositoryRulesets(t *testing.T) {
10851086
})
10861087
}
10871088

1089+
func TestGithubRepositoryRulesetArchived(t *testing.T) {
1090+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
1091+
1092+
t.Run("skips update and delete on archived repository", func(t *testing.T) {
1093+
config := fmt.Sprintf(`
1094+
resource "github_repository" "test" {
1095+
name = "tf-acc-test-archive-%s"
1096+
auto_init = true
1097+
archived = false
1098+
}
1099+
resource "github_repository_ruleset" "test" {
1100+
name = "test"
1101+
repository = github_repository.test.name
1102+
target = "branch"
1103+
enforcement = "active"
1104+
rules { creation = true }
1105+
}
1106+
`, randomID)
1107+
1108+
resource.Test(t, resource.TestCase{
1109+
PreCheck: func() { skipUnlessMode(t, individual) },
1110+
Providers: testAccProviders,
1111+
Steps: []resource.TestStep{
1112+
{Config: config},
1113+
{Config: strings.Replace(config, "archived = false", "archived = true", 1)},
1114+
{Config: strings.Replace(strings.Replace(config, "archived = false", "archived = true", 1), `enforcement = "active"`, `enforcement = "disabled"`, 1)},
1115+
},
1116+
})
1117+
})
1118+
1119+
t.Run("prevents creating ruleset on archived repository", func(t *testing.T) {
1120+
config := fmt.Sprintf(`
1121+
resource "github_repository" "test" {
1122+
name = "tf-acc-test-archive-create-%s"
1123+
auto_init = true
1124+
archived = true
1125+
}
1126+
resource "github_repository_ruleset" "test" {
1127+
name = "test"
1128+
repository = github_repository.test.name
1129+
target = "branch"
1130+
enforcement = "active"
1131+
rules { creation = true }
1132+
}
1133+
`, randomID)
1134+
1135+
resource.Test(t, resource.TestCase{
1136+
PreCheck: func() { skipUnlessMode(t, individual) },
1137+
Providers: testAccProviders,
1138+
Steps: []resource.TestStep{
1139+
{Config: config, ExpectError: regexp.MustCompile("cannot create ruleset on archived repository")},
1140+
},
1141+
})
1142+
})
1143+
}
1144+
10881145
func importRepositoryRulesetByResourcePaths(repoLogicalName, rulesetLogicalName string) resource.ImportStateIdFunc {
10891146
// test importing using an ID of the form <repo-node-id>:<ruleset-id>
10901147
return func(s *terraform.State) (string, error) {

0 commit comments

Comments
 (0)