Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b2dc91f
Move `toInt` and `toInt64` functions to `util.go`
deiga Jan 16, 2026
a5a3c30
`resource_github_emu_group_mapping`) Change `Read` to use `ListExtern…
deiga Jan 17, 2026
ac0e35f
`resource_github_emu_group_mapping`: Refactor `Create` to have less u…
deiga Jan 18, 2026
299f192
`emu_group_mapping`: Add `group_name` computed attribute
deiga Jan 18, 2026
b0d1c43
Add matching of team ID into Read
deiga Jan 25, 2026
4287744
Split Create and Update to separate functions
deiga Jan 25, 2026
bd09539
Update Importer to use new ID pattern
deiga Jan 25, 2026
a18a68e
Add Schema migration for new ID format
deiga Jan 25, 2026
1303c7f
Changes `group_id` to `ForceNew`
deiga Jan 25, 2026
9b796b6
Add skipped test while waiting for `terraform-plugin-testing`
deiga Jan 25, 2026
1685cc2
Add `CustomizeDiff` function to determine if `team_slug` change needs…
deiga Jan 25, 2026
7667c9e
Update docs
deiga Jan 25, 2026
021ca31
Use `lookupTeamID` instead of `getTeamID`
deiga Jan 27, 2026
bf2f737
Move `Create` before `Read`
deiga Jan 27, 2026
b095f13
Replace `deep` package with `go-cmp`
deiga Jan 29, 2026
ed3f783
`ListExternalGroupsForTeamBySlug` does not return a nested `Teams` sl…
deiga Jan 29, 2026
a40d8e2
Replace `go-github-mock` with `githubApiMock`
deiga Jan 29, 2026
60456ad
Remove unnecessry `matchTeamID` function
deiga Jan 30, 2026
d94aad9
Address review comments
deiga Feb 3, 2026
5f1e5aa
Rename state migartion functions
deiga Feb 3, 2026
030ceb1
Inline unnecessary function
deiga Feb 3, 2026
edd0100
Use new reusable diffing pattern
deiga Feb 3, 2026
7f04918
Address review comments
deiga Feb 3, 2026
a199b18
Refactor mockResponse builder to accept inputs
deiga Feb 4, 2026
0423017
feat: Consistent secret and variable selected repos (#3155)
stevehipwell Feb 4, 2026
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
5 changes: 4 additions & 1 deletion github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ func Provider() *schema.Provider {
"github_actions_organization_oidc_subject_claim_customization_template": resourceGithubActionsOrganizationOIDCSubjectClaimCustomizationTemplate(),
"github_actions_organization_permissions": resourceGithubActionsOrganizationPermissions(),
"github_actions_organization_secret": resourceGithubActionsOrganizationSecret(),
"github_actions_organization_variable": resourceGithubActionsOrganizationVariable(),
"github_actions_organization_secret_repositories": resourceGithubActionsOrganizationSecretRepositories(),
"github_actions_organization_secret_repository": resourceGithubActionsOrganizationSecretRepository(),
"github_actions_organization_variable": resourceGithubActionsOrganizationVariable(),
"github_actions_organization_variable_repositories": resourceGithubActionsOrganizationVariableRepositories(),
"github_actions_organization_variable_repository": resourceGithubActionsOrganizationVariableRepository(),
"github_actions_repository_access_level": resourceGithubActionsRepositoryAccessLevel(),
"github_actions_repository_oidc_subject_claim_customization_template": resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplate(),
"github_actions_repository_permissions": resourceGithubActionsRepositoryPermissions(),
Expand All @@ -161,6 +163,7 @@ func Provider() *schema.Provider {
"github_codespaces_user_secret": resourceGithubCodespacesUserSecret(),
"github_dependabot_organization_secret": resourceGithubDependabotOrganizationSecret(),
"github_dependabot_organization_secret_repositories": resourceGithubDependabotOrganizationSecretRepositories(),
"github_dependabot_organization_secret_repository": resourceGithubDependabotOrganizationSecretRepository(),
"github_dependabot_secret": resourceGithubDependabotSecret(),
"github_emu_group_mapping": resourceGithubEMUGroupMapping(),
"github_issue": resourceGithubIssue(),
Expand Down
39 changes: 21 additions & 18 deletions github/resource_github_actions_organization_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func resourceGithubActionsOrganizationSecret() *schema.Resource {
},
Optional: true,
Description: "An array of repository IDs that can access the organization secret.",
Deprecated: "This field is deprecated and will be removed in a future release. Please use the `github_actions_organization_secret_repositories` or `github_actions_organization_secret_repository` resources to manage repository access to organization secrets.",
},
"created_at": {
Type: schema.TypeString,
Expand Down Expand Up @@ -225,32 +226,34 @@ func resourceGithubActionsOrganizationSecretRead(ctx context.Context, d *schema.
return diag.FromErr(err)
}

repoIDs := []int64{}
if secret.Visibility == "selected" {
opt := &github.ListOptions{
PerPage: maxPerPage,
}
for {
results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, secretName, opt)
if err != nil {
return diag.FromErr(err)
if _, ok := d.GetOk("selected_repository_ids"); ok {
repoIDs := []int64{}
opt := &github.ListOptions{
PerPage: maxPerPage,
}

for _, repo := range results.Repositories {
repoIDs = append(repoIDs, repo.GetID())
for {
results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, secretName, opt)
if err != nil {
return diag.FromErr(err)
}

for _, repo := range results.Repositories {
repoIDs = append(repoIDs, repo.GetID())
}

if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

if resp.NextPage == 0 {
break
if err := d.Set("selected_repository_ids", repoIDs); err != nil {
return diag.FromErr(err)
}
opt.Page = resp.NextPage
}
}

if err := d.Set("selected_repository_ids", repoIDs); err != nil {
return diag.FromErr(err)
}

return nil
}

Expand Down
138 changes: 87 additions & 51 deletions github/resource_github_actions_organization_secret_repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,91 +4,91 @@ import (
"context"

"github.com/google/go-github/v82/github"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceGithubActionsOrganizationSecretRepositories() *schema.Resource {
return &schema.Resource{
Create: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate,
Read: resourceGithubActionsOrganizationSecretRepositoriesRead,
Update: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate,
Delete: resourceGithubActionsOrganizationSecretRepositoriesDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"secret_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the existing secret.",
ValidateDiagFunc: validateSecretNameFunc,
Description: "Name of the existing secret.",
},
"selected_repository_ids": {
Type: schema.TypeSet,
Set: schema.HashInt,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
Set: schema.HashInt,
Required: true,
Description: "An array of repository ids that can access the organization secret.",
},
},

CreateContext: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate,
ReadContext: resourceGithubActionsOrganizationSecretRepositoriesRead,
UpdateContext: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate,
DeleteContext: resourceGithubActionsOrganizationSecretRepositoriesDelete,
Importer: &schema.ResourceImporter{
StateContext: resourceGithubActionsOrganizationSecretRepositoriesImport,
},
}
}

func resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
owner := meta.(*Owner).name
ctx := context.Background()

err := checkOrganization(meta)
if err != nil {
return err
func resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
if err := checkOrganization(m); err != nil {
return diag.FromErr(err)
}

secretName := d.Get("secret_name").(string)
selectedRepositories := d.Get("selected_repository_ids")
meta := m.(*Owner)
client := meta.v3client
owner := meta.name

selectedRepositoryIDs := []int64{}
secretName := d.Get("secret_name").(string)
repoIDs := []int64{}

ids := selectedRepositories.(*schema.Set).List()
ids := d.Get("selected_repository_ids").(*schema.Set).List()
for _, id := range ids {
selectedRepositoryIDs = append(selectedRepositoryIDs, int64(id.(int)))
repoIDs = append(repoIDs, int64(id.(int)))
}

_, err = client.Actions.SetSelectedReposForOrgSecret(ctx, owner, secretName, selectedRepositoryIDs)
_, err := client.Actions.SetSelectedReposForOrgSecret(ctx, owner, secretName, repoIDs)
if err != nil {
return err
return diag.FromErr(err)
}

d.SetId(secretName)
return resourceGithubActionsOrganizationSecretRepositoriesRead(d, meta)
}

func resourceGithubActionsOrganizationSecretRepositoriesRead(d *schema.ResourceData, meta any) error {
client := meta.(*Owner).v3client
owner := meta.(*Owner).name
ctx := context.Background()
return nil
}

err := checkOrganization(meta)
if err != nil {
return err
func resourceGithubActionsOrganizationSecretRepositoriesRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
if err := checkOrganization(m); err != nil {
return diag.FromErr(err)
}

selectedRepositoryIDs := []int64{}
meta := m.(*Owner)
client := meta.v3client
owner := meta.name

secretName := d.Get("secret_name").(string)

repoIDs := []int64{}
opt := &github.ListOptions{
PerPage: maxPerPage,
}
for {
results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, d.Id(), opt)
results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, secretName, opt)
if err != nil {
return err
return diag.FromErr(err)
}

for _, repo := range results.Repositories {
selectedRepositoryIDs = append(selectedRepositoryIDs, repo.GetID())
repoIDs = append(repoIDs, repo.GetID())
}

if resp.NextPage == 0 {
Expand All @@ -97,28 +97,64 @@ func resourceGithubActionsOrganizationSecretRepositoriesRead(d *schema.ResourceD
opt.Page = resp.NextPage
}

if err = d.Set("selected_repository_ids", selectedRepositoryIDs); err != nil {
return err
if err := d.Set("selected_repository_ids", repoIDs); err != nil {
return diag.FromErr(err)
}

return nil
}

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

err := checkOrganization(meta)
if err != nil {
return err
func resourceGithubActionsOrganizationSecretRepositoriesDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
if err := checkOrganization(m); err != nil {
return diag.FromErr(err)
}

selectedRepositoryIDs := []int64{}
_, err = client.Actions.SetSelectedReposForOrgSecret(ctx, owner, d.Id(), selectedRepositoryIDs)
meta := m.(*Owner)
client := meta.v3client
owner := meta.name

_, err := client.Actions.SetSelectedReposForOrgSecret(ctx, owner, d.Id(), []int64{})
if err != nil {
return err
return diag.FromErr(err)
}

return nil
}

func resourceGithubActionsOrganizationSecretRepositoriesImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) {
meta := m.(*Owner)
client := meta.v3client
owner := meta.name

secretName := d.Id()

if err := d.Set("secret_name", secretName); err != nil {
return nil, err
}

repoIDs := []int64{}
opt := &github.ListOptions{
PerPage: maxPerPage,
}
for {
results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, secretName, opt)
if err != nil {
return nil, err
}

for _, repo := range results.Repositories {
repoIDs = append(repoIDs, repo.GetID())
}

if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

if err := d.Set("selected_repository_ids", repoIDs); err != nil {
return nil, err
}

return []*schema.ResourceData{d}, nil
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github

import (
"encoding/base64"
"fmt"
"testing"

Expand All @@ -9,53 +10,49 @@ import (
)

func TestAccGithubActionsOrganizationSecretRepositories(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
repoName1 := fmt.Sprintf("%srepo-act-org-secret-%s-1", testResourcePrefix, randomID)
repoName2 := fmt.Sprintf("%srepo-act-org-secret-%s-2", testResourcePrefix, randomID)

t.Run("set repository allowlist for a organization secret", func(t *testing.T) {
if len(testAccConf.testOrgSecretName) == 0 {
t.Skipf("'GH_TEST_ORG_SECRET_NAME' environment variable is missing")
}
t.Run("create", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
secretName := fmt.Sprintf("test_%s", randomID)
secretValue := base64.StdEncoding.EncodeToString([]byte("foo"))
repoName0 := fmt.Sprintf("%s%s-0", testResourcePrefix, randomID)
repoName1 := fmt.Sprintf("%s%s-1", testResourcePrefix, randomID)

config := fmt.Sprintf(`
resource "github_repository" "test_repo_1" {
name = "%s"
visibility = "internal"
vulnerability_alerts = "true"
}

resource "github_repository" "test_repo_2" {
name = "%s"
visibility = "internal"
vulnerability_alerts = "true"
}

resource "github_actions_organization_secret_repositories" "org_secret_repos" {
secret_name = "%s"
selected_repository_ids = [
github_repository.test_repo_1.repo_id,
github_repository.test_repo_2.repo_id
]
}
`, repoName1, repoName2, testAccConf.testOrgSecretName)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(
"github_actions_organization_secret_repositories.org_secret_repos", "secret_name",
),
resource.TestCheckResourceAttr(
"github_actions_organization_secret_repositories.org_secret_repos", "selected_repository_ids.#", "2",
),
)
resource "github_actions_organization_secret" "test" {
secret_name = "%s"
encrypted_value = "%s"
visibility = "selected"
}

resource "github_repository" "test_0" {
name = "%s"
visibility = "public"
}

resource "github_repository" "test_1" {
name = "%s"
visibility = "public"
}

resource "github_actions_organization_secret_repositories" "test" {
secret_name = github_actions_organization_secret.test.secret_name
selected_repository_ids = [
github_repository.test_0.repo_id,
github_repository.test_1.repo_id
]
}
`, secretName, secretValue, repoName0, repoName1)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessHasOrgs(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("github_actions_organization_secret_repositories.test", "secret_name", "github_actions_organization_secret.test", "secret_name"),
resource.TestCheckResourceAttr("github_actions_organization_secret_repositories.test", "selected_repository_ids.#", "2"),
),
},
},
})
Expand Down
Loading