diff --git a/modules/internal_repository/README.md b/modules/internal_repository/README.md new file mode 100644 index 0000000..5fc5ef1 --- /dev/null +++ b/modules/internal_repository/README.md @@ -0,0 +1,59 @@ +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.6 | +| [github](#requirement\_github) | ~> 6.0 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [repository\_base](#module\_repository\_base) | ../repository_base | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [action\_secrets](#input\_action\_secrets) | An (Optional) map of GitHub Actions secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no | +| [advance\_security](#input\_advance\_security) | Enables advance security for the repository. If repository is public `advance_security` is enabled by default and cannot be changed. | `bool` | `true` | no | +| [allow\_auto\_merge](#input\_allow\_auto\_merge) | Allow auto-merging pull requests on the repository | `bool` | `true` | no | +| [allow\_merge\_commit](#input\_allow\_merge\_commit) | (Optional) Set to `false` to disable merge commits on the repository. | `bool` | `true` | no | +| [allow\_rebase\_merge](#input\_allow\_rebase\_merge) | (Optional) Set to `false` to disable rebase merges on the repository. | `bool` | `true` | no | +| [allow\_squash\_merge](#input\_allow\_squash\_merge) | (Optional) Set to `false` to disable squash merges on the repository. | `bool` | `true` | no | +| [codespace\_secrets](#input\_codespace\_secrets) | An (Optional) map of GitHub Codespace secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no | +| [default\_branch](#input\_default\_branch) | The branch to set as the default branch for this repository. Defaults to "main" | `string` | `"main"` | no | +| [delete\_head\_on\_merge](#input\_delete\_head\_on\_merge) | Sets the delete head on merge option for the repository. If true it will delete pull request branches automatically on merge. Defaults to true | `bool` | `true` | no | +| [dependabot\_secrets](#input\_dependabot\_secrets) | An (Optional) map of Dependabot secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no | +| [dependabot\_security\_updates](#input\_dependabot\_security\_updates) | Enables dependabot security updates. Only works when `has_vulnerability_alerts` is set because that is required to enable dependabot for the repository. | `bool` | `true` | no | +| [description](#input\_description) | The description to give to the repository. Defaults to `""` | `string` | `""` | no | +| [environments](#input\_environments) | Environments to create for the repository. |
map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})) | `{}` | no |
+| [homepage](#input\_homepage) | The homepage for the repository | `string` | `""` | no |
+| [license\_template](#input\_license\_template) | The (Optional) license template to apply to the repository | `string` | `null` | no |
+| [merge\_commit\_message](#input\_merge\_commit\_message) | (Optional) Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if allow\_merge\_commit is `true`. | `string` | `"PR_TITLE"` | no |
+| [merge\_commit\_title](#input\_merge\_commit\_title) | (Optional) Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if allow\_merge\_commit is `true`. | `string` | `"MERGE_MESSAGE"` | no |
+| [name](#input\_name) | The name of the repository to create/import. | `string` | n/a | yes |
+| [pages](#input\_pages) | The (Optional) configuration for GitHub Pages for the repository | object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}) | `null` | no |
+| [protected\_branches](#input\_protected\_branches) | A list of ref names or patterns that should be protected. Defaults `["main"]` | `list(string)` | [| no | +| [repository\_team\_permissions](#input\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have in the repository | `map(string)` | n/a | yes | +| [repository\_user\_permissions](#input\_repository\_user\_permissions) | A map where the keys are github usernames and the value is the permissions the user should have in the repository | `map(string)` | n/a | yes | +| [requires\_web\_commit\_signing](#input\_requires\_web\_commit\_signing) | If set commit signatures are required for commits to the organization. Defaults to `false`. | `bool` | `false` | no | +| [rulesets](#input\_rulesets) | n/a |
"main"
]
map(object({
bypass_actors = optional(object({
repository_roles = optional(list(object({
role = string
always_bypass = optional(bool)
})))
teams = optional(list(object({
team = string
always_bypass = optional(bool)
})))
integrations = optional(list(object({
installation_id = number
always_bypass = optional(bool)
})))
organization_admins = optional(list(object({
user = string
always_bypass = optional(bool)
})))
}))
conditions = optional(object({
ref_name = object({
include = list(string)
exclude = list(string)
})
}))
rules = object({
branch_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
tag_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_author_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_message_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
committer_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
creation = optional(bool)
deletion = optional(bool)
update = optional(bool)
non_fast_forward = optional(bool)
required_linear_history = optional(bool)
required_signatures = optional(bool)
update_allows_fetch_and_merge = optional(bool)
pull_request = optional(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_status_checks = optional(object({
required_check = list(object({
context = string
integration_id = optional(number)
}))
strict_required_status_check_policy = optional(bool)
}))
required_deployment_environments = optional(list(string))
})
target = string
enforcement = string
})) | `{}` | no |
+| [squash\_merge\_commit\_message](#input\_squash\_merge\_commit\_message) | (Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if allow\_squash\_merge is `true`. | `string` | `"PR_BODY"` | no |
+| [squash\_merge\_commit\_title](#input\_squash\_merge\_commit\_title) | (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if allow\_squash\_merge is `true`. | `string` | `"PR_TITLE"` | no |
+| [template\_repository](#input\_template\_repository) | A (Optional) list of template repositories to use for the repository | object({
owner = string
repository = string
include_all_branches = bool
}) | `null` | no |
+| [topics](#input\_topics) | The topics to apply to the repository | `list(string)` | `[]` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [id](#output\_id) | The ID of the repository |
\ No newline at end of file
diff --git a/modules/internal_repository/outputs.tf b/modules/internal_repository/outputs.tf
new file mode 100644
index 0000000..b34f827
--- /dev/null
+++ b/modules/internal_repository/outputs.tf
@@ -0,0 +1,4 @@
+output "id" {
+ value = module.repository_base.id
+ description = "The ID of the repository"
+}
diff --git a/modules/internal_repository/repository.tf b/modules/internal_repository/repository.tf
new file mode 100644
index 0000000..c90795c
--- /dev/null
+++ b/modules/internal_repository/repository.tf
@@ -0,0 +1,48 @@
+module "repository_base" {
+ source = "../repository_base"
+
+ name = var.name
+ description = var.description
+ homepage = var.homepage
+ topics = var.topics
+ visibility = "internal"
+ has_downloads = false
+ has_issues = true
+ has_projects = true
+ has_wiki = true
+ has_discussions = true
+
+ repository_team_permissions = var.repository_team_permissions
+ repository_user_permissions = var.repository_user_permissions
+
+ default_branch = var.default_branch
+ protected_branches = var.protected_branches
+ delete_head_on_merge = var.delete_head_on_merge
+ allow_auto_merge = var.allow_auto_merge
+ allow_merge_commit = var.allow_merge_commit
+ allow_rebase_merge = var.allow_rebase_merge
+ allow_squash_merge = var.allow_squash_merge
+ squash_merge_commit_message = var.squash_merge_commit_message
+ squash_merge_commit_title = var.squash_merge_commit_title
+ merge_commit_message = var.merge_commit_message
+ merge_commit_title = var.merge_commit_title
+ requires_web_commit_signing = var.requires_web_commit_signing
+ pages = var.pages
+
+ secret_scanning = true
+ secret_scanning_on_push = true
+ has_vulnerability_alerts = true
+ advance_security = var.advance_security
+ dependabot_security_updates = var.dependabot_security_updates
+
+ codespace_secrets = var.codespace_secrets
+ dependabot_secrets = var.dependabot_secrets
+ action_secrets = var.action_secrets
+
+ environments = var.environments
+
+ template_repository = var.template_repository
+ license_template = var.license_template
+
+ rulesets = var.rulesets
+}
diff --git a/modules/internal_repository/repository.tftest.hcl b/modules/internal_repository/repository.tftest.hcl
new file mode 100644
index 0000000..5605865
--- /dev/null
+++ b/modules/internal_repository/repository.tftest.hcl
@@ -0,0 +1,65 @@
+mock_provider "github" {}
+
+variables {
+ name = "github-foundations-modules"
+ description = "A collection of terraform modules used in the Github Foundations framework."
+ visibility = "internal"
+ has_downloads = true
+ has_issues = true
+ has_projects = true
+ has_wiki = true
+ has_discussions = true
+ has_vulnerability_alerts = true
+ topics = ["terraform", "github", "foundations"]
+ homepage = "myhomepage"
+ delete_head_on_merge = false
+ allow_auto_merge = true
+ allow_squash_merge = false
+ squash_merge_commit_message = "COMMIT_MESSAGES"
+ squash_merge_commit_title = "COMMIT_OR_PR_TITLE"
+ allow_merge_commit = false
+ merge_commit_message = "PR_BODY"
+ merge_commit_title = "PR_TITLE"
+ allow_rebase_merge = true
+ requires_web_commit_signing = false
+ license_template = "mit"
+ dependabot_security_updates = true
+ advance_security = true
+ secret_scanning = true
+ secret_scanning_on_push = true
+
+ default_branch = "main"
+ protected_branches = ["main", "develop"]
+
+ template_repository = {
+ owner = "owner"
+ repository = "template_repository"
+ include_all_branches = true
+ }
+
+ pages = {
+ source = {
+ branch = "main"
+ path = "path"
+ }
+ cname = "cname"
+ }
+
+ repository_team_permissions = {
+ "repo_team1" = "push"
+ "repo_team2" = "admin"
+ }
+ repository_user_permissions = {
+ "user1" = "push"
+ "user2" = "admin"
+ }
+}
+
+run "create_test" {
+ command = apply
+
+ assert {
+ condition = module.repository_base.id != null
+ error_message = "The repository was not created"
+ }
+}
diff --git a/modules/internal_repository/variables.tf b/modules/internal_repository/variables.tf
new file mode 100644
index 0000000..7d5cf79
--- /dev/null
+++ b/modules/internal_repository/variables.tf
@@ -0,0 +1,269 @@
+variable "name" {
+ type = string
+ description = "The name of the repository to create/import."
+}
+
+variable "description" {
+ type = string
+ description = "The description to give to the repository. Defaults to `\"\"`"
+ default = ""
+}
+
+variable "default_branch" {
+ type = string
+ description = "The branch to set as the default branch for this repository. Defaults to \"main\""
+ default = "main"
+}
+
+variable "repository_team_permissions" {
+ type = map(string)
+ description = "A map where the keys are github team slugs and the value is the permissions the team should have in the repository"
+}
+
+variable "repository_user_permissions" {
+ type = map(string)
+ description = "A map where the keys are github usernames and the value is the permissions the user should have in the repository"
+}
+
+variable "protected_branches" {
+ type = list(string)
+ description = "A list of ref names or patterns that should be protected. Defaults `[\"main\"]`"
+ default = ["main"]
+}
+
+variable "topics" {
+ description = "The topics to apply to the repository"
+ type = list(string)
+ default = []
+}
+
+variable "homepage" {
+ description = "The homepage for the repository"
+ type = string
+ default = ""
+}
+
+variable "delete_head_on_merge" {
+ description = "Sets the delete head on merge option for the repository. If true it will delete pull request branches automatically on merge. Defaults to true"
+ type = bool
+ default = true
+}
+
+variable "allow_auto_merge" {
+ description = "Allow auto-merging pull requests on the repository"
+ type = bool
+ default = true
+}
+
+variable "requires_web_commit_signing" {
+ description = "If set commit signatures are required for commits to the organization. Defaults to `false`."
+ type = bool
+ default = false
+}
+
+variable "dependabot_security_updates" {
+ description = "Enables dependabot security updates. Only works when `has_vulnerability_alerts` is set because that is required to enable dependabot for the repository."
+ type = bool
+ default = true
+}
+
+variable "advance_security" {
+ description = "Enables advance security for the repository. If repository is public `advance_security` is enabled by default and cannot be changed."
+ type = bool
+ default = true
+}
+
+variable "action_secrets" {
+ description = "An (Optional) map of GitHub Actions secrets to create for this repository. The key is the name of the secret and the value is the encrypted value."
+ type = map(string)
+ default = {}
+}
+
+variable "codespace_secrets" {
+ description = "An (Optional) map of GitHub Codespace secrets to create for this repository. The key is the name of the secret and the value is the encrypted value."
+ type = map(string)
+ default = {}
+}
+
+variable "dependabot_secrets" {
+ description = "An (Optional) map of Dependabot secrets to create for this repository. The key is the name of the secret and the value is the encrypted value."
+ type = map(string)
+ default = {}
+}
+
+variable "environments" {
+ description = "Environments to create for the repository."
+ type = map(object({
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
+ }))
+ default = {}
+}
+
+variable "template_repository" {
+ description = "A (Optional) list of template repositories to use for the repository"
+ type = object({
+ owner = string
+ repository = string
+ include_all_branches = bool
+ })
+ default = null
+}
+
+variable "license_template" {
+ description = "The (Optional) license template to apply to the repository"
+ type = string
+ default = null
+}
+
+variable "pages" {
+ description = "The (Optional) configuration for GitHub Pages for the repository"
+ type = object({
+ source = optional(object({
+ branch = string
+ path = optional(string)
+ }))
+ build_type = optional(string)
+ cname = optional(string)
+ })
+ default = null
+}
+
+variable "allow_squash_merge" {
+ description = "(Optional) Set to `false` to disable squash merges on the repository."
+ type = bool
+ default = true
+}
+
+variable "allow_rebase_merge" {
+ description = "(Optional) Set to `false` to disable rebase merges on the repository."
+ type = bool
+ default = true
+}
+
+variable "allow_merge_commit" {
+ description = " (Optional) Set to `false` to disable merge commits on the repository."
+ type = bool
+ default = true
+}
+
+variable "squash_merge_commit_title" {
+ description = " (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if allow_squash_merge is `true`."
+ type = string
+ default = "PR_TITLE"
+}
+
+variable "squash_merge_commit_message" {
+ description = "(Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if allow_squash_merge is `true`."
+ type = string
+ default = "PR_BODY"
+}
+
+variable "merge_commit_title" {
+ description = "(Optional) Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if allow_merge_commit is `true`."
+ type = string
+ default = "MERGE_MESSAGE"
+}
+
+variable "merge_commit_message" {
+ description = "(Optional) Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if allow_merge_commit is `true`."
+ type = string
+ default = "PR_TITLE"
+}
+
+variable "rulesets" {
+ type = map(object({
+ bypass_actors = optional(object({
+ repository_roles = optional(list(object({
+ role = string
+ always_bypass = optional(bool)
+ })))
+ teams = optional(list(object({
+ team = string
+ always_bypass = optional(bool)
+ })))
+ integrations = optional(list(object({
+ installation_id = number
+ always_bypass = optional(bool)
+ })))
+ organization_admins = optional(list(object({
+ user = string
+ always_bypass = optional(bool)
+ })))
+ }))
+ conditions = optional(object({
+ ref_name = object({
+ include = list(string)
+ exclude = list(string)
+ })
+ }))
+ rules = object({
+ branch_name_pattern = optional(object({
+ operator = string
+ pattern = string
+ name = optional(string)
+ negate = optional(bool)
+ }))
+ tag_name_pattern = optional(object({
+ operator = string
+ pattern = string
+ name = optional(string)
+ negate = optional(bool)
+ }))
+ commit_author_email_pattern = optional(object({
+ operator = string
+ pattern = string
+ name = optional(string)
+ negate = optional(bool)
+ }))
+ commit_message_pattern = optional(object({
+ operator = string
+ pattern = string
+ name = optional(string)
+ negate = optional(bool)
+ }))
+ committer_email_pattern = optional(object({
+ operator = string
+ pattern = string
+ name = optional(string)
+ negate = optional(bool)
+ }))
+ creation = optional(bool)
+ deletion = optional(bool)
+ update = optional(bool)
+ non_fast_forward = optional(bool)
+ required_linear_history = optional(bool)
+ required_signatures = optional(bool)
+ update_allows_fetch_and_merge = optional(bool)
+ pull_request = optional(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_status_checks = optional(object({
+ required_check = list(object({
+ context = string
+ integration_id = optional(number)
+ }))
+ strict_required_status_check_policy = optional(bool)
+ }))
+ required_deployment_environments = optional(list(string))
+ })
+ target = string
+ enforcement = string
+ }))
+ default = {}
+}
diff --git a/modules/internal_repository/versions.tf b/modules/internal_repository/versions.tf
new file mode 100644
index 0000000..1957e13
--- /dev/null
+++ b/modules/internal_repository/versions.tf
@@ -0,0 +1,9 @@
+terraform {
+ required_version = ">= 1.6"
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}
diff --git a/modules/repository_set/README.md b/modules/repository_set/README.md
index 13eacbe..5b41b63 100644
--- a/modules/repository_set/README.md
+++ b/modules/repository_set/README.md
@@ -15,6 +15,7 @@
| Name | Source | Version |
|------|--------|---------|
+| [internal\_repositories](#module\_internal\_repositories) | ../internal_repository | n/a |
| [private\_repositories](#module\_private\_repositories) | ../private_repository | n/a |
| [public\_repositories](#module\_public\_repositories) | ../public_repository | n/a |
@@ -32,6 +33,7 @@
|------|-------------|------|---------|:--------:|
| [default\_repository\_team\_permissions](#input\_default\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have by default for every repository. If an entry exists in `repository_team_permissions_override` for a repository then that will take precedence over this default. Defaults to `{}` giving no team access to the repositories. | `map(string)` | `{}` | no |
| [has\_ghas\_license](#input\_has\_ghas\_license) | If the organization owning the repositories has a GitHub Advanced Security license or not. Defaults to false. | `bool` | `false` | no |
+| [internal\_repositories](#input\_internal\_repositories) | A map of internal repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | `{}` | no |
| [private\_repositories](#input\_private\_repositories) | A map of private repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
has_vulnerability_alerts = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
requires_web_commit_signing = bool
dependabot_security_updates = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
| [public\_repositories](#input\_public\_repositories) | A map of public repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
| [rulesets](#input\_rulesets) | n/a | map(object({
bypass_actors = optional(object({
repository_roles = optional(list(object({
role = string
always_bypass = optional(bool)
})))
teams = optional(list(object({
team = string
always_bypass = optional(bool)
})))
integrations = optional(list(object({
installation_id = number
always_bypass = optional(bool)
})))
organization_admins = optional(list(object({
user = string
always_bypass = optional(bool)
})))
}))
conditions = optional(object({
ref_name = object({
include = list(string)
exclude = list(string)
})
}))
rules = object({
branch_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
tag_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_author_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_message_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
committer_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
creation = optional(bool)
deletion = optional(bool)
update = optional(bool)
non_fast_forward = optional(bool)
required_linear_history = optional(bool)
required_signatures = optional(bool)
update_allows_fetch_and_merge = optional(bool)
pull_request = optional(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_status_checks = optional(object({
required_check = list(object({
context = string
integration_id = optional(number)
}))
strict_required_status_check_policy = optional(bool)
}))
required_deployment_environments = optional(list(string))
})
target = string
enforcement = string
repositories = list(string)
})) | `{}` | no |
diff --git a/modules/repository_set/organization-secrets.tf b/modules/repository_set/organization-secrets.tf
index ab5f84d..8c6f42f 100644
--- a/modules/repository_set/organization-secrets.tf
+++ b/modules/repository_set/organization-secrets.tf
@@ -1,40 +1,47 @@
locals {
coalesced_public_repositories = coalesce(var.public_repositories, {})
coalesced_private_repositories = coalesce(var.private_repositories, {})
+ coalesced_internal_repositories = coalesce(var.internal_repositories, {})
organization_action_secrets = distinct(flatten(concat(
[for _, repo in local.coalesced_public_repositories : repo.organization_action_secrets if repo.organization_action_secrets != null],
- [for _, repo in local.coalesced_private_repositories : repo.organization_action_secrets if repo.organization_action_secrets != null]
+ [for _, repo in local.coalesced_private_repositories : repo.organization_action_secrets if repo.organization_action_secrets != null],
+ [for _, repo in local.coalesced_internal_repositories : repo.organization_action_secrets if repo.organization_action_secrets != null]
)))
organization_action_secrets_repository_id_list = {
for secret in local.organization_action_secrets : secret => toset(distinct(concat(
[for repo_name, repo in local.coalesced_public_repositories : module.public_repositories[repo_name].id if contains(coalesce(repo.organization_action_secrets, []), secret)],
- [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_action_secrets, []), secret)]
+ [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_action_secrets, []), secret)],
+ [for repo_name, repo in local.coalesced_internal_repositories : module.internal_repositories[repo_name].id if contains(coalesce(repo.organization_action_secrets, []), secret)]
)))
}
codespace_secrets = distinct(flatten(concat(
[for _, repo in local.coalesced_public_repositories : repo.organization_codespace_secrets if repo.organization_codespace_secrets != null],
- [for _, repo in local.coalesced_private_repositories : repo.organization_codespace_secrets if repo.organization_codespace_secrets != null]
+ [for _, repo in local.coalesced_private_repositories : repo.organization_codespace_secrets if repo.organization_codespace_secrets != null],
+ [for _, repo in local.coalesced_internal_repositories : repo.organization_codespace_secrets if repo.organization_codespace_secrets != null]
)))
codespace_secrets_repository_id_list = {
for secret in local.codespace_secrets : secret => toset(distinct(concat(
[for repo_name, repo in local.coalesced_public_repositories : module.public_repositories[repo_name].id if contains(coalesce(repo.organization_codespace_secrets, []), secret)],
- [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_codespace_secrets, []), secret)]
+ [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_codespace_secrets, []), secret)],
+ [for repo_name, repo in local.coalesced_internal_repositories : module.internal_repositories[repo_name].id if contains(coalesce(repo.organization_codespace_secrets, []), secret)]
)))
}
dependabot_secrets = distinct(flatten(concat(
[for _, repo in local.coalesced_public_repositories : repo.organization_dependabot_secrets if repo.organization_dependabot_secrets != null],
- [for _, repo in local.coalesced_private_repositories : repo.organization_dependabot_secrets if repo.organization_dependabot_secrets != null]
+ [for _, repo in local.coalesced_private_repositories : repo.organization_dependabot_secrets if repo.organization_dependabot_secrets != null],
+ [for _, repo in local.coalesced_internal_repositories : repo.organization_dependabot_secrets if repo.organization_dependabot_secrets != null]
)))
dependabot_secrets_id_list = {
for secret in local.dependabot_secrets : secret => toset(distinct(concat(
[for repo_name, repo in local.coalesced_public_repositories : module.public_repositories[repo_name].id if contains(coalesce(repo.organization_dependabot_secrets, []), secret)],
- [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_dependabot_secrets, []), secret)]
+ [for repo_name, repo in local.coalesced_private_repositories : module.private_repositories[repo_name].id if contains(coalesce(repo.organization_dependabot_secrets, []), secret)],
+ [for repo_name, repo in local.coalesced_internal_repositories : module.internal_repositories[repo_name].id if contains(coalesce(repo.organization_dependabot_secrets, []), secret)]
)))
}
}
diff --git a/modules/repository_set/organization_secrets.tftest.hcl b/modules/repository_set/organization_secrets.tftest.hcl
index f9d8495..3f77184 100644
--- a/modules/repository_set/organization_secrets.tftest.hcl
+++ b/modules/repository_set/organization_secrets.tftest.hcl
@@ -25,6 +25,7 @@ variables {
}
private_repositories = {}
+
}
run "organization_actions_secrets_test" {
diff --git a/modules/repository_set/repositories.tf b/modules/repository_set/repositories.tf
index d507dad..fe148e8 100644
--- a/modules/repository_set/repositories.tf
+++ b/modules/repository_set/repositories.tf
@@ -9,6 +9,11 @@ locals {
for ruleset_name, ruleset_config in var.rulesets : ruleset_name => ruleset_config if contains(ruleset_config.repositories, repo_name)
}
}
+ rulesets_by_internal_repository = {
+ for repo_name, repo_config in var.internal_repositories : repo_name => {
+ for ruleset_name, ruleset_config in var.rulesets : ruleset_name => ruleset_config if contains(ruleset_config.repositories, repo_name)
+ }
+ }
}
module "public_repositories" {
@@ -81,3 +86,38 @@ module "private_repositories" {
rulesets = lookup(local.rulesets_by_private_repository, each.key, {})
pages = each.value.pages
}
+
+module "internal_repositories" {
+ source = "../internal_repository"
+
+ for_each = var.internal_repositories
+
+ name = each.key
+ repository_team_permissions = merge(var.default_repository_team_permissions, coalesce(each.value.repository_team_permissions_override, {}))
+ repository_user_permissions = coalesce(each.value.user_permissions, {})
+ description = each.value.description
+ default_branch = each.value.default_branch
+ protected_branches = each.value.protected_branches
+ advance_security = each.value.advance_security
+ topics = each.value.topics
+ homepage = each.value.homepage
+ delete_head_on_merge = each.value.delete_head_on_merge
+ allow_auto_merge = each.value.allow_auto_merge
+ allow_merge_commit = each.value.allow_merge_commit
+ allow_rebase_merge = each.value.allow_rebase_merge
+ allow_squash_merge = each.value.allow_squash_merge
+ merge_commit_title = each.value.merge_commit_title
+ merge_commit_message = each.value.merge_commit_message
+ squash_merge_commit_title = each.value.squash_merge_commit_title
+ squash_merge_commit_message = each.value.squash_merge_commit_message
+ dependabot_security_updates = each.value.dependabot_security_updates
+ action_secrets = each.value.action_secrets
+ codespace_secrets = each.value.codespace_secrets
+ dependabot_secrets = each.value.dependabot_secrets
+ environments = each.value.environments
+ template_repository = each.value.template_repository
+ license_template = each.value.license_template
+ requires_web_commit_signing = each.value.requires_web_commit_signing
+ rulesets = lookup(local.rulesets_by_internal_repository, each.key, {})
+ pages = each.value.pages
+}
diff --git a/modules/repository_set/repositories.tftest.hcl b/modules/repository_set/repositories.tftest.hcl
index d0ff2de..de777a2 100644
--- a/modules/repository_set/repositories.tftest.hcl
+++ b/modules/repository_set/repositories.tftest.hcl
@@ -169,6 +169,88 @@ variables {
GhFoundationsAdmins = "admin"
GhFoundationsDevelopers = "push"
}
+
+ internal_repositories = {
+
+ "internal-github-foundations-modules" = {
+ description = "A collection of terraform modules used in the Github Foundations framework."
+ default_branch = "main"
+ protected_branches = ["main"]
+ advance_security = false
+ has_vulnerability_alerts = true
+ topics = ["terraform", "github", "foundations"]
+ homepage = "myhomepage"
+ delete_head_on_merge = false
+ dependabot_security_updates = true
+ requires_web_commit_signing = false
+ allow_auto_merge = true
+ allow_squash_merge = false
+ allow_rebase_merge = true
+ allow_merge_commit = false
+ squash_merge_commit_title = "COMMIT_OR_PR_TITLE"
+ squash_merge_commit_message = "COMMIT_MESSAGES"
+ merge_commit_title = "PR_TITLE"
+ merge_commit_message = "PR_BODY"
+ repository_team_permissions_override = {
+ "repo_team1" = "push"
+ "repo_team2" = "admin"
+ }
+ user_permissions = {
+ "user1" = "push"
+ "user2" = "admin"
+ }
+
+
+ action_secrets = {
+ "action_secret1" = "value1"
+ }
+
+ codespace_secrets = {
+ "codespace_secret1" = "value1"
+ }
+
+ dependabot_secrets = {
+ "dependabot_secret1" = "value1"
+ }
+
+ environments = {
+ "env1" = {
+ wait_timer = 10
+ can_admins_bypass = true
+ prevent_self_review = false
+ action_secrets = {
+ "action_secret1" = "dmFsdWUxCg==" # base64 encoded
+ }
+ reviewers = {
+ teams = [111, 222]
+ users = [55, 66]
+ }
+ deployment_branch_policy = {
+ protected_branches = true
+ custom_branch_policies = false
+ branch_patterns = ["main"]
+ }
+ }
+ }
+
+ template_repository = {
+ owner = "owner"
+ repository = "template_repository"
+ include_all_branches = true
+ }
+
+ license_template = "mit"
+
+ pages = {
+ source = {
+ branch = "main"
+ path = "path"
+ }
+ # build_type = "build_type"
+ cname = "cname"
+ }
+ }
+ }
}
run "apply" {
@@ -188,3 +270,10 @@ run "private_repository_test" {
error_message = "The repository id value is incorrect. Expected not null, got ${module.private_repositories["private-github-foundations-modules"].id}"
}
}
+
+run "internal_repository_test" {
+ assert {
+ condition = module.internal_repositories["internal-github-foundations-modules"].id != null
+ error_message = "The repository id value is incorrect. Expected not null, got ${module.internal_repositories["internal-github-foundations-modules"].id}"
+ }
+}
diff --git a/modules/repository_set/variables.tf b/modules/repository_set/variables.tf
index 9288cb9..0c9b883 100644
--- a/modules/repository_set/variables.tf
+++ b/modules/repository_set/variables.tf
@@ -119,6 +119,67 @@ variable "public_repositories" {
description = "A map of public repositories where the key is the repository name and the value is the configuration"
}
+variable "internal_repositories" {
+ type = map(object({
+ description = string
+ default_branch = string
+ protected_branches = list(string)
+ advance_security = bool
+ topics = list(string)
+ homepage = string
+ delete_head_on_merge = bool
+ dependabot_security_updates = bool
+ requires_web_commit_signing = bool
+ allow_auto_merge = optional(bool)
+ allow_squash_merge = optional(bool)
+ allow_rebase_merge = optional(bool)
+ allow_merge_commit = optional(bool)
+ squash_merge_commit_title = optional(string)
+ squash_merge_commit_message = optional(string)
+ merge_commit_title = optional(string)
+ merge_commit_message = optional(string)
+ repository_team_permissions_override = optional(map(string))
+ user_permissions = optional(map(string))
+ organization_action_secrets = optional(list(string))
+ organization_codespace_secrets = optional(list(string))
+ organization_dependabot_secrets = optional(list(string))
+ action_secrets = optional(map(string))
+ codespace_secrets = optional(map(string))
+ dependabot_secrets = optional(map(string))
+ environments = optional(map(object({
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
+ })))
+ template_repository = optional(object({
+ owner = string
+ repository = string
+ include_all_branches = bool
+ }))
+ license_template = optional(string)
+ pages = optional(object({
+ source = optional(object({
+ branch = string
+ path = optional(string)
+ }))
+ build_type = optional(string)
+ cname = optional(string)
+ }))
+ }))
+ description = "A map of internal repositories where the key is the repository name and the value is the configuration"
+ default = {}
+}
+
variable "has_ghas_license" {
type = bool
description = "If the organization owning the repositories has a GitHub Advanced Security license or not. Defaults to false."
@@ -217,3 +278,4 @@ variable "rulesets" {
}))
default = {}
}
+