diff --git a/modules/github-org-settings/.terraform-docs.yml b/modules/github-org-settings/.terraform-docs.yml new file mode 100644 index 000000000..49be8b854 --- /dev/null +++ b/modules/github-org-settings/.terraform-docs.yml @@ -0,0 +1,48 @@ +formatter: "markdown" # this is required + +version: "" + +header-from: docs/header.md +footer-from: docs/footer.md + +recursive: + enabled: false + path: modules + include-main: true + +sections: + hide: [] + show: [] + +content: "" + +output: + file: "README.md" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/modules/github-org-settings/README.md b/modules/github-org-settings/README.md new file mode 100644 index 000000000..f462c0b47 --- /dev/null +++ b/modules/github-org-settings/README.md @@ -0,0 +1,137 @@ + +# **GitHub Organization Settings Terraform Module** + +## Overview + +This module creates and manages the basic settings of a GitHub organization using the `github_organization_settings` Terraform resource. It is designed to be consumed by Firestartr `gh_provisioner` through a single strongly typed `config` object generated as `terraform.tfvars.json`. + +The module centralizes organization profile fields, repository creation policies, project settings, member permissions, and default security settings for new repositories. It intentionally manages one organization settings resource so it maps cleanly to one Firestartr custom resource and one Terraform state. + +This module does not create or delete a GitHub organization. It only updates settings for the organization configured in the GitHub provider. + +## Key Features + +- **gh-provisioner compatible**: Accepts one top-level `config` object suitable for generated `terraform.tfvars.json`. +- **Basic organization settings**: Manages billing email, company, blog, public email, location, display name, and description. +- **Repository creation policy**: Controls default repository permission and which repository types members can create. +- **Page and fork controls**: Manages Pages creation and private repository fork permissions. +- **Security defaults**: Configures Advanced Security, Dependabot, dependency graph, secret scanning, and push protection defaults for new repositories. + +## Firestartr Compatibility + +Expected generated input: + +```json +{ + "config": { + "billingEmail": "platform@example.com", + "defaultRepositoryPermission": "read", + "membersCanCreateRepositories": true + } +} +``` + +The matching `gh_provisioner` entity should map the Firestartr CR spec to this `config` shape and use the Terraform address `github_organization_settings.this` for imports. + +## Basic Usage + +### Using `terraform.tfvars.json` (recommended for Firestartr) + +```hcl +module "org_settings" { + source = "git::https://github.com/prefapp/tfm.git//modules/github-org-settings" + + config = var.config +} +``` + +### Inline example + +```hcl +module "org_settings" { + source = "git::https://github.com/prefapp/tfm.git//modules/github-org-settings" + + config = { + billingEmail = "platform@example.com" + name = "Example Organization" + description = "Managed by Firestartr" + defaultRepositoryPermission = "read" + membersCanCreateRepositories = true + membersCanCreatePublicRepositories = false + membersCanCreatePrivateRepositories = true + dependencyGraphEnabledForNewRepositories = true + secretScanningEnabledForNewRepositories = true + } +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.5 | +| [github](#requirement\_github) | ~> 6.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | ~> 6.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_organization_settings.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_settings) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [config](#input\_config) | GitHub organization settings configuration |
object({
billingEmail = string
company = optional(string)
blog = optional(string)
email = optional(string)
twitterUsername = optional(string)
location = optional(string)
name = optional(string)
description = optional(string)
hasOrganizationProjects = optional(bool, true)
hasRepositoryProjects = optional(bool, true)
defaultRepositoryPermission = optional(string, "read")
membersCanCreateRepositories = optional(bool, true)
membersCanCreatePublicRepositories = optional(bool, true)
membersCanCreatePrivateRepositories = optional(bool, true)
membersCanCreateInternalRepositories = optional(bool)
membersCanCreatePages = optional(bool, true)
membersCanCreatePublicPages = optional(bool, true)
membersCanCreatePrivatePages = optional(bool, true)
membersCanForkPrivateRepositories = optional(bool, false)
webCommitSignoffRequired = optional(bool, false)
advancedSecurityEnabledForNewRepositories = optional(bool, false)
dependabotAlertsEnabledForNewRepositories = optional(bool, false)
dependabotSecurityUpdatesEnabledForNewRepositories = optional(bool, false)
dependencyGraphEnabledForNewRepositories = optional(bool, false)
secretScanningEnabledForNewRepositories = optional(bool, false)
secretScanningPushProtectionEnabledForNewRepositories = optional(bool, false)
}) | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [advanced\_security\_enabled\_for\_new\_repositories](#output\_advanced\_security\_enabled\_for\_new\_repositories) | Whether GitHub Advanced Security is enabled for new repositories. |
+| [billing\_email](#output\_billing\_email) | Billing email configured for the organization. |
+| [default\_repository\_permission](#output\_default\_repository\_permission) | Default repository permission configured for organization members. |
+| [members\_can\_create\_repositories](#output\_members\_can\_create\_repositories) | Whether members can create repositories in the organization. |
+| [organization\_settings\_id](#output\_organization\_settings\_id) | GitHub organization ID used by github\_organization\_settings. |
+
+## Examples
+
+For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-org-settings/_examples):
+
+- [basic](https://github.com/prefapp/tfm/tree/main/modules/github-org-settings/_examples/basic) - Minimal organization settings managed through a `config.json` file.
+
+## Import Behavior
+
+This module manages one Terraform resource:
+
+- Terraform address: `github_organization_settings.this`
+- Import ID: GitHub organization numeric ID
+
+The organization ID can be discovered with the GitHub REST API `GET /orgs/{org}`. Firestartr `gh_provisioner` should import using that numeric ID when adopting existing organization settings.
+
+## Delete Behavior
+
+`github_organization_settings` does not delete the GitHub organization. Terraform provider delete semantics reset organization settings to provider defaults. This is unsafe for normal Firestartr deletion because deleting the CR could unexpectedly mutate organization-wide settings.
+
+Firestartr integrations should treat deletion of the corresponding CR as non-destructive unmanagement, for example by removing Terraform state only instead of running `terraform destroy`.
+
+## Resources
+
+- **github\_organization\_settings**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_settings)
+- **GitHub REST API - Get an organization**: [Official Documentation](https://docs.github.com/en/rest/orgs/orgs#get-an-organization)
+- **GitHub Terraform Provider**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs)
+
+## Support
+
+For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues).
+
diff --git a/modules/github-org-settings/_examples/basic/config.json b/modules/github-org-settings/_examples/basic/config.json
new file mode 100644
index 000000000..ee2d6bead
--- /dev/null
+++ b/modules/github-org-settings/_examples/basic/config.json
@@ -0,0 +1,28 @@
+{
+ "config": {
+ "billingEmail": "platform@example.com",
+ "company": "Example Company",
+ "blog": "https://example.com",
+ "email": "opensource@example.com",
+ "location": "Remote",
+ "name": "Example Organization",
+ "description": "Managed by Firestartr",
+ "hasOrganizationProjects": true,
+ "hasRepositoryProjects": true,
+ "defaultRepositoryPermission": "read",
+ "membersCanCreateRepositories": true,
+ "membersCanCreatePublicRepositories": false,
+ "membersCanCreatePrivateRepositories": true,
+ "membersCanCreatePages": true,
+ "membersCanCreatePublicPages": true,
+ "membersCanCreatePrivatePages": true,
+ "membersCanForkPrivateRepositories": false,
+ "webCommitSignoffRequired": false,
+ "advancedSecurityEnabledForNewRepositories": false,
+ "dependabotAlertsEnabledForNewRepositories": true,
+ "dependabotSecurityUpdatesEnabledForNewRepositories": true,
+ "dependencyGraphEnabledForNewRepositories": true,
+ "secretScanningEnabledForNewRepositories": true,
+ "secretScanningPushProtectionEnabledForNewRepositories": true
+ }
+}
diff --git a/modules/github-org-settings/_examples/basic/main.tf b/modules/github-org-settings/_examples/basic/main.tf
new file mode 100644
index 000000000..25c4b91fa
--- /dev/null
+++ b/modules/github-org-settings/_examples/basic/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_version = ">= 1.5"
+
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}
+
+module "org_settings" {
+ source = "../../"
+
+ config = jsondecode(file("${path.module}/config.json")).config
+}
+
+output "organization_settings_id" {
+ value = module.org_settings.organization_settings_id
+}
diff --git a/modules/github-org-settings/docs/footer.md b/modules/github-org-settings/docs/footer.md
new file mode 100644
index 000000000..bb5634e70
--- /dev/null
+++ b/modules/github-org-settings/docs/footer.md
@@ -0,0 +1,30 @@
+## Examples
+
+For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-org-settings/_examples):
+
+- [basic](https://github.com/prefapp/tfm/tree/main/modules/github-org-settings/_examples/basic) - Minimal organization settings managed through a `config.json` file.
+
+## Import Behavior
+
+This module manages one Terraform resource:
+
+- Terraform address: `github_organization_settings.this`
+- Import ID: GitHub organization numeric ID
+
+The organization ID can be discovered with the GitHub REST API `GET /orgs/{org}`. Firestartr `gh_provisioner` should import using that numeric ID when adopting existing organization settings.
+
+## Delete Behavior
+
+`github_organization_settings` does not delete the GitHub organization. Terraform provider delete semantics reset organization settings to provider defaults. This is unsafe for normal Firestartr deletion because deleting the CR could unexpectedly mutate organization-wide settings.
+
+Firestartr integrations should treat deletion of the corresponding CR as non-destructive unmanagement, for example by removing Terraform state only instead of running `terraform destroy`.
+
+## Resources
+
+- **github_organization_settings**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/organization_settings)
+- **GitHub REST API - Get an organization**: [Official Documentation](https://docs.github.com/en/rest/orgs/orgs#get-an-organization)
+- **GitHub Terraform Provider**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs)
+
+## Support
+
+For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues).
diff --git a/modules/github-org-settings/docs/header.md b/modules/github-org-settings/docs/header.md
new file mode 100644
index 000000000..037bf1454
--- /dev/null
+++ b/modules/github-org-settings/docs/header.md
@@ -0,0 +1,65 @@
+# **GitHub Organization Settings Terraform Module**
+
+## Overview
+
+This module creates and manages the basic settings of a GitHub organization using the `github_organization_settings` Terraform resource. It is designed to be consumed by Firestartr `gh_provisioner` through a single strongly typed `config` object generated as `terraform.tfvars.json`.
+
+The module centralizes organization profile fields, repository creation policies, project settings, member permissions, and default security settings for new repositories. It intentionally manages one organization settings resource so it maps cleanly to one Firestartr custom resource and one Terraform state.
+
+This module does not create or delete a GitHub organization. It only updates settings for the organization configured in the GitHub provider.
+
+## Key Features
+
+- **gh-provisioner compatible**: Accepts one top-level `config` object suitable for generated `terraform.tfvars.json`.
+- **Basic organization settings**: Manages billing email, company, blog, public email, location, display name, and description.
+- **Repository creation policy**: Controls default repository permission and which repository types members can create.
+- **Page and fork controls**: Manages Pages creation and private repository fork permissions.
+- **Security defaults**: Configures Advanced Security, Dependabot, dependency graph, secret scanning, and push protection defaults for new repositories.
+
+## Firestartr Compatibility
+
+Expected generated input:
+
+```json
+{
+ "config": {
+ "billingEmail": "platform@example.com",
+ "defaultRepositoryPermission": "read",
+ "membersCanCreateRepositories": true
+ }
+}
+```
+
+The matching `gh_provisioner` entity should map the Firestartr CR spec to this `config` shape and use the Terraform address `github_organization_settings.this` for imports.
+
+## Basic Usage
+
+### Using `terraform.tfvars.json` (recommended for Firestartr)
+
+```hcl
+module "org_settings" {
+ source = "git::https://github.com/prefapp/tfm.git//modules/github-org-settings"
+
+ config = var.config
+}
+```
+
+### Inline example
+
+```hcl
+module "org_settings" {
+ source = "git::https://github.com/prefapp/tfm.git//modules/github-org-settings"
+
+ config = {
+ billingEmail = "platform@example.com"
+ name = "Example Organization"
+ description = "Managed by Firestartr"
+ defaultRepositoryPermission = "read"
+ membersCanCreateRepositories = true
+ membersCanCreatePublicRepositories = false
+ membersCanCreatePrivateRepositories = true
+ dependencyGraphEnabledForNewRepositories = true
+ secretScanningEnabledForNewRepositories = true
+ }
+}
+```
diff --git a/modules/github-org-settings/main.tf b/modules/github-org-settings/main.tf
new file mode 100644
index 000000000..9200ed1b7
--- /dev/null
+++ b/modules/github-org-settings/main.tf
@@ -0,0 +1,31 @@
+resource "github_organization_settings" "this" {
+ billing_email = var.config.billingEmail
+ company = var.config.company
+ blog = var.config.blog
+ email = var.config.email
+ twitter_username = var.config.twitterUsername
+ location = var.config.location
+ name = var.config.name
+ description = var.config.description
+
+ has_organization_projects = var.config.hasOrganizationProjects
+ has_repository_projects = var.config.hasRepositoryProjects
+ default_repository_permission = var.config.defaultRepositoryPermission
+
+ members_can_create_repositories = var.config.membersCanCreateRepositories
+ members_can_create_public_repositories = var.config.membersCanCreatePublicRepositories
+ members_can_create_private_repositories = var.config.membersCanCreatePrivateRepositories
+ members_can_create_internal_repositories = var.config.membersCanCreateInternalRepositories
+ members_can_create_pages = var.config.membersCanCreatePages
+ members_can_create_public_pages = var.config.membersCanCreatePublicPages
+ members_can_create_private_pages = var.config.membersCanCreatePrivatePages
+ members_can_fork_private_repositories = var.config.membersCanForkPrivateRepositories
+ web_commit_signoff_required = var.config.webCommitSignoffRequired
+
+ advanced_security_enabled_for_new_repositories = var.config.advancedSecurityEnabledForNewRepositories
+ dependabot_alerts_enabled_for_new_repositories = var.config.dependabotAlertsEnabledForNewRepositories
+ dependabot_security_updates_enabled_for_new_repositories = var.config.dependabotSecurityUpdatesEnabledForNewRepositories
+ dependency_graph_enabled_for_new_repositories = var.config.dependencyGraphEnabledForNewRepositories
+ secret_scanning_enabled_for_new_repositories = var.config.secretScanningEnabledForNewRepositories
+ secret_scanning_push_protection_enabled_for_new_repositories = var.config.secretScanningPushProtectionEnabledForNewRepositories
+}
diff --git a/modules/github-org-settings/outputs.tf b/modules/github-org-settings/outputs.tf
new file mode 100644
index 000000000..445bb1123
--- /dev/null
+++ b/modules/github-org-settings/outputs.tf
@@ -0,0 +1,25 @@
+output "organization_settings_id" {
+ description = "GitHub organization ID used by github_organization_settings."
+ value = github_organization_settings.this.id
+}
+
+output "billing_email" {
+ description = "Billing email configured for the organization."
+ value = github_organization_settings.this.billing_email
+ sensitive = true
+}
+
+output "default_repository_permission" {
+ description = "Default repository permission configured for organization members."
+ value = github_organization_settings.this.default_repository_permission
+}
+
+output "members_can_create_repositories" {
+ description = "Whether members can create repositories in the organization."
+ value = github_organization_settings.this.members_can_create_repositories
+}
+
+output "advanced_security_enabled_for_new_repositories" {
+ description = "Whether GitHub Advanced Security is enabled for new repositories."
+ value = github_organization_settings.this.advanced_security_enabled_for_new_repositories
+}
diff --git a/modules/github-org-settings/variables.tf b/modules/github-org-settings/variables.tf
new file mode 100644
index 000000000..d0dde70eb
--- /dev/null
+++ b/modules/github-org-settings/variables.tf
@@ -0,0 +1,49 @@
+variable "config" {
+ description = "GitHub organization settings configuration"
+ type = object({
+ billingEmail = string
+
+ company = optional(string)
+ blog = optional(string)
+ email = optional(string)
+ twitterUsername = optional(string)
+ location = optional(string)
+ name = optional(string)
+ description = optional(string)
+
+ hasOrganizationProjects = optional(bool, true)
+ hasRepositoryProjects = optional(bool, true)
+ defaultRepositoryPermission = optional(string, "read")
+ membersCanCreateRepositories = optional(bool, true)
+ membersCanCreatePublicRepositories = optional(bool, true)
+ membersCanCreatePrivateRepositories = optional(bool, true)
+ membersCanCreateInternalRepositories = optional(bool)
+ membersCanCreatePages = optional(bool, true)
+ membersCanCreatePublicPages = optional(bool, true)
+ membersCanCreatePrivatePages = optional(bool, true)
+ membersCanForkPrivateRepositories = optional(bool, false)
+ webCommitSignoffRequired = optional(bool, false)
+
+ advancedSecurityEnabledForNewRepositories = optional(bool, false)
+ dependabotAlertsEnabledForNewRepositories = optional(bool, false)
+ dependabotSecurityUpdatesEnabledForNewRepositories = optional(bool, false)
+ dependencyGraphEnabledForNewRepositories = optional(bool, false)
+ secretScanningEnabledForNewRepositories = optional(bool, false)
+ secretScanningPushProtectionEnabledForNewRepositories = optional(bool, false)
+ })
+
+ validation {
+ condition = length(trimspace(var.config.billingEmail)) > 0
+ error_message = "config.billingEmail must be a non-empty email address."
+ }
+
+ validation {
+ condition = can(regex("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$", var.config.billingEmail))
+ error_message = "config.billingEmail must look like a valid email address."
+ }
+
+ validation {
+ condition = contains(["read", "write", "admin", "none"], var.config.defaultRepositoryPermission)
+ error_message = "config.defaultRepositoryPermission must be one of: read, write, admin, none."
+ }
+}
diff --git a/modules/github-org-settings/versions.tf b/modules/github-org-settings/versions.tf
new file mode 100644
index 000000000..9afbac820
--- /dev/null
+++ b/modules/github-org-settings/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.5"
+
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}