diff --git a/github/provider.go b/github/provider.go index dc1878f2e8..d9922f45e3 100644 --- a/github/provider.go +++ b/github/provider.go @@ -75,37 +75,38 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "github_actions_environment_secret": resourceGithubActionsEnvironmentSecret(), - "github_actions_organization_secret": resourceGithubActionsOrganizationSecret(), - "github_actions_secret": resourceGithubActionsSecret(), - "github_app_installation_repository": resourceGithubAppInstallationRepository(), - "github_branch": resourceGithubBranch(), - "github_branch_protection": resourceGithubBranchProtection(), - "github_branch_protection_v3": resourceGithubBranchProtectionV3(), - "github_issue_label": resourceGithubIssueLabel(), - "github_membership": resourceGithubMembership(), - "github_organization_block": resourceOrganizationBlock(), - "github_organization_project": resourceGithubOrganizationProject(), - "github_organization_webhook": resourceGithubOrganizationWebhook(), - "github_project_card": resourceGithubProjectCard(), - "github_project_column": resourceGithubProjectColumn(), - "github_repository_collaborator": resourceGithubRepositoryCollaborator(), - "github_repository_deploy_key": resourceGithubRepositoryDeployKey(), - "github_repository_environment": resourceGithubRepositoryEnvironment(), - "github_repository_file": resourceGithubRepositoryFile(), - "github_repository_milestone": resourceGithubRepositoryMilestone(), - "github_repository_project": resourceGithubRepositoryProject(), - "github_repository_pull_request": resourceGithubRepositoryPullRequest(), - "github_repository_webhook": resourceGithubRepositoryWebhook(), - "github_repository": resourceGithubRepository(), - "github_team_membership": resourceGithubTeamMembership(), - "github_team_repository": resourceGithubTeamRepository(), - "github_team_sync_group_mapping": resourceGithubTeamSyncGroupMapping(), - "github_team": resourceGithubTeam(), - "github_user_gpg_key": resourceGithubUserGpgKey(), - "github_user_invitation_accepter": resourceGithubUserInvitationAccepter(), - "github_user_ssh_key": resourceGithubUserSshKey(), - "github_branch_default": resourceGithubBranchDefault(), + "github_actions_environment_secret": resourceGithubActionsEnvironmentSecret(), + "github_actions_organization_secret": resourceGithubActionsOrganizationSecret(), + "github_actions_organization_secret_repositories": resourceGithubActionsOrganizationSecretRepositories(), + "github_actions_secret": resourceGithubActionsSecret(), + "github_app_installation_repository": resourceGithubAppInstallationRepository(), + "github_branch": resourceGithubBranch(), + "github_branch_protection": resourceGithubBranchProtection(), + "github_branch_protection_v3": resourceGithubBranchProtectionV3(), + "github_issue_label": resourceGithubIssueLabel(), + "github_membership": resourceGithubMembership(), + "github_organization_block": resourceOrganizationBlock(), + "github_organization_project": resourceGithubOrganizationProject(), + "github_organization_webhook": resourceGithubOrganizationWebhook(), + "github_project_card": resourceGithubProjectCard(), + "github_project_column": resourceGithubProjectColumn(), + "github_repository_collaborator": resourceGithubRepositoryCollaborator(), + "github_repository_deploy_key": resourceGithubRepositoryDeployKey(), + "github_repository_environment": resourceGithubRepositoryEnvironment(), + "github_repository_file": resourceGithubRepositoryFile(), + "github_repository_milestone": resourceGithubRepositoryMilestone(), + "github_repository_project": resourceGithubRepositoryProject(), + "github_repository_pull_request": resourceGithubRepositoryPullRequest(), + "github_repository_webhook": resourceGithubRepositoryWebhook(), + "github_repository": resourceGithubRepository(), + "github_team_membership": resourceGithubTeamMembership(), + "github_team_repository": resourceGithubTeamRepository(), + "github_team_sync_group_mapping": resourceGithubTeamSyncGroupMapping(), + "github_team": resourceGithubTeam(), + "github_user_gpg_key": resourceGithubUserGpgKey(), + "github_user_invitation_accepter": resourceGithubUserInvitationAccepter(), + "github_user_ssh_key": resourceGithubUserSshKey(), + "github_branch_default": resourceGithubBranchDefault(), }, DataSourcesMap: map[string]*schema.Resource{ diff --git a/github/resource_github_actions_organization_secret_repositories.go b/github/resource_github_actions_organization_secret_repositories.go new file mode 100644 index 0000000000..cbfc80bd55 --- /dev/null +++ b/github/resource_github_actions_organization_secret_repositories.go @@ -0,0 +1,120 @@ +package github + +import ( + "context" + + "github.com/google/go-github/v38/github" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceGithubActionsOrganizationSecretRepositories() *schema.Resource { + return &schema.Resource{ + Create: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate, + Read: resourceGithubActionsOrganizationSecretRepositoriesRead, + Update: resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate, + Delete: resourceGithubActionsOrganizationSecretRepositoriesDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateSecretNameFunc, + }, + "selected_repository_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + Set: schema.HashInt, + Required: true, + }, + }, + } +} + +func resourceGithubActionsOrganizationSecretRepositoriesCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + ctx := context.Background() + + err := checkOrganization(meta) + if err != nil { + return err + } + + secretName := d.Get("secret_name").(string) + selectedRepositories := d.Get("selected_repository_ids") + + selectedRepositoryIDs := []int64{} + + ids := selectedRepositories.(*schema.Set).List() + for _, id := range ids { + selectedRepositoryIDs = append(selectedRepositoryIDs, int64(id.(int))) + } + + _, err = client.Actions.SetSelectedReposForOrgSecret(ctx, owner, secretName, selectedRepositoryIDs) + if err != nil { + return err + } + + d.SetId(secretName) + return resourceGithubActionsOrganizationSecretRepositoriesRead(d, meta) +} + +func resourceGithubActionsOrganizationSecretRepositoriesRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + ctx := context.Background() + + err := checkOrganization(meta) + if err != nil { + return err + } + + selectedRepositoryIDs := []int64{} + opt := &github.ListOptions{ + PerPage: maxPerPage, + } + for { + results, resp, err := client.Actions.ListSelectedReposForOrgSecret(ctx, owner, d.Id(), opt) + if err != nil { + return err + } + + for _, repo := range results.Repositories { + selectedRepositoryIDs = append(selectedRepositoryIDs, repo.GetID()) + } + + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } + + d.Set("selected_repository_ids", selectedRepositoryIDs) + + return nil +} + +func resourceGithubActionsOrganizationSecretRepositoriesDelete(d *schema.ResourceData, meta interface{}) 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 + } + + selectedRepositoryIDs := []int64{} + _, err = client.Actions.SetSelectedReposForOrgSecret(ctx, owner, d.Id(), selectedRepositoryIDs) + if err != nil { + return err + } + + return nil +} diff --git a/github/resource_github_actions_organization_secret_repositories_test.go b/github/resource_github_actions_organization_secret_repositories_test.go new file mode 100644 index 0000000000..dcc9344189 --- /dev/null +++ b/github/resource_github_actions_organization_secret_repositories_test.go @@ -0,0 +1,79 @@ +package github + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccGithubActionsOrganizationSecretRepositories(t *testing.T) { + + const ORG_SECRET_NAME = "ORG_SECRET_NAME" + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + secret_name, exists := os.LookupEnv(ORG_SECRET_NAME) + + t.Run("set repository allowlist for a organization secret", func(t *testing.T) { + if !exists { + t.Skipf("%s environment variable is missing", ORG_SECRET_NAME) + } + + config := fmt.Sprintf(` + resource "github_repository" "test_repo_1" { + name = "tf-acc-test-%s-1" + visibility = "internal" + vulnerability_alerts = "true" + } + + resource "github_repository" "test_repo_2" { + name = "tf-acc-test-%s-2" + 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 + ] + } + `, randomID, randomID, secret_name) + + 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", + ), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + t.Skip("individual account not supported for this operation") + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + }) +} diff --git a/website/docs/r/actions_organization_secret_repositories.html.markdown b/website/docs/r/actions_organization_secret_repositories.html.markdown new file mode 100644 index 0000000000..b2d47e3dc3 --- /dev/null +++ b/website/docs/r/actions_organization_secret_repositories.html.markdown @@ -0,0 +1,41 @@ +--- +layout: "github" +page_title: "GitHub: github_actions_organization_secret_repositories" +description: |- + Manages repository allow list for an Action Secret within a GitHub organization +--- + +# github_actions_organization_secret_repositories + +This resource allows you to manage repository allow list for existing GitHub Actions secrets within your GitHub organization. +You must have write access to an organization secret to use this resource. + +This resource is only applicable when `visibility` of the existing organization secret has been set to `selected`. + +## Example Usage + +```hcl +data "github_repository" "repo" { + full_name = "my-org/repo" +} + +resource "github_actions_organization_secret_repositories" "org_secret_repos" { + secret_name = "existing_secret_name" + selected_repository_ids = [data.github_repository.repo.repo_id] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `secret_name` - (Required) Name of the existing secret +* `selected_repository_ids` - (Required) An array of repository ids that can access the organization secret. + +## Import + +This resource can be imported using an ID made up of the secret name: + +``` +$ terraform import github_actions_organization_secret_repositories.test_secret_repos test_secret_name +``` diff --git a/website/github.erb b/website/github.erb index 0ffa36b482..36b9420ecd 100644 --- a/website/github.erb +++ b/website/github.erb @@ -64,6 +64,9 @@
  • github_actions_organization_secret
  • +
  • + github_actions_organization_secret_repositories +
  • github_actions_secret