Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: GitHub component #2

Merged
merged 11 commits into from
Oct 20, 2023
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
root = true

# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
quote_type = double

[*.md]
max_line_length = 0
trim_trailing_whitespace = false
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
*.tfstate
*.tfstate.*

# Terraform lock files
.terraform.lock.hcl
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should include

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The components are intended to be used as child modules, and the root module should have it's own lock file anyway. What's the reason we might want to keep it here?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this component is already at root module level for a consumer. The most we would do is just copy it into sts-devops, no? to wrap it an additional time and write another variable = var.variable ... block seems like too much

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally I see no opinions online that lockfiles should not be included in child modules and don't see a reason not to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just not used by Terraform, no init is run on this level.

Copy link
Member Author

@gberenice gberenice Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this component is already at root module level for a consumer. The most we would do is just copy it into sts-devops, no? to wrap it an additional time and write another variable = var.variable ... block seems like too much

Not sure. Let's discuss on a call.


# Crash log files
crash.log

# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
# .tfvars files are managed as part of configuration and so should be included in
# version control.
#
# example.tfvars
*.tfvars

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
Expand Down
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.83.5 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases
hooks:
- id: terraform_fmt
- id: terraform_docs
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
# terraform-components
The Masterpoint reusable and sharable Terraform Root Modules (Components)
[![Masterpoint Logo](https://i.imgur.com/RDLnuQO.png)](https://masterpoint.io)

# terraform-components [![Latest Release](https://img.shields.io/github/release/masterpointio/terraform-components.svg)](https://github.com/masterpointio/terraform-components/releases/latest)

This is a Masterpoint's reusable and sharable collection of Terraform Root Modules (Components). Each Component is a set of Terraform modules, resources, data sources and local expressions that represent an higher abstraction layer of infrastructure comparing to an average community child module. It can be easily integrated into the architecture and removed if needed.

It's Open Source and licensed under the [APACHE2](LICENSE).

## Components

* [GitHub](./github/README.md): responsible for managing GitHub resources, including repositories, teams, permissions, pages, etc.
94 changes: 94 additions & 0 deletions github/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# GitHub Component
This repository contains a collection of Terraform configurations tailored for managing GitHub resources, including repositories, teams (TBD), permissions, and more.

## Usage

### Prerequsites

This Terraform module makes extensive use of the [integrations/github](https://registry.terraform.io/providers/integrations/github/latest/docs#pem_file) Terraform Provider to manage resources within a GitHub organization or user account. This requires setting up the GitHub provider with appropriate credentials to interact with the GitHub API.

The following ways to authenticate with GitHub API are supported:
* OAuth / Personal Access Token
* GitHub App Installation

We use [terraform-secrets-helper](https://github.com/masterpointio/terraform-secrets-helper/tree/main) to retrieve sensitive data, such as tokens or pem file content. At the moment, we support SOPS encrypted files as a source, so before using this component:
* Create a [GitHub Token](https://github.com/settings/tokens) or [GitHub App Installation](https://docs.github.com/en/rest/apps/installations?apiVersion=2022-11-28).
* Add the secret to SOPS file, see [SOPS Usage](https://github.com/getsops/sops#usage) for detailed instructions.
* Provide the secrets name and path to your SOPS file as inputs.

### Example

You can start with the configuration below to use the GitHub component module.

:warning: the key of each item in the `repos` map matches the repository's name. This is to ensure consistent naming and referencing throughout your Terraform configuration.

```hcl
module "github" {
source = "git::https://github.com/masterpointio/terraform-components.git//github?ref=<TAG_OR_COMMIT_SHA>"

# GitHub provider
gh_owner = "myorg"
gh_token_secret_name = "gh_token"

# SOPS secrets
secret_mapping = [{
name = "gh_token"
file = "./config/secrets/global.yaml"
type = "sops"
}]

# GitHub repositories
repos = {
"best-pet-project" = {
description = "This is a private repo for the Best Pet Project."
# ... other configurations
},
"demo" = {
visibility = public
# ... other configurations
}
}
}
```

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_github"></a> [github](#requirement\_github) | >= 5.0 |
| <a name="requirement_sops"></a> [sops](#requirement\_sops) | >= 0.7 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_repos"></a> [repos](#module\_repos) | mineiros-io/repository/github | 0.18.0 |
| <a name="module_secrets"></a> [secrets](#module\_secrets) | masterpointio/helper/secrets | 0.2.0 |

## Resources

No resources.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_gh_app_auth_id"></a> [gh\_app\_auth\_id](#input\_gh\_app\_auth\_id) | The ID of the GitHub App. | `string` | `""` | no |
| <a name="input_gh_app_auth_installation_id"></a> [gh\_app\_auth\_installation\_id](#input\_gh\_app\_auth\_installation\_id) | The ID of the GitHub App installation | `string` | `""` | no |
| <a name="input_gh_app_auth_pem_file_secret_name"></a> [gh\_app\_auth\_pem\_file\_secret\_name](#input\_gh\_app\_auth\_pem\_file\_secret\_name) | The name of the secret retrieved by secrets mixin that contains<br>the contents of the GitHub App private key PEM file. | `string` | `null` | no |
| <a name="input_gh_base_url"></a> [gh\_base\_url](#input\_gh\_base\_url) | (Optional) This is the target GitHub base API endpoint.<br>Providing a value is a requirement when working with GitHub Enterprise.<br>It is optional to provide this value and it can also be sourced from the GITHUB\_BASE\_URL environment variable.<br>The value must end with a slash, for example: https://terraformtesting-ghe.westus.cloudapp.azure.com/ | `string` | `null` | no |
| <a name="input_gh_owner"></a> [gh\_owner](#input\_gh\_owner) | (Optional) This is the target GitHub organization or individual user account to manage.<br>For example, `torvalds` and `github` are valid owners. It is optional to provide this value<br>and it can also be sourced from the GITHUB\_OWNER environment variable.<br>When not provided and a token is available, the individual user account owning the token will be used.<br>When not provided and no token is available, the provider may not function correctly. | `string` | `null` | no |
| <a name="input_gh_token_secret_name"></a> [gh\_token\_secret\_name](#input\_gh\_token\_secret\_name) | The name of the secret retrieved by secrets mixin that contains the GitHub personal access token. | `string` | `null` | no |
| <a name="input_repos"></a> [repos](#input\_repos) | The GitHub repositories for this organization. | <pre>map(object({<br> # Main Resource Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#main-resource-configuration<br> allow_auto_merge = optional(bool, false)<br> allow_merge_commit = optional(bool, true)<br> allow_rebase_merge = optional(bool, false)<br> allow_squash_merge = optional(bool, false)<br> archive_on_destroy = optional(bool, true)<br> archived = optional(bool, false)<br> default_branch = optional(string, null)<br> description = optional(string, "")<br> extra_topics = optional(list(string), [])<br> has_downloads = optional(bool, false)<br> has_issues = optional(bool, false)<br> has_projects = optional(bool, false)<br> has_wiki = optional(bool, false)<br> homepage_url = optional(string, "")<br> is_template = optional(bool, false)<br> pages = optional(object({<br> branch = string<br> cname = optional(string, null)<br> path = optional(string, "/")<br> }))<br> topics = optional(list(string), [])<br> visibility = optional(string, "private")<br> vulnerability_alerts = optional(bool, false)<br><br> # Extended Resource Configuration<br><br> ## Repository Creation Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#repository-creation-configuration<br> auto_init = optional(bool, true)<br> gitignore_template = optional(string, "")<br> license_template = optional(string, "")<br> template = optional(object({<br> owner = string<br> repository = string<br> }))<br><br> ## Teams Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#teams-configuration<br> admin_teams = optional(list(string), [])<br> maintain_teams = optional(list(string), [])<br> pull_teams = optional(list(string), [])<br> push_teams = optional(list(string), [])<br> triage_teams = optional(list(string), [])<br><br> ## Collaborator Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#collaborator-configuration<br> admin_collaborators = optional(list(string), [])<br> maintain_collaborators = optional(list(string), [])<br> pull_collaborators = optional(list(string), [])<br> push_collaborators = optional(list(string), [])<br> triage_collaborators = optional(list(string), [])<br><br> ## Branches Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#branches-configuration<br> branches = optional(list(object({<br> name = string<br> source_branch = optional(string, null)<br> source_sha = optional(bool, null)<br> })), [])<br><br> ## Deploy Keys Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#deploy-keys-configuration<br> deploy_keys = optional(list(object({<br> id = optional(string, "md5(key)")<br> key = string<br> read_only = optional(bool, true)<br> title = optional(string, null)<br> })), [])<br> deploy_keys_computed = optional(list(object({<br> id = optional(string, "md5(key)")<br> key = string<br> read_only = optional(bool, true)<br> title = optional(string, null)<br> })), [])<br><br> ## Branch Protections v3 Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#branch-protections-v3-configuration<br> branch_protections_v3 = optional(list(object({<br> branch = string<br> enforce_admins = optional(bool, false)<br> require_conversation_resolution = optional(bool, false)<br> require_signed_commits = optional(bool, false)<br> required_pull_request_reviews = optional(object({<br> dismiss_stale_reviews = optional(bool, true)<br> dismissal_users = optional(list(string), []),<br> dismissal_teams = optional(list(string), []),<br> require_code_owner_reviews = optional(bool, true)<br> required_approving_review_count = optional(number, 1)<br> }), {})<br> required_status_checks = optional(object({<br> strict = optional(bool, false)<br> contexts = optional(list(string), [])<br> }), {})<br> restrictions = optional(object({<br> users = optional(list(string), [])<br> teams = optional(list(string), [])<br> apps = optional(list(string), [])<br> }), {})<br> })), [])<br><br> ## Branch Protections v4 Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#branch-protections-v4-configuration<br> branch_protections_v4 = optional(list(object({<br> pattern = string<br> _key = optional(string)<br> allows_deletions = optional(bool, false)<br> allows_force_pushes = optional(bool, false)<br> blocks_creations = optional(bool, false)<br> enforce_admins = optional(bool, true)<br> push_restrictions = optional(list(string), [])<br> require_conversation_resolution = optional(bool, false)<br> require_signed_commits = optional(bool, false)<br> required_linear_history = optional(bool, false)<br> required_pull_request_reviews = optional(list(object({<br> dismiss_stale_reviews = optional(bool, true)<br> restrict_dismissals = optional(bool, false)<br> dismissal_restrictions = optional(list(string), [])<br> pull_request_bypassers = optional(list(string), [])<br> require_code_owner_reviews = optional(bool, true)<br> required_approving_review_count = optional(number, 1)<br> })), [])<br> required_status_checks = optional(list(object({<br> strict = optional(bool, false)<br> contexts = optional(list(string), [])<br> })), [])<br> })), [])<br><br> ## Issue Labels Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#issue-labels-configuration<br> issue_labels = optional(list(object({<br> color = string<br> description = optional(string, null)<br> id = optional(string, "name")<br> name = string<br> })), [])<br><br> issue_labels_merge_with_github_labels = optional(bool)<br> issue_labels_create = optional(bool)<br><br> ## Projects Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#projects-configuration<br> projects = optional(list(object({<br> body = optional(string, "")<br> id = optional(string, "name")<br> name = string<br> })), [])<br><br> ## Webhooks Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#webhooks-configuration<br> webhooks = optional(list(object({<br> active = optional(bool, true)<br> content_type = optional(string, "form")<br> insecure_ssl = optional(bool, false)<br> events = list(string)<br> name = optional(string)<br> secret = optional(string)<br> url = string<br> })), [])<br><br> ## Secrets Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#secrets-configuration<br> plaintext_secrets = optional(map(string), {})<br> encrypted_secrets = optional(map(string), {})<br><br> ## Autolink References Configuration<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#autolink-references-configuration<br> autolink_references = optional(list(object({<br> key_prefix = string<br> target_url_template = string<br> })), [])<br><br> ## App Installations<br> # https://github.com/mineiros-io/terraform-github-repository/tree/main#app-installations<br> app_installations = optional(set(string), [])<br> }))</pre> | `{}` | no |
| <a name="input_secret_mapping"></a> [secret\_mapping](#input\_secret\_mapping) | The list of secret mappings the application will need.<br>This creates secret values for the component to consume at `local.secrets[name]`. | <pre>list(object({<br> name = string<br> type = string<br> path = optional(string, null)<br> file = string<br> }))</pre> | `[]` | no |

## Outputs

No outputs.
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
88 changes: 88 additions & 0 deletions github/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
module "repos" {
source = "mineiros-io/repository/github"
version = "0.18.0"

for_each = var.repos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!


# Main Resource Configuration
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
archive_on_destroy = each.value.archive_on_destroy
archived = each.value.archived
# NOTE: The configured branch must exist in the repository.
# If the branch doesn't exist yet, or if you are creating a new repository,
# please add the desired default branch to the `branches` variable, which will cause Terraform to create it for you.
default_branch = each.value.default_branch
description = each.value.description
extra_topics = each.value.extra_topics
has_downloads = each.value.has_downloads
has_issues = each.value.has_issues
has_projects = each.value.has_projects
has_wiki = each.value.has_wiki
homepage_url = each.value.homepage_url
is_template = each.value.is_template
name = each.key
pages = each.value.pages
topics = each.value.topics
visibility = each.value.visibility
vulnerability_alerts = each.value.vulnerability_alerts

# Extended Resource Configuration
auto_init = each.value.auto_init
gitignore_template = each.value.gitignore_template
license_template = each.value.license_template
template = each.value.template

# Teams Configuration
admin_teams = each.value.admin_teams
maintain_teams = each.value.maintain_teams
pull_teams = each.value.pull_teams
push_teams = each.value.push_teams
triage_teams = each.value.triage_teams

# Collaborator Configuration
admin_collaborators = each.value.admin_collaborators
maintain_collaborators = each.value.maintain_collaborators
pull_collaborators = each.value.pull_collaborators
push_collaborators = each.value.push_collaborators
triage_collaborators = each.value.triage_collaborators

# Branches Configuration
branches = each.value.branches

# Deploy Keys Configuration
deploy_keys = each.value.deploy_keys
deploy_keys_computed = each.value.deploy_keys_computed

# Branch Protections v3 Configuration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove V3 config so we can avoid potentially using it since it sounds like it's now legacy?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, especially considering it may conflict with v4 branch protections if used for the same branch. Removed.

branch_protections_v3 = each.value.branch_protections_v3

# Branch Protections v4 Configuration
branch_protections_v4 = each.value.branch_protections_v4

# Issue Labels Configuration
issue_labels = each.value.issue_labels
issue_labels_create = each.value.issue_labels_create

issue_labels_merge_with_github_labels = each.value.issue_labels_merge_with_github_labels

# Projects Configuration
projects = each.value.projects

# Webhooks Configuration
webhooks = each.value.webhooks

# Secrets Configuration
plaintext_secrets = each.value.plaintext_secrets
encrypted_secrets = each.value.encrypted_secrets

# Autolink References Configuration
autolink_references = each.value.autolink_references

# App Installations
app_installations = each.value.app_installations
}


kevcube marked this conversation as resolved.
Show resolved Hide resolved
Loading