From 3c244dbae1e4513886bb0911fc275b680546daec Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Thu, 5 Sep 2024 22:01:31 +0200 Subject: [PATCH 1/7] add organizations ruleset resource --- modules/organization_ruleset/README.md | 59 ++++++++ modules/organization_ruleset/main.tf | 155 ++++++++++++++++++++++ modules/organization_ruleset/outputs.tf | 13 ++ modules/organization_ruleset/variables.tf | 123 +++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 modules/organization_ruleset/README.md create mode 100644 modules/organization_ruleset/main.tf create mode 100644 modules/organization_ruleset/outputs.tf create mode 100644 modules/organization_ruleset/variables.tf diff --git a/modules/organization_ruleset/README.md b/modules/organization_ruleset/README.md new file mode 100644 index 0000000..a4f8373 --- /dev/null +++ b/modules/organization_ruleset/README.md @@ -0,0 +1,59 @@ + + + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| github | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_organization_ruleset.this](https://registry.terraform.io/providers/hashicorp/github/latest/docs/resources/organization_ruleset) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| bypass_actors | The actors that can bypass the rules in this ruleset. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#bypass_actors | ```list(object({ actor_id = number actor_type = string bypass_mode = optional(string) }))``` | `[]` | no | +| conditions | Parameters for an organization ruleset condition. `ref_name` is required alongside one of `repository_name` or `repository_id`. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#conditions | ```list(object({ ref_name = list(object({ exclude = list(string) include = list(string) })) repository_id = optional(list(number), []) repository_name = optional(list(object({ exclude = list(string) include = list(string) })), []) }))``` | `[]` | no | +| enforcement | Possible values for Enforcement are `disabled`, `active`, `evaluate`. Note: `evaluate` is currently only supported for owners of type organization. | `string` | n/a | yes | +| name | The name of the ruleset. | `string` | n/a | yes | +| rules | Rules within the ruleset. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#rules | ```list(object({ # Enterprise only! Use `conditions` block for matching branches. branch_name_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! commit_author_email_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! commit_message_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! committer_email_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) creation = optional(bool) deletion = optional(bool) non_fast_forward = optional(bool) pull_request = optional(list(object({ dismiss_stale_reviews_on_push = optional(bool) require_code_owner_review = optional(bool) require_last_push_approval = optional(bool) required_approving_review_count = optional(number) required_review_thread_resolution = optional(bool) })), []) required_linear_history = optional(bool) required_signatures = optional(bool) required_status_checks = optional(list(object({ required_check = list(object({ context = string integration_id = optional(number) })) strict_required_status_checks_policy = optional(bool) })), []) required_workflows = optional(list(object({ required_workflow = list(object({ repository_id = number path = string ref = optional(string) })) })), []) tag_name_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) update = optional(bool) }))``` | n/a | yes | +| target | Possible values are `branch` and `tag`. | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| etag | n/a | +| node_id | GraphQL global node id for use with v4 API. | +| ruleset_id | GitHub ID for the ruleset. | + + +## Contributing + +Contributions are welcome and appreciated! + +Found an issue or want to request a feature? [Open an issue](TODO) + +Want to fix a bug you found or add some functionality? Fork, clone, commit, push, and PR and we'll check it out. + +If you have any issues or are waiting a long time for a PR to get merged then feel free to ping us at [hello@masterpoint.io](mailto:hello@masterpoint.io). + +## Built By + +[![Masterpoint Logo](https://i.imgur.com/RDLnuQO.png)](https://masterpoint.io) + + + diff --git a/modules/organization_ruleset/main.tf b/modules/organization_ruleset/main.tf new file mode 100644 index 0000000..6eeb05c --- /dev/null +++ b/modules/organization_ruleset/main.tf @@ -0,0 +1,155 @@ +resource "github_organization_ruleset" "this" { + name = var.name + + enforcement = var.enforcement + + dynamic "rules" { + for_each = var.rules + content { + dynamic "branch_name_pattern" { + for_each = rules.value.branch_name_pattern + + content { + operator = branch_name_pattern.value.operator + pattern = branch_name_pattern.value.pattern + name = branch_name_pattern.value.name + negate = branch_name_pattern.value.negate + } + } + + dynamic "commit_author_email_pattern" { + for_each = rules.value.commit_author_email_pattern + + content { + operator = commit_author_email_pattern.value.operator + pattern = commit_author_email_pattern.value.pattern + name = commit_author_email_pattern.value.name + negate = commit_author_email_pattern.value.negate + } + } + + dynamic "commit_message_pattern" { + for_each = rules.value.commit_message_pattern + + content { + operator = commit_message_pattern.value.operator + pattern = commit_message_pattern.value.pattern + name = commit_message_pattern.value.name + negate = commit_message_pattern.value.negate + } + } + + dynamic "committer_email_pattern" { + for_each = rules.value.committer_email_pattern + + content { + operator = committer_email_pattern.value.operator + pattern = committer_email_pattern.value.pattern + name = committer_email_pattern.value.name + negate = committer_email_pattern.value.negate + } + } + + creation = rules.value.creation + deletion = rules.value.deletion + non_fast_forward = rules.value.non_fast_forward + + dynamic "pull_request" { + for_each = rules.value.pull_request + + content { + dismiss_stale_reviews_on_push = pull_request.value.dismiss_stale_reviews_on_push + require_code_owner_review = pull_request.value.require_code_owner_review + require_last_push_approval = pull_request.value.require_last_push_approval + required_approving_review_count = pull_request.value.required_approving_review_count + required_review_thread_resolution = pull_request.value.required_review_thread_resolution + } + } + + required_linear_history = rules.value.required_linear_history + required_signatures = rules.value.required_signatures + + dynamic "required_status_checks" { + for_each = rules.value.required_status_checks + + content { + dynamic "required_check" { + for_each = required_status_checks.value.required_check + + content { + context = required_check.value.context + integration_id = required_check.value.integration_id + } + } + + strict_required_status_checks_policy = required_status_checks.value.strict_required_status_checks_policy + } + } + + dynamic "required_workflows" { + for_each = rules.value.required_workflows + + content { + dynamic "required_workflow" { + for_each = required_workflows.value.required_workflow + + content { + repository_id = required_workflow.value.repository_id + path = required_workflow.value.path + ref = required_workflow.value.ref + } + } + } + } + + dynamic "tag_name_pattern" { + for_each = rules.value.tag_name_pattern + + content { + operator = tag_name_pattern.value.operator + pattern = tag_name_pattern.value.pattern + name = tag_name_pattern.value.name + negate = tag_name_pattern.value.negate + } + } + + update = rules.value.update + } + } + + target = var.target + + dynamic "bypass_actors" { + for_each = var.bypass_actors + content { + actor_id = bypass_actors.value.actor_id + actor_type = bypass_actors.value.actor_type + bypass_mode = bypass_actors.value.bypass_mode + } + } + + dynamic "conditions" { + for_each = var.conditions + content { + dynamic "ref_name" { + for_each = conditions.value.ref_name + + content { + exclude = ref_name.value.exclude + include = ref_name.value.include + } + } + + repository_id = conditions.value.repository_id + + dynamic "repository_name" { + for_each = conditions.value.repository_name + + content { + exclude = repository_name.value.exclude + include = repository_name.value.include + } + } + } + } +} diff --git a/modules/organization_ruleset/outputs.tf b/modules/organization_ruleset/outputs.tf new file mode 100644 index 0000000..281b2ec --- /dev/null +++ b/modules/organization_ruleset/outputs.tf @@ -0,0 +1,13 @@ +output "etag" { + value = github_organization_ruleset.this[*].etag +} + +output "node_id" { + value = github_organization_ruleset.this[*].node_id + description = "GraphQL global node id for use with v4 API." +} + +output "ruleset_id" { + value = github_organization_ruleset.this[*].ruleset_id + description = "GitHub ID for the ruleset." +} diff --git a/modules/organization_ruleset/variables.tf b/modules/organization_ruleset/variables.tf new file mode 100644 index 0000000..ae7f701 --- /dev/null +++ b/modules/organization_ruleset/variables.tf @@ -0,0 +1,123 @@ +variable "enforcement" { + description = "Possible values for Enforcement are `disabled`, `active`, `evaluate`. Note: `evaluate` is currently only supported for owners of type organization." + type = string + validation { + condition = var.enforcement == "disabled" || var.enforcement == "active" || var.enforcement == "evaluate" + error_message = "Enforcement must be either 'disabled', 'active', or 'evaluate'." + } +} + +variable "name" { + description = "The name of the ruleset." + type = string +} + +variable "rules" { + description = "Rules within the ruleset. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#rules" + type = list(object({ + # Enterprise only! Use `conditions` block for matching branches. + branch_name_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + commit_author_email_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + commit_message_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + committer_email_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + creation = optional(bool) + deletion = optional(bool) + non_fast_forward = optional(bool) + pull_request = optional(list(object({ + dismiss_stale_reviews_on_push = optional(bool) + require_code_owner_review = optional(bool) + require_last_push_approval = optional(bool) + required_approving_review_count = optional(number) + required_review_thread_resolution = optional(bool) + })), []) + required_linear_history = optional(bool) + required_signatures = optional(bool) + required_status_checks = optional(list(object({ + required_check = list(object({ + context = string + integration_id = optional(number) + })) + strict_required_status_checks_policy = optional(bool) + })), []) + required_workflows = optional(list(object({ + required_workflow = list(object({ + repository_id = number + path = string + ref = optional(string) + })) + })), []) + tag_name_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + update = optional(bool) + })) + validation { + condition = length(var.rules) == 1 + error_message = "Only one rules block is allowed." + } + validation { + condition = length(var.rules[*].branch_name_pattern) <= 1 && length(var.rules[*].commit_author_email_pattern) <= 1 && length(var.rules[*].commit_message_pattern) <= 1 && length(var.rules[*].committer_email_pattern) <= 1 && length(var.rules[*].pull_request) <= 1 && length(var.rules[*].required_status_checks) <= 1 && length(var.rules[*].required_workflows) <= 1 && length(var.rules[*].tag_name_pattern) <= 1 + error_message = "commit_author_email_pattern, commit_message_pattern, committer_email_pattern, pull_request, required_status_checks, required_workflows, and tag_name_pattern can have a maximum of one block." + } +} + +variable "target" { + description = "Possible values are `branch` and `tag`." + type = string + validation { + condition = var.target == "branch" || var.target == "tag" + error_message = "Target must be either 'branch' or 'tag'." + } +} + +variable "bypass_actors" { + description = "The actors that can bypass the rules in this ruleset. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#bypass_actors" + type = list(object({ + actor_id = number + actor_type = string + bypass_mode = optional(string) + })) + default = [] +} + +variable "conditions" { + description = "Parameters for an organization ruleset condition. `ref_name` is required alongside one of `repository_name` or `repository_id`. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset#conditions" + type = list(object({ + ref_name = list(object({ + exclude = list(string) + include = list(string) + })) + repository_id = optional(list(number), []) + repository_name = optional(list(object({ + exclude = list(string) + include = list(string) + })), []) + })) + default = [] +} From c16b5066b367294660d5c6505b14252979e3bd76 Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Thu, 5 Sep 2024 22:01:48 +0200 Subject: [PATCH 2/7] add actions permissions at organization scope --- .../README.md | 60 +++++++++++++++++++ .../actions_organization_permissions/main.tf | 21 +++++++ .../outputs.tf | 3 + .../variables.tf | 52 ++++++++++++++++ .../versions.tf | 9 +++ 5 files changed, 145 insertions(+) create mode 100644 modules/actions_organization_permissions/README.md create mode 100644 modules/actions_organization_permissions/main.tf create mode 100644 modules/actions_organization_permissions/outputs.tf create mode 100644 modules/actions_organization_permissions/variables.tf create mode 100644 modules/actions_organization_permissions/versions.tf diff --git a/modules/actions_organization_permissions/README.md b/modules/actions_organization_permissions/README.md new file mode 100644 index 0000000..5d6755b --- /dev/null +++ b/modules/actions_organization_permissions/README.md @@ -0,0 +1,60 @@ +# + + + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >=1.3 | +| github | >= 6.2.3 | + +## Providers + +| Name | Version | +|------|---------| +| github | >= 6.2.3 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_actions_organization_permissions.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_permissions) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| allowed_actions | The permissions policy that controls the actions that are allowed to run. Can be one of: `all`, `local_only`, or `selected`. | `string` | `null` | no | +| allowed_actions_config | Sets the actions that are allowed in an organization. Only available when allowed_actions = selected. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_permissions#allowed-actions-config for details. { github_owned_allowed: (Required, bool) Whether GitHub-owned actions are allowed in the organization. patterns_allowed: (Optional, list(string)) Specifies a list of string-matching patterns to allow specific action(s). Wildcards, tags, and SHAs are allowed. For example, monalisa/octocat@, monalisa/octocat@v2, monalisa/." verified_allowed: (Optional, bool) Whether actions in GitHub Marketplace from verified creators are allowed. Set to true to allow all GitHub Marketplace actions by verified creators. } | ```object({ github_owned_allowed = bool patterns_allowed = optional(list(string)) verified_allowed = optional(bool) })``` | `null` | no | +| enabled_repositories | The permissions policy that controls which repositories can run actions. Can be one of: `all`, `local_only`, or `selected`. | `list(string)` | n/a | yes | +| enabled_repositories_config | Sets the list of selected repositories that are enabled for GitHub Actions in an organization. Only available when enabled_repositories = selected. See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_permissions#enabled-repositories-config for details. { repository_ids: (Required, list(string)) A list of repository IDs that are allowed to run actions. } | ```list(object({ repository_ids = list(string) }))``` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| github_actions_allowed | n/a | + + +## Contributing + +Contributions are welcome and appreciated! + +Found an issue or want to request a feature? [Open an issue](TODO) + +Want to fix a bug you found or add some functionality? Fork, clone, commit, push, and PR and we'll check it out. + +If you have any issues or are waiting a long time for a PR to get merged then feel free to ping us at [hello@masterpoint.io](mailto:hello@masterpoint.io). + +## Built By + +[![Masterpoint Logo](https://i.imgur.com/RDLnuQO.png)](https://masterpoint.io) + + + diff --git a/modules/actions_organization_permissions/main.tf b/modules/actions_organization_permissions/main.tf new file mode 100644 index 0000000..169b2ff --- /dev/null +++ b/modules/actions_organization_permissions/main.tf @@ -0,0 +1,21 @@ +resource "github_actions_organization_permissions" "this" { + allowed_actions = var.allowed_actions + + dynamic "allowed_actions_config" { + for_each = var.allowed_actions_config == null ? [] : [var.allowed_actions_config] + content { + github_owned_allowed = allowed_actions_config.value.github_owned_allowed + patterns_allowed = allowed_actions_config.value.patterns_allowed + verified_allowed = allowed_actions_config.value.verified_allowed + } + } + + enabled_repositories = var.enabled_repositories + + dynamic "enabled_repositories_config" { + for_each = var.enabled_repositories_config + content { + repository_ids = enabled_repositories_config.value.repository_ids + } + } +} diff --git a/modules/actions_organization_permissions/outputs.tf b/modules/actions_organization_permissions/outputs.tf new file mode 100644 index 0000000..f227d4c --- /dev/null +++ b/modules/actions_organization_permissions/outputs.tf @@ -0,0 +1,3 @@ +output "github_actions_allowed" { + value = github_actions_organization_permissions.this.allowed_actions_config.github_owned_allowed +} diff --git a/modules/actions_organization_permissions/variables.tf b/modules/actions_organization_permissions/variables.tf new file mode 100644 index 0000000..59a247a --- /dev/null +++ b/modules/actions_organization_permissions/variables.tf @@ -0,0 +1,52 @@ +variable "allowed_actions" { + type = string + description = "The permissions policy that controls the actions that are allowed to run. Can be one of: `all`, `local_only`, or `selected`." + validation { + condition = var.allowed_actions == "all" || var.allowed_actions == "local_only" || var.allowed_actions == "selected" + error_message = "Allowed actions must be either 'all', 'local_only', or 'selected'." + } + default = null +} + +variable "allowed_actions_config" { + type = object({ + github_owned_allowed = bool + patterns_allowed = optional(list(string)) + verified_allowed = optional(bool) + }) + description = <<-EOT + Sets the actions that are allowed in an organization. + Only available when allowed_actions = selected. + See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_permissions#allowed-actions-config for details. + { + github_owned_allowed: (Required, bool) Whether GitHub-owned actions are allowed in the organization. + patterns_allowed: (Optional, list(string)) Specifies a list of string-matching patterns to allow specific action(s). Wildcards, tags, and SHAs are allowed. For example, monalisa/octocat@, monalisa/octocat@v2, monalisa/." + verified_allowed: (Optional, bool) Whether actions in GitHub Marketplace from verified creators are allowed. Set to true to allow all GitHub Marketplace actions by verified creators. + } + EOT + default = null +} + +variable "enabled_repositories" { + type = list(string) + description = "The permissions policy that controls which repositories can run actions. Can be one of: `all`, `local_only`, or `selected`." + validation { + condition = var.enabled_repositories == "all" || var.enabled_repositories == "local_only" || var.enabled_repositories == "selected" + error_message = "Enabled repositories must be either 'all', 'local_only', or 'selected'." + } +} + +variable "enabled_repositories_config" { + type = list(object({ + repository_ids = list(string) + })) + description = <<-EOT + Sets the list of selected repositories that are enabled for GitHub Actions in an organization. + Only available when enabled_repositories = selected. + See https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_organization_permissions#enabled-repositories-config for details. + { + repository_ids: (Required, list(string)) A list of repository IDs that are allowed to run actions. + } + EOT + default = null +} diff --git a/modules/actions_organization_permissions/versions.tf b/modules/actions_organization_permissions/versions.tf new file mode 100644 index 0000000..a431a52 --- /dev/null +++ b/modules/actions_organization_permissions/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">=1.3" + required_providers { + github = { + source = "integrations/github" + version = ">= 6.2.3" + } + } +} From 2e8dd974b25a31f60c4c2caa517ad6709559727c Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Thu, 5 Sep 2024 22:02:10 +0200 Subject: [PATCH 3/7] add organization-level user blocking module/resource --- modules/organization_block/README.md | 55 +++++++++++++++++++++++++ modules/organization_block/main.tf | 3 ++ modules/organization_block/outputs.tf | 3 ++ modules/organization_block/variables.tf | 4 ++ modules/organization_block/versions.tf | 9 ++++ 5 files changed, 74 insertions(+) create mode 100644 modules/organization_block/README.md create mode 100644 modules/organization_block/main.tf create mode 100644 modules/organization_block/outputs.tf create mode 100644 modules/organization_block/variables.tf create mode 100644 modules/organization_block/versions.tf diff --git a/modules/organization_block/README.md b/modules/organization_block/README.md new file mode 100644 index 0000000..3eb038b --- /dev/null +++ b/modules/organization_block/README.md @@ -0,0 +1,55 @@ + + + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 1.3.0 | +| github | >= 6.2.3 | + +## Providers + +| Name | Version | +|------|---------| +| github | >= 6.2.3 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_organization_block.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_block) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| username | The name of the user to block. | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| blocked_user | n/a | + + +## Contributing + +Contributions are welcome and appreciated! + +Found an issue or want to request a feature? [Open an issue](TODO) + +Want to fix a bug you found or add some functionality? Fork, clone, commit, push, and PR and we'll check it out. + +If you have any issues or are waiting a long time for a PR to get merged then feel free to ping us at [hello@masterpoint.io](mailto:hello@masterpoint.io). + +## Built By + +[![Masterpoint Logo](https://i.imgur.com/RDLnuQO.png)](https://masterpoint.io) + + + diff --git a/modules/organization_block/main.tf b/modules/organization_block/main.tf new file mode 100644 index 0000000..fda5282 --- /dev/null +++ b/modules/organization_block/main.tf @@ -0,0 +1,3 @@ +resource "github_organization_block" "this" { + username = var.username +} diff --git a/modules/organization_block/outputs.tf b/modules/organization_block/outputs.tf new file mode 100644 index 0000000..f660bcc --- /dev/null +++ b/modules/organization_block/outputs.tf @@ -0,0 +1,3 @@ +output "blocked_user" { + value = github_organization_block.this.username +} diff --git a/modules/organization_block/variables.tf b/modules/organization_block/variables.tf new file mode 100644 index 0000000..e55c4c9 --- /dev/null +++ b/modules/organization_block/variables.tf @@ -0,0 +1,4 @@ +variable "username" { + type = string + description = "The name of the user to block." +} diff --git a/modules/organization_block/versions.tf b/modules/organization_block/versions.tf new file mode 100644 index 0000000..32ed349 --- /dev/null +++ b/modules/organization_block/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.3.0" + required_providers { + github = { + source = "integrations/github" + version = ">= 6.2.3" + } + } +} From 42fd89402b05697d6d43b31f923cf7dce8d99717 Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Fri, 6 Sep 2024 15:15:15 +0200 Subject: [PATCH 4/7] move actions_organization_secret[s] --- .../README.md | 2 ++ .../main.tf | 0 .../outputs.tf | 0 .../variables.tf | 0 .../versions.tf | 0 5 files changed, 2 insertions(+) rename modules/{actions_organization_secrets => actions_organization_secret}/README.md (97%) rename modules/{actions_organization_secrets => actions_organization_secret}/main.tf (100%) rename modules/{actions_organization_secrets => actions_organization_secret}/outputs.tf (100%) rename modules/{actions_organization_secrets => actions_organization_secret}/variables.tf (100%) rename modules/{actions_organization_secrets => actions_organization_secret}/versions.tf (100%) diff --git a/modules/actions_organization_secrets/README.md b/modules/actions_organization_secret/README.md similarity index 97% rename from modules/actions_organization_secrets/README.md rename to modules/actions_organization_secret/README.md index 02eb605..376e258 100644 --- a/modules/actions_organization_secrets/README.md +++ b/modules/actions_organization_secret/README.md @@ -1,3 +1,5 @@ +# github_actions_organization_secret + diff --git a/modules/actions_organization_secrets/main.tf b/modules/actions_organization_secret/main.tf similarity index 100% rename from modules/actions_organization_secrets/main.tf rename to modules/actions_organization_secret/main.tf diff --git a/modules/actions_organization_secrets/outputs.tf b/modules/actions_organization_secret/outputs.tf similarity index 100% rename from modules/actions_organization_secrets/outputs.tf rename to modules/actions_organization_secret/outputs.tf diff --git a/modules/actions_organization_secrets/variables.tf b/modules/actions_organization_secret/variables.tf similarity index 100% rename from modules/actions_organization_secrets/variables.tf rename to modules/actions_organization_secret/variables.tf diff --git a/modules/actions_organization_secrets/versions.tf b/modules/actions_organization_secret/versions.tf similarity index 100% rename from modules/actions_organization_secrets/versions.tf rename to modules/actions_organization_secret/versions.tf From 138e2d5ab7b5eb281afe85032a62fe687139b06d Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Fri, 6 Sep 2024 15:18:29 +0200 Subject: [PATCH 5/7] lint fixes --- modules/actions_organization_variable/README.md | 2 ++ modules/organization_block/README.md | 2 ++ modules/organization_ruleset/README.md | 11 ++++++++--- modules/organization_ruleset/versions.tf | 9 +++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 modules/organization_ruleset/versions.tf diff --git a/modules/actions_organization_variable/README.md b/modules/actions_organization_variable/README.md index c5b6838..30ee58e 100644 --- a/modules/actions_organization_variable/README.md +++ b/modules/actions_organization_variable/README.md @@ -1,3 +1,5 @@ +# github_actions_organization_variable + diff --git a/modules/organization_block/README.md b/modules/organization_block/README.md index 3eb038b..8c67dd2 100644 --- a/modules/organization_block/README.md +++ b/modules/organization_block/README.md @@ -1,3 +1,5 @@ +# github_organization_block + diff --git a/modules/organization_ruleset/README.md b/modules/organization_ruleset/README.md index a4f8373..7e8a4d5 100644 --- a/modules/organization_ruleset/README.md +++ b/modules/organization_ruleset/README.md @@ -1,15 +1,20 @@ +# github_organization_ruleset + ## Requirements -No requirements. +| Name | Version | +|------|---------| +| terraform | >=1.3 | +| github | >= 6.2.3 | ## Providers | Name | Version | |------|---------| -| github | n/a | +| github | >= 6.2.3 | ## Modules @@ -19,7 +24,7 @@ No modules. | Name | Type | |------|------| -| [github_organization_ruleset.this](https://registry.terraform.io/providers/hashicorp/github/latest/docs/resources/organization_ruleset) | resource | +| [github_organization_ruleset.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_ruleset) | resource | ## Inputs diff --git a/modules/organization_ruleset/versions.tf b/modules/organization_ruleset/versions.tf new file mode 100644 index 0000000..a431a52 --- /dev/null +++ b/modules/organization_ruleset/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">=1.3" + required_providers { + github = { + source = "integrations/github" + version = ">= 6.2.3" + } + } +} From 91b0d632e5b84ba4450d6277a90c9929e97c6585 Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Fri, 6 Sep 2024 15:19:22 +0200 Subject: [PATCH 6/7] update root module --- README.md | 9 +++++ main.tf | 95 ++++++++++------------------------------------------ variables.tf | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 5815750..0fe8e88 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ No providers. | Name | Source | Version | |------|--------|---------| | actions_runner_group | ./modules/actions_runner_group | n/a | +| organization_block | ./modules/organization_block | n/a | +| organization_ruleset | ./modules/organization_ruleset | n/a | +| organization_secret | ./modules/actions_organization_secret | n/a | | organization_settings | ./modules/organization_settings | n/a | +| organization_variable | ./modules/actions_organization_variable | n/a | ## Resources @@ -36,9 +40,11 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| actions_runner_groups | A map of actions runner groups to create in your GitHub organization. Map key is the name of the runner group. | ```map(object({ restricted_to_workflows = optional(list(string)) selected_repository_ids = optional(list(string)) selected_workflows = optional(list(string)) visibility = optional(string) allows_public_repositories = optional(bool) }))``` | `{}` | no | | advanced_security_enabled_for_new_repositories | Whether or not advanced security is enabled for new repositories. Defaults to false. | `bool` | `null` | no | | allows_public_repositories | Whether public repositories can be added to the runner group | `bool` | `null` | no | | billing_email | The billing email address for the organization. | `string` | n/a | yes | +| blocked_usernames | A list of usernames to block from your GitHub organization. | `list(string)` | `[]` | no | | blog | The blog URL for the organization. | `string` | `null` | no | | company | The company name for the organization. | `string` | `null` | no | | default_repository_permission | The default permission for organization members to create new repositories. Can be one of read, write, admin, or none. Defaults to read. | `string` | `null` | no | @@ -59,6 +65,9 @@ No resources. | members_can_create_repositories | Whether or not organization members can create new repositories. Defaults to true. | `bool` | `null` | no | | members_can_fork_private_repositories | Whether or not organization members can fork private repositories. Defaults to false. | `bool` | `null` | no | | organization_name | The name for the organization. | `string` | `null` | no | +| organization_rulesets | A map of organization rulesets to create. The map key is the name of the ruleset. | ```map(object({ enforcement = string rules = list(object({ # Enterprise only! Use `conditions` block for matching branches. branch_name_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! commit_author_email_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! commit_message_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) # Enterprise only! committer_email_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) creation = optional(bool) deletion = optional(bool) non_fast_forward = optional(bool) pull_request = optional(list(object({ dismiss_stale_reviews_on_push = optional(bool) require_code_owner_review = optional(bool) require_last_push_approval = optional(bool) required_approving_review_count = optional(number) required_review_thread_resolution = optional(bool) })), []) required_linear_history = optional(bool) required_signatures = optional(bool) required_status_checks = optional(list(object({ required_check = list(object({ context = string integration_id = optional(number) })) strict_required_status_checks_policy = optional(bool) })), []) required_workflows = optional(list(object({ required_workflow = list(object({ repository_id = number path = string ref = optional(string) })) })), []) tag_name_pattern = optional(list(object({ operator = string pattern = string name = optional(string) negate = optional(bool) })), []) update = optional(bool) })) target = string bypass_actors = optional(list(object({ actor_id = number actor_type = string bypass_mode = optional(string) })), []) }))``` | n/a | yes | +| organization_secrets | A map of organization secrets to create. The map key is the secret name. | ```map(object({ encrypted_value = optional(string) plaintext_value = optional(string) visibility = string selected_repository_ids = optional(list(string)) }))``` | `{}` | no | +| organization_variables | n/a | ```map(object({ value = string visibility = string selected_repository_ids = optional(list(string)) }))``` | n/a | yes | | restricted_to_workflows | If true, the runner group will be restricted to running only the workflows specified in the selected_workflows array. Defaults to false. | `bool` | `null` | no | | runner_group_name | Name of the runner group | `string` | n/a | yes | | secret_scanning_enabled_for_new_repositories | Whether or not secret scanning is enabled for new repositories. Defaults to false. | `bool` | `null` | no | diff --git a/main.tf b/main.tf index df10a2c..ea3841b 100644 --- a/main.tf +++ b/main.tf @@ -49,87 +49,18 @@ module "organization_block" { } module "organization_ruleset" { + source = "./modules/organization_ruleset" + for_each = var.organization_rulesets -} -variable "organization_rulesets" { - description = "A map of organization rulesets to create. The map key is the name of the ruleset." - type = map(object({ - enforcement = string - rules = list(object({ - # Enterprise only! Use `conditions` block for matching branches. - branch_name_pattern = optional(list(object({ - operator = string - pattern = string - name = optional(string) - negate = optional(bool) - })), []) - # Enterprise only! - commit_author_email_pattern = optional(list(object({ - operator = string - pattern = string - name = optional(string) - negate = optional(bool) - })), []) - # Enterprise only! - commit_message_pattern = optional(list(object({ - operator = string - pattern = string - name = optional(string) - negate = optional(bool) - })), []) - # Enterprise only! - committer_email_pattern = optional(list(object({ - operator = string - pattern = string - name = optional(string) - negate = optional(bool) - })), []) - creation = optional(bool) - deletion = optional(bool) - non_fast_forward = optional(bool) - pull_request = optional(list(object({ - dismiss_stale_reviews_on_push = optional(bool) - require_code_owner_review = optional(bool) - require_last_push_approval = optional(bool) - required_approving_review_count = optional(number) - required_review_thread_resolution = optional(bool) - })), []) - required_linear_history = optional(bool) - required_signatures = optional(bool) - required_status_checks = optional(list(object({ - required_check = list(object({ - context = string - integration_id = optional(number) - })) - strict_required_status_checks_policy = optional(bool) - })), []) - required_workflows = optional(list(object({ - required_workflow = list(object({ - repository_id = number - path = string - ref = optional(string) - })) - })), []) - tag_name_pattern = optional(list(object({ - operator = string - pattern = string - name = optional(string) - negate = optional(bool) - })), []) - update = optional(bool) - })) - target = string - bypass_actors = optional(list(object({ - actor_id = number - actor_type = string - bypass_mode = optional(string) - })), []) - })) + name = each.key + enforcement = each.value.enforcement + rules = each.value.rules + target = each.value.target + bypass_actors = each.value.bypass_actors } - module "organization_secret" { - source = "./modules/actions_organization_secrets" + source = "./modules/actions_organization_secret" for_each = var.organization_secrets secret_name = each.key @@ -138,3 +69,13 @@ module "organization_secret" { visibility = each.value.visibility selected_repository_ids = each.value.selected_repository_ids } + +module "organization_variable" { + source = "./modules/actions_organization_variable" + for_each = var.organization_variables + + variable_name = each.key + value = each.value.value + visibility = each.value.visibility + selected_repository_ids = each.value.selected_repository_ids +} diff --git a/variables.tf b/variables.tf index 96bea9e..202faa1 100644 --- a/variables.tf +++ b/variables.tf @@ -225,6 +225,18 @@ variable "actions_runner_groups" { default = {} } +################################## +# Organization actions variables # +################################## + +variable "organization_variables" { + type = map(object({ + value = string + visibility = string + selected_repository_ids = optional(list(string)) + })) +} + ################################ # Organization actions secrets # ################################ @@ -239,3 +251,83 @@ variable "organization_secrets" { })) default = {} } + +######################### +# Organization rulesets # +######################### + +variable "organization_rulesets" { + description = "A map of organization rulesets to create. The map key is the name of the ruleset." + type = map(object({ + enforcement = string + rules = list(object({ + # Enterprise only! Use `conditions` block for matching branches. + branch_name_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + commit_author_email_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + commit_message_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + # Enterprise only! + committer_email_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + creation = optional(bool) + deletion = optional(bool) + non_fast_forward = optional(bool) + pull_request = optional(list(object({ + dismiss_stale_reviews_on_push = optional(bool) + require_code_owner_review = optional(bool) + require_last_push_approval = optional(bool) + required_approving_review_count = optional(number) + required_review_thread_resolution = optional(bool) + })), []) + required_linear_history = optional(bool) + required_signatures = optional(bool) + required_status_checks = optional(list(object({ + required_check = list(object({ + context = string + integration_id = optional(number) + })) + strict_required_status_checks_policy = optional(bool) + })), []) + required_workflows = optional(list(object({ + required_workflow = list(object({ + repository_id = number + path = string + ref = optional(string) + })) + })), []) + tag_name_pattern = optional(list(object({ + operator = string + pattern = string + name = optional(string) + negate = optional(bool) + })), []) + update = optional(bool) + })) + target = string + bypass_actors = optional(list(object({ + actor_id = number + actor_type = string + bypass_mode = optional(string) + })), []) + })) +} From 1e21cec03f6d293ddaf11334e505cc67bca03c16 Mon Sep 17 00:00:00 2001 From: Kevin Mahoney Date: Fri, 6 Sep 2024 15:29:15 +0200 Subject: [PATCH 7/7] trigger title check