-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add module gh-repo-secrets-section #955
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
e72eea1
fb43705
76954c4
48a8033
e23eb20
e72190f
d0efbda
0e6133b
ddf875d
f056a2f
2757e81
da6cf5e
ffaf612
521b8f2
cbe8ad8
928876d
135d0d8
ba7d332
6505933
704ec0a
be45669
52ccb95
6fe80be
e571797
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| formatter: "markdown" | ||
|
|
||
| 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: |- | ||
| <!-- BEGIN_TF_DOCS --> | ||
| {{ .Content }} | ||
| <!-- END_TF_DOCS --> | ||
|
|
||
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| <!-- BEGIN_TF_DOCS --> | ||
| # **GitHub Repository Secrets Terraform Module** | ||
|
|
||
| ## Overview | ||
|
|
||
| This module manages GitHub repository secrets for **Actions**, **Codespaces**, and **Dependabot** using a single strongly-typed `config` object. | ||
|
|
||
| **Important**: | ||
| The `encryptedValue` values passed in the `config` **must already be encrypted** using **libsodium** against the target repository’s public key (GitHub’s recommended method). | ||
| **Terraform does not perform any encryption**. It simply forwards the pre-encrypted value to the GitHub API. | ||
|
|
||
| This approach is the most secure for automated pipelines (Prefapp IDP, GitHub Actions, etc.). | ||
|
|
||
| ## Key Features | ||
|
|
||
| - **Single complex object**: All secrets are defined in one `config` variable. | ||
| - **Pre-encrypted values**: `encryptedValue` must be provided already encrypted with libsodium. | ||
| - **Three secret types**: Actions, Codespaces, and Dependabot supported in the same module. | ||
| - **Lifecycle protection**: `ignore_changes` on `encrypted_value` to prevent unnecessary drift. | ||
| - **Full validation**: Enforces required fields and non-empty values. | ||
| - **JSON-native**: Works seamlessly with `terraform.tfvars.json` generated by external programs. | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| ### Using `terraform.tfvars.json` (recommended) | ||
|
|
||
| ```hcl | ||
| module "repo_secrets" { | ||
| source = "git::https://github.com/prefapp/tfm.git//modules/github-repository-secrets" | ||
|
|
||
| config = var.config # Terraform automatically loads terraform.tfvars.json | ||
|
Comment on lines
+27
to
+31
|
||
| } | ||
|
|
||
| ### Inline example | ||
|
|
||
| ```hcl | ||
| module "repo\_secrets" { | ||
| source = "git::https://github.com/prefapp/tfm.git//modules/github-repository-secrets" | ||
|
|
||
| config = { | ||
| actions = { | ||
| SECRET\_A = { | ||
| secretName = "SECRET\_A" | ||
| repository = "component\_a" | ||
| encryptedValue = "r+RFBGIn8U7z2Opm5RN7PXKdgFzefXiV91IpG3O2DrClZl9dkTJBfhRZbi2uV2nu4ijn5yUfZ9O1eqjaXL2dWByFV+T2swZCQVQdDGmDlF24MPvEFh2ZbQ==" | ||
| } | ||
| } | ||
| codespaces = {} | ||
| dependabot = {} | ||
| } | ||
| } | ||
|
|
||
frmadem marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ## Requirements | ||
|
|
||
| | Name | Version | | ||
| |------|---------| | ||
| | <a name="requirement_github"></a> [github](#requirement\_github) | ~> 6.0 | | ||
|
|
||
| ## Providers | ||
|
|
||
| | Name | Version | | ||
| |------|---------| | ||
| | <a name="provider_github"></a> [github](#provider\_github) | ~> 6.0 | | ||
|
|
||
| ## Modules | ||
|
|
||
| No modules. | ||
|
|
||
| ## Resources | ||
|
|
||
| | Name | Type | | ||
| |------|------| | ||
| | [github_actions_secret.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource | | ||
| | [github_codespaces_secret.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/codespaces_secret) | resource | | ||
| | [github_dependabot_secret.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/dependabot_secret) | resource | | ||
|
|
||
| ## Inputs | ||
|
|
||
| | Name | Description | Type | Default | Required | | ||
| |------|-------------|------|---------|:--------:| | ||
| | <a name="input_config"></a> [config](#input\_config) | GitHub repository secrets configuration as a single complex object.<br/><br/>IMPORTANT:<br/>- encryptedValue must be ALREADY encrypted with libsodium using the target repository's public key.<br/>- Terraform does NOT encrypt anything — it only passes the pre-encrypted value. | <pre>object({<br/> actions = optional(map(object({<br/> secretName = string<br/> repository = string<br/> encryptedValue = string<br/> })), {})<br/><br/> codespaces = optional(map(object({<br/> secretName = string<br/> repository = string<br/> encryptedValue = string<br/> })), {})<br/><br/> dependabot = optional(map(object({<br/> secretName = string<br/> repository = string<br/> encryptedValue = string<br/> })), {})<br/> })</pre> | n/a | yes | | ||
|
|
||
| ## Outputs | ||
|
|
||
| | Name | Description | | ||
| |------|-------------| | ||
| | <a name="output_actions_secrets"></a> [actions\_secrets](#output\_actions\_secrets) | List of Action secrets created | | ||
| | <a name="output_all_secret_names"></a> [all\_secret\_names](#output\_all\_secret\_names) | Combined list of all secret names | | ||
| | <a name="output_codespaces_secrets"></a> [codespaces\_secrets](#output\_codespaces\_secrets) | List of Codespaces secrets created | | ||
| | <a name="output_dependabot_secrets"></a> [dependabot\_secrets](#output\_dependabot\_secrets) | List of Dependabot secrets created | | ||
|
|
||
| ### 3. `docs/footer.md` | ||
| ```markdown | ||
| ## Examples | ||
|
|
||
| For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-repository-secrets/_examples): | ||
|
|
||
| - [basic](https://github.com/prefapp/tfm/tree/main/modules/github-repository-secrets/_examples/basic) - Full example with Actions, Codespaces, and Dependabot secrets | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Resources | ||
|
|
||
| - **github_actions_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | ||
| - **github_codespaces_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/codespaces_secret) | ||
| - **github_dependabot_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/dependabot_secret) | ||
| - **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). | ||
|
|
||
| ``` | ||
| <!-- END_TF_DOCS --> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| module "repo_secrets" { | ||
| source = "git::https://github.com/prefapp/tfm.git//modules/github-repository-secrets" | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| config = var.config # Terraform automatically loads terraform.tfvars.json | ||
| } | ||
|
Comment on lines
+1
to
+5
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { | ||
| "config": { | ||
| "actions": { | ||
|
Comment on lines
+1
to
+4
|
||
| "SECRET_A": { | ||
| "secretName": "SECRET_A", | ||
| "repository": "component_a", | ||
| "encryptedValue": "r+RFBGIn8U7z2Opm5RN7PXKdgFzefXiV91IpG3O2DrClZl9dkTJBfhRZbi2uV2nu4ijn5yUfZ9O1eqjaXL2dWByFV+T2swZCQVQdDGmDlF24MPvEFh2ZbQ==" | ||
| }, | ||
| "SECRET_B": { | ||
| "secretName": "SECRET_B", | ||
| "repository": "component_a", | ||
| "encryptedValue": "MkLxMAQDhWu0HotjWvNDzyquGJyCxf+n/Qh+eLtDi+Ci0U+M5CCYYLabH6Y0/+sx5aksP+PJPM9PxIYQImx82lOcy1MJ08Fi+JCtT2l2CixOP19McNu7XQ==" | ||
| } | ||
| }, | ||
| "codespaces": { | ||
| "SECRET_C": { | ||
| "secretName": "SECRET_C", | ||
| "repository": "component_a", | ||
| "encryptedValue": "rJ0H0YfnvedPtMOD0Ete+Pl802OQXa8e7Ia6lbfeTEnIiFRnqjc3XMPGxk7VC8yMeM2znStVAP2eeI97XrfMzvM/N/289g8ZElsCXlLesn4JXY2+chmcCQ==" | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| }, | ||
| "dependabot": {} | ||
| } | ||
| } | ||
|
Comment on lines
+1
to
+14
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
|
|
||
| ### 3. `docs/footer.md` | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ```markdown | ||
| ## Examples | ||
|
|
||
| For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-repository-secrets/_examples): | ||
|
|
||
| - [basic](https://github.com/prefapp/tfm/tree/main/modules/github-repository-secrets/_examples/basic) - Full example with Actions, Codespaces, and Dependabot secrets | ||
|
|
||
| ## Resources | ||
|
|
||
| - **github_actions_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | ||
| - **github_codespaces_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/codespaces_secret) | ||
| - **github_dependabot_secret**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/dependabot_secret) | ||
| - **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). | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # **GitHub Repository Secrets Terraform Module** | ||
|
|
||
| ## Overview | ||
|
|
||
| This module manages GitHub repository secrets for **Actions**, **Codespaces**, and **Dependabot** using a single strongly-typed `config` object. | ||
|
|
||
| **Important**: | ||
| The `encryptedValue` values passed in the `config` **must already be encrypted** using **libsodium** against the target repository’s public key (GitHub’s recommended method). | ||
| **Terraform does not perform any encryption**. It simply forwards the pre-encrypted value to the GitHub API. | ||
|
|
||
| This approach is the most secure for automated pipelines (Prefapp IDP, GitHub Actions, etc.). | ||
|
|
||
| ## Key Features | ||
|
|
||
| - **Single complex object**: All secrets are defined in one `config` variable. | ||
| - **Pre-encrypted values**: `encryptedValue` must be provided already encrypted with libsodium. | ||
| - **Three secret types**: Actions, Codespaces, and Dependabot supported in the same module. | ||
| - **Lifecycle protection**: `ignore_changes` on `encrypted_value` to prevent unnecessary drift. | ||
| - **Full validation**: Enforces required fields and non-empty values. | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - **JSON-native**: Works seamlessly with `terraform.tfvars.json` generated by external programs. | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| ### Using `terraform.tfvars.json` (recommended) | ||
|
|
||
frmadem marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ```hcl | ||
| module "repo_secrets" { | ||
| source = "git::https://github.com/prefapp/tfm.git//modules/github-repository-secrets" | ||
|
|
||
| config = var.config # Terraform automatically loads terraform.tfvars.json | ||
| } | ||
|
|
||
| ### Inline example | ||
|
|
||
| ```hcl | ||
| module "repo_secrets" { | ||
| source = "git::https://github.com/prefapp/tfm.git//modules/github-repository-secrets" | ||
|
|
||
| config = { | ||
| actions = { | ||
| SECRET_A = { | ||
| secretName = "SECRET_A" | ||
| repository = "component_a" | ||
| encryptedValue = "r+RFBGIn8U7z2Opm5RN7PXKdgFzefXiV91IpG3O2DrClZl9dkTJBfhRZbi2uV2nu4ijn5yUfZ9O1eqjaXL2dWByFV+T2swZCQVQdDGmDlF24MPvEFh2ZbQ==" | ||
| } | ||
| } | ||
| codespaces = {} | ||
| dependabot = {} | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # ───────────────────────────────────────────────────────────── | ||
| # GitHub Actions Secrets | ||
| # encrypted_value is ALREADY libsodium-encrypted against the repo public key | ||
| # Terraform does NOT perform any encryption | ||
| # ───────────────────────────────────────────────────────────── | ||
| resource "github_actions_secret" "this" { | ||
| for_each = var.config.actions | ||
|
|
||
| repository = each.value.repository | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| secret_name = each.value.secretName | ||
| encrypted_value = each.value.encryptedValue | ||
|
|
||
| lifecycle { | ||
| ignore_changes = ["encrypted_value"] | ||
| } | ||
frmadem marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+16
to
+20
|
||
| } | ||
|
|
||
| # ───────────────────────────────────────────────────────────── | ||
| # GitHub Codespaces Secrets | ||
| # encrypted_value is ALREADY libsodium-encrypted against the repo public key | ||
| # Terraform does NOT perform any encryption | ||
| # ───────────────────────────────────────────────────────────── | ||
| resource "github_codespaces_secret" "this" { | ||
| for_each = var.config.codespaces | ||
|
|
||
| repository = each.value.repository | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| secret_name = each.value.secretName | ||
| encrypted_value = each.value.encryptedValue | ||
|
|
||
| lifecycle { | ||
| ignore_changes = ["encrypted_value"] | ||
| } | ||
frmadem marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| # ───────────────────────────────────────────────────────────── | ||
| # GitHub Dependabot Secrets | ||
| # encrypted_value is ALREADY libsodium-encrypted against the repo public key | ||
| # Terraform does NOT perform any encryption | ||
| # ───────────────────────────────────────────────────────────── | ||
| resource "github_dependabot_secret" "this" { | ||
| for_each = var.config.dependabot | ||
|
|
||
| repository = each.value.repository | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| secret_name = each.value.secretName | ||
| encrypted_value = each.value.encryptedValue | ||
|
|
||
| lifecycle { | ||
| ignore_changes = ["encrypted_value"] | ||
| } | ||
frmadem marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| output "actions_secrets" { | ||
| description = "List of Action secrets created" | ||
| value = [for k, v in var.config.actions : v.secretName] | ||
| } | ||
|
|
||
| output "codespaces_secrets" { | ||
| description = "List of Codespaces secrets created" | ||
| value = [for k, v in var.config.codespaces : v.secretName] | ||
| } | ||
|
|
||
| output "dependabot_secrets" { | ||
| description = "List of Dependabot secrets created" | ||
| value = [for k, v in var.config.dependabot : v.secretName] | ||
| } | ||
|
|
||
| output "all_secret_names" { | ||
| description = "Combined list of all secret names" | ||
| value = concat( | ||
| [for v in var.config.actions : v.secretName], | ||
| [for v in var.config.codespaces : v.secretName], | ||
| [for v in var.config.dependabot : v.secretName] | ||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| variable "config" { | ||
| description = <<EOT | ||
| GitHub repository secrets configuration as a single complex object. | ||
|
|
||
| IMPORTANT: | ||
| - encryptedValue must be ALREADY encrypted with libsodium using the target repository's public key. | ||
| - Terraform does NOT encrypt anything — it only passes the pre-encrypted value. | ||
| EOT | ||
|
|
||
| type = object({ | ||
| actions = optional(map(object({ | ||
| secretName = string | ||
| repository = string | ||
| encryptedValue = string | ||
| })), {}) | ||
|
|
||
| codespaces = optional(map(object({ | ||
| secretName = string | ||
| repository = string | ||
| encryptedValue = string | ||
| })), {}) | ||
|
|
||
| dependabot = optional(map(object({ | ||
| secretName = string | ||
| repository = string | ||
| encryptedValue = string | ||
| })), {}) | ||
| }) | ||
|
|
||
| # validation { | ||
| # condition = length(var.config.actions) + length(var.config.codespaces) + length(var.config.dependabot) > 0 | ||
| # error_message = "At least one secret must be defined in actions, codespaces or dependabot." | ||
| # } | ||
|
|
||
frmadem marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| validation { | ||
| condition = alltrue([ | ||
| for k, v in var.config.actions : length(trimspace(v.secretName)) > 0 && length(trimspace(v.repository)) > 0 | ||
| ]) | ||
| error_message = "Every action secret must have non-empty secretName and repository." | ||
| } | ||
|
|
||
| validation { | ||
| condition = alltrue([ | ||
| for k, v in var.config.codespaces : length(trimspace(v.secretName)) > 0 && length(trimspace(v.repository)) > 0 | ||
| ]) | ||
| error_message = "Every codespaces secret must have non-empty secretName and repository." | ||
| } | ||
|
|
||
| validation { | ||
| condition = alltrue([ | ||
| for k, v in var.config.dependabot : length(trimspace(v.secretName)) > 0 && length(trimspace(v.repository)) > 0 | ||
| ]) | ||
| error_message = "Every dependabot secret must have non-empty secretName and repository." | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
README refers to
encryptedValueand claims “Full validation…non-empty values”, but the module usesencrypted_valuestrings in the maps and does not validate non-empty secret values. Please update the README to match the actual input schema (or implement the validations described).