From bd9f72911659b478bc57c6ba1f26d968b8a7fb60 Mon Sep 17 00:00:00 2001 From: Cassandra Tait Date: Tue, 2 Jun 2026 14:39:18 +1000 Subject: [PATCH] feat: Add github_actions_organization_permissions data source to provider --- .../actions_organization_permissions.md | 32 ++++ .../data-source.tf | 2 + ...github_actions_organization_permissions.go | 152 ++++++++++++++++++ ...b_actions_organization_permissions_test.go | 115 +++++++++++++ github/provider.go | 1 + .../actions_organization_permissions.md.tmpl | 29 ++++ 6 files changed, 331 insertions(+) create mode 100644 docs/data-sources/actions_organization_permissions.md create mode 100644 examples/data-sources/actions_organization_permissions/data-source.tf create mode 100644 github/data_source_github_actions_organization_permissions.go create mode 100644 github/data_source_github_actions_organization_permissions_test.go create mode 100644 templates/data-sources/actions_organization_permissions.md.tmpl diff --git a/docs/data-sources/actions_organization_permissions.md b/docs/data-sources/actions_organization_permissions.md new file mode 100644 index 0000000000..5d937e1b45 --- /dev/null +++ b/docs/data-sources/actions_organization_permissions.md @@ -0,0 +1,32 @@ +--- +page_title: "github_actions_organization_permissions (Data Source) - GitHub" +description: |- + Get GitHub Actions permissions for an organization +--- + +# github_actions_organization_permissions (Data Source) + +Use this data source to retrieve the GitHub Actions permissions for an organization, including which actions are allowed and which repositories are enabled. + +## Example Usage + +```terraform +data "github_actions_organization_permissions" "example" { +} +``` + +## Argument Reference + +No arguments are required. The organization is determined by the provider configuration. + +## Attributes Reference + +- `allowed_actions` - The permissions policy that controls the actions that are allowed to run. Can be one of: `all`, `local_only`, or `selected`. +- `enabled_repositories` - The policy that controls the repositories in the organization that are allowed to run GitHub Actions. Can be one of: `all`, `none`, or `selected`. +- `allowed_actions_config` - (Set when `allowed_actions` is `selected`) The actions that are allowed in the organization. + - `github_owned_allowed` - Whether GitHub-owned actions are allowed in the organization. + - `patterns_allowed` - Specifies a list of string-matching patterns to allow specific action(s). + - `verified_allowed` - Whether actions in GitHub Marketplace from verified creators are allowed. +- `enabled_repositories_config` - (Set when `enabled_repositories` is `selected`) The list of selected repositories enabled for GitHub Actions. + - `repository_ids` - List of repository IDs enabled for GitHub Actions. +- `sha_pinning_required` - Whether pinning to a specific SHA is required for all actions and reusable workflows in an organization. diff --git a/examples/data-sources/actions_organization_permissions/data-source.tf b/examples/data-sources/actions_organization_permissions/data-source.tf new file mode 100644 index 0000000000..dd6b324954 --- /dev/null +++ b/examples/data-sources/actions_organization_permissions/data-source.tf @@ -0,0 +1,2 @@ +data "github_actions_organization_permissions" "example" { +} diff --git a/github/data_source_github_actions_organization_permissions.go b/github/data_source_github_actions_organization_permissions.go new file mode 100644 index 0000000000..58b28d5cac --- /dev/null +++ b/github/data_source_github_actions_organization_permissions.go @@ -0,0 +1,152 @@ +package github + +import ( + "context" + + "github.com/google/go-github/v88/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceGithubActionsOrganizationPermissions() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceGithubActionsOrganizationPermissionsRead, + + Schema: map[string]*schema.Schema{ + "allowed_actions": { + Type: schema.TypeString, + Computed: true, + Description: "The permissions policy that controls the actions that are allowed to run. Can be one of: 'all', 'local_only', or 'selected'.", + }, + "enabled_repositories": { + Type: schema.TypeString, + Computed: true, + Description: "The policy that controls the repositories in the organization that are allowed to run GitHub Actions. Can be one of: 'all', 'none', or 'selected'.", + }, + "allowed_actions_config": { + Type: schema.TypeList, + Computed: true, + Description: "The actions that are allowed in the organization when 'allowed_actions' is 'selected'.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "github_owned_allowed": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether GitHub-owned actions are allowed in the organization.", + }, + "patterns_allowed": { + Type: schema.TypeSet, + Computed: true, + Description: "Specifies a list of string-matching patterns to allow specific action(s). Wildcards, tags, and SHAs are allowed.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "verified_allowed": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether actions in GitHub Marketplace from verified creators are allowed.", + }, + }, + }, + }, + "enabled_repositories_config": { + Type: schema.TypeList, + Computed: true, + Description: "The list of selected repositories that are enabled for GitHub Actions when 'enabled_repositories' is 'selected'.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repository_ids": { + Type: schema.TypeSet, + Computed: true, + Description: "List of repository IDs enabled for GitHub Actions.", + Elem: &schema.Schema{Type: schema.TypeInt}, + }, + }, + }, + }, + "sha_pinning_required": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether pinning to a specific SHA is required for all actions and reusable workflows in an organization.", + }, + }, + } +} + +func dataSourceGithubActionsOrganizationPermissionsRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + err := checkOrganization(meta) + if err != nil { + return diag.FromErr(err) + } + + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + + actionsPermissions, _, err := client.Actions.GetActionsPermissions(ctx, owner) + if err != nil { + return diag.FromErr(err) + } + + if actionsPermissions.GetAllowedActions() == "selected" { + actionsAllowed, _, err := client.Actions.GetActionsAllowed(ctx, owner) + if err != nil { + return diag.FromErr(err) + } + + if actionsAllowed != nil { + if err = d.Set("allowed_actions_config", []any{ + map[string]any{ + "github_owned_allowed": actionsAllowed.GetGithubOwnedAllowed(), + "patterns_allowed": actionsAllowed.PatternsAllowed, + "verified_allowed": actionsAllowed.GetVerifiedAllowed(), + }, + }); err != nil { + return diag.FromErr(err) + } + } + } + + if actionsPermissions.GetEnabledRepositories() == "selected" { + opts := github.ListOptions{PerPage: 10, Page: 1} + var repoList []int64 + var allRepos []*github.Repository + + for { + enabledRepos, resp, err := client.Actions.ListEnabledReposInOrg(ctx, owner, &opts) + if err != nil { + return diag.FromErr(err) + } + allRepos = append(allRepos, enabledRepos.Repositories...) + opts.Page = resp.NextPage + if resp.NextPage == 0 { + break + } + } + + for _, repo := range allRepos { + repoList = append(repoList, *repo.ID) + } + + if allRepos != nil { + if err = d.Set("enabled_repositories_config", []any{ + map[string]any{ + "repository_ids": repoList, + }, + }); err != nil { + return diag.FromErr(err) + } + } + } + + if err = d.Set("allowed_actions", actionsPermissions.GetAllowedActions()); err != nil { + return diag.FromErr(err) + } + if err = d.Set("enabled_repositories", actionsPermissions.GetEnabledRepositories()); err != nil { + return diag.FromErr(err) + } + if err = d.Set("sha_pinning_required", actionsPermissions.GetSHAPinningRequired()); err != nil { + return diag.FromErr(err) + } + + d.SetId(owner) + return nil +} diff --git a/github/data_source_github_actions_organization_permissions_test.go b/github/data_source_github_actions_organization_permissions_test.go new file mode 100644 index 0000000000..8dde950e60 --- /dev/null +++ b/github/data_source_github_actions_organization_permissions_test.go @@ -0,0 +1,115 @@ +package github + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestAccGithubActionsOrganizationPermissionsDataSource(t *testing.T) { + t.Run("reads organization permissions without error", func(t *testing.T) { + config := ` + resource "github_actions_organization_permissions" "test" { + allowed_actions = "local_only" + enabled_repositories = "all" + } + + data "github_actions_organization_permissions" "test" { + depends_on = [github_actions_organization_permissions.test] + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessHasOrgs(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("allowed_actions"), + knownvalue.StringExact("local_only"), + ), + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("enabled_repositories"), + knownvalue.StringExact("all"), + ), + }, + }, + }, + }) + }) + + t.Run("reads selected repository and action permissions", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + repoName := fmt.Sprintf("%srepo-act-org-perm-ds-%s", testResourcePrefix, randomID) + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%[1]s" + description = "Terraform acceptance tests %[1]s" + } + + resource "github_actions_organization_permissions" "test" { + allowed_actions = "selected" + enabled_repositories = "selected" + allowed_actions_config { + github_owned_allowed = true + verified_allowed = true + patterns_allowed = ["actions/cache@*", "actions/checkout@*"] + } + enabled_repositories_config { + repository_ids = [github_repository.test.repo_id] + } + } + + data "github_actions_organization_permissions" "test" { + depends_on = [github_actions_organization_permissions.test] + } + `, repoName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessHasOrgs(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("allowed_actions"), + knownvalue.StringExact("selected"), + ), + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("enabled_repositories"), + knownvalue.StringExact("selected"), + ), + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("allowed_actions_config").AtSliceIndex(0).AtMapKey("github_owned_allowed"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("allowed_actions_config").AtSliceIndex(0).AtMapKey("verified_allowed"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "data.github_actions_organization_permissions.test", + tfjsonpath.New("enabled_repositories_config").AtSliceIndex(0).AtMapKey("repository_ids"), + knownvalue.SetSizeExact(1), + ), + }, + }, + }, + }) + }) +} diff --git a/github/provider.go b/github/provider.go index b70c58c9f0..283c320ac4 100644 --- a/github/provider.go +++ b/github/provider.go @@ -224,6 +224,7 @@ func NewProvider() func() *schema.Provider { "github_actions_environment_secrets": dataSourceGithubActionsEnvironmentSecrets(), "github_actions_environment_variables": dataSourceGithubActionsEnvironmentVariables(), "github_actions_organization_oidc_subject_claim_customization_template": dataSourceGithubActionsOrganizationOIDCSubjectClaimCustomizationTemplate(), + "github_actions_organization_permissions": dataSourceGithubActionsOrganizationPermissions(), "github_actions_organization_public_key": dataSourceGithubActionsOrganizationPublicKey(), "github_actions_organization_registration_token": dataSourceGithubActionsOrganizationRegistrationToken(), "github_actions_organization_secrets": dataSourceGithubActionsOrganizationSecrets(), diff --git a/templates/data-sources/actions_organization_permissions.md.tmpl b/templates/data-sources/actions_organization_permissions.md.tmpl new file mode 100644 index 0000000000..da838656ed --- /dev/null +++ b/templates/data-sources/actions_organization_permissions.md.tmpl @@ -0,0 +1,29 @@ +--- +page_title: "{{.Name}} ({{.Type}}) - {{.RenderedProviderName}}" +description: |- + Get GitHub Actions permissions for an organization +--- + +# {{.Name}} ({{.Type}}) + +Use this data source to retrieve the GitHub Actions permissions for an organization, including which actions are allowed and which repositories are enabled. + +## Example Usage + +{{ tffile "examples/data-sources/actions_organization_permissions/data-source.tf" }} + +## Argument Reference + +No arguments are required. The organization is determined by the provider configuration. + +## Attributes Reference + +- `allowed_actions` - The permissions policy that controls the actions that are allowed to run. Can be one of: `all`, `local_only`, or `selected`. +- `enabled_repositories` - The policy that controls the repositories in the organization that are allowed to run GitHub Actions. Can be one of: `all`, `none`, or `selected`. +- `allowed_actions_config` - (Set when `allowed_actions` is `selected`) The actions that are allowed in the organization. + - `github_owned_allowed` - Whether GitHub-owned actions are allowed in the organization. + - `patterns_allowed` - Specifies a list of string-matching patterns to allow specific action(s). + - `verified_allowed` - Whether actions in GitHub Marketplace from verified creators are allowed. +- `enabled_repositories_config` - (Set when `enabled_repositories` is `selected`) The list of selected repositories enabled for GitHub Actions. + - `repository_ids` - List of repository IDs enabled for GitHub Actions. +- `sha_pinning_required` - Whether pinning to a specific SHA is required for all actions and reusable workflows in an organization.