From b6a5ae514a932278e07294f35b537fd585023e36 Mon Sep 17 00:00:00 2001 From: NWarila <33955773+NWarila@users.noreply.github.com> Date: Mon, 3 Aug 2026 01:00:04 +0000 Subject: [PATCH] docs: repair Terraform reference drift --- docs/explanation/tech-debt.md | 22 ++++++++++++++++++++++ docs/how-to/develop-this-module.md | 5 +++-- docs/reference/terraform.md | 19 ++++++++++++------- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/docs/explanation/tech-debt.md b/docs/explanation/tech-debt.md index 24c94f3..3669c65 100644 --- a/docs/explanation/tech-debt.md +++ b/docs/explanation/tech-debt.md @@ -156,3 +156,25 @@ available, so the hole reopens for any repository that sets it `true`. **What would close it:** a validation rule rejecting `verified_allowed: true` outright, if the ergonomic cost is acceptable. + +--- + +## TD-7 — Generated Terraform reference drift is not gated here + +**Status:** accepted for now; tracked for a dedicated follow-up. + +This repository's CI runs neither `make ci` nor `make docs-diff`. Changes to +Terraform can therefore leave the generated reference stale while framework CI +remains green. The drift becomes visible only when a consumer runs the full +`make ci`, where `docs-diff` fails. + +The gap is accepted temporarily because changing framework PR gating has its own +blast radius and is being handled separately from repairing the current drift. +Consumers still detect the mismatch, but only after it has escaped this +repository's checks. + +**What would close it:** add a docs-only framework PR gate that installs +checksum-verified `terraform-docs` 0.23.0 and runs `make docs-diff`. + +**How it would be noticed:** a downstream consumer's `make ci` fails at +`docs-diff`, or a maintainer runs `make docs-diff` locally. diff --git a/docs/how-to/develop-this-module.md b/docs/how-to/develop-this-module.md index 90f0242..600bccc 100644 --- a/docs/how-to/develop-this-module.md +++ b/docs/how-to/develop-this-module.md @@ -24,5 +24,6 @@ make docs # regenerate docs/reference/terraform.md make ci ``` -If `make ci` is green locally, it is aligned with the Terraform test workflow -in CI. +Local `make ci` is broader than the Terraform test workflow in CI: the hosted +workflow runs `fmt-check`, `init`, `validate`, and `test`, but not the other six +gates, including `docs-diff`. diff --git a/docs/reference/terraform.md b/docs/reference/terraform.md index 20264bb..f03f3da 100644 --- a/docs/reference/terraform.md +++ b/docs/reference/terraform.md @@ -1,18 +1,19 @@ # Terraform Reference -This file is overwritten by `terraform-docs` on every PR via the -`docs-diff` gate. Do not edit by hand between the markers below. +This file is generated by `make docs`; `make docs-diff` only checks whether it +is current. Framework PR workflows do not run that check today; only consumers do. ## Resources | Name | Type | -|------|------| +| ---- | ---- | | [github_actions_environment_secret.env_secret](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/actions_environment_secret) | resource | | [github_actions_environment_variable.env_var](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/actions_environment_variable) | resource | | [github_actions_repository_permissions.actions](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/actions_repository_permissions) | resource | | [github_branch.branches](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/branch) | resource | | [github_branch_default.default](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/branch_default) | resource | +| [github_organization_settings.org](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/organization_settings) | resource | | [github_repository.repo](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/repository) | resource | | [github_repository_environment.environment](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/repository_environment) | resource | | [github_repository_environment_deployment_policy.environment](https://registry.terraform.io/providers/integrations/github/6.12.1/docs/resources/repository_environment_deployment_policy) | resource | @@ -24,25 +25,29 @@ This file is overwritten by `terraform-docs` on every PR via the ## Inputs | Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| +| ---- | ----------- | ---- | ------- | :------: | | github\_app\_auth | GitHub App authentication config. Required when github\_auth\_mode = 'app'. Must be null when github\_auth\_mode = 'token'. pem\_file accepts PEM contents as a string. |
object({
id = string
installation_id = string
pem_file = string
})
| `null` | no | | github\_auth\_mode | Provider authentication mode. Must be either 'app' (GitHub App installation, preferred) or 'token' (classic or fine-grained PAT, break-glass only). | `string` | `"token"` | no | | github\_is\_organization | Whether the github\_owner is an organization (true) or personal account (false). Controls org-only features and CODEOWNERS synthesis behavior. | `bool` | `false` | no | | github\_owner | GitHub organization or user account name | `string` | n/a | yes | -| github\_security\_capabilities | Declaration of which GitHub security\_and\_analysis features the current owner/plan supports, keyed by repository visibility. Fully-required matrix (no optional fields): operators must declare every feature for every visibility to keep the capability contract explicit and auditable. Setting a feature to false means the owner/plan does not have entitlement to enable it on that visibility. If a specific repository must omit a feature despite the matrix, set unmanaged\_security\_features in that repo YAML. |
object({
public = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
private = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
internal = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
})
|
{
"internal": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": true
},
"private": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": true
},
"public": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": true
}
}
| no | +| github\_security\_capabilities | Baseline-path capability matrix for GitHub security\_and\_analysis features, keyed by repository visibility. This gates only baseline enablement; an explicit repository YAML true intentionally bypasses a false capability as the sanctioned, PR-reviewed opt-in. Private/internal secret scanning and push protection are paid Secret Protection features. |
object({
public = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
private = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
internal = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
})
|
{
"internal": {
"advanced_security": false,
"code_security": false,
"secret_scanning": false,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": false
},
"private": {
"advanced_security": false,
"code_security": false,
"secret_scanning": false,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": false
},
"public": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": true
}
}
| no | | github\_supports\_push\_rulesets | Whether the current GitHub owner and plan support push rulesets. GitHub currently limits them to Team-plan internal/private repositories and their forks. | `bool` | `false` | no | | github\_token | GitHub Personal Access Token for authentication. Required when github\_auth\_mode = 'token'. Must be null when github\_auth\_mode = 'app'. | `string` | `null` | no | +| org\_billing\_email | Billing email required by the GitHub API when organization settings are managed. Source this value from a GitHub Actions secret. | `string` | `null` | no | +| org\_settings | Organization settings to manage. Null leaves organization settings unmanaged. Profile strings must match live values because the GitHub provider cannot clear non-empty strings. |
object({
name = string
description = optional(string, "")
company = optional(string, "")
blog = optional(string, "")
email = optional(string, "")
location = optional(string, "")
twitter_username = optional(string, "")
default_repository_permission = optional(string, "read")
members_can_create_repositories = optional(bool, false)
members_can_create_public_repositories = optional(bool, false)
members_can_create_private_repositories = optional(bool, false)
members_can_create_internal_repositories = optional(bool, false)
members_can_create_pages = optional(bool, false)
members_can_create_public_pages = optional(bool, false)
members_can_create_private_pages = optional(bool, false)
members_can_fork_private_repositories = optional(bool, false)
has_organization_projects = optional(bool, false)
has_repository_projects = optional(bool, false)
web_commit_signoff_required = optional(bool, true)
security_defaults_for_new_repositories = optional(object({
advanced_security = optional(bool, false)
secret_scanning = optional(bool, false)
secret_scanning_push_protection = optional(bool, false)
dependabot_alerts = optional(bool, false)
dependabot_security_updates = optional(bool, false)
dependency_graph = optional(bool, false)
}), {})
})
| `null` | no | | repo\_default\_branches | Default branch list applied when a repo YAML does not explicitly define branches. | `list(string)` |
[
"main"
]
| no | | repo\_default\_codeowners | Global CODEOWNERS default honored in both organization and personal-account modes. A per-repository 'codeowners' value overrides it. Empty or whitespace-only values are treated as unset; in organization mode, code owners must name a user or team, not the bare organization. | `string` | `null` | no | | repo\_default\_rules | Default repository rulesets applied when a repo YAML does not explicitly define rules. |
list(
object({
name = optional(string)
target = optional(string)
enforcement = optional(string)

bypass_actors = optional(
list(
object({
actor_id = number
actor_type = string
bypass_mode = optional(string)
})
),
[]
)

conditions = optional(
object({
include = list(string)
exclude = optional(list(string), [])
})
)

rules = object({
creation = optional(bool)
update = optional(bool)
deletion = optional(bool)
non_fast_forward = optional(bool)
required_linear_history = optional(bool)
required_signatures = optional(bool)

pull_request = optional(
object({
allowed_merge_methods = list(string)
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)
})
)

copilot_code_review = optional(
object({
review_on_push = optional(bool)
review_draft_pull_requests = optional(bool)
})
)

required_status_checks = optional(
object({
required_check = optional(
list(
object({
context = string
integration_id = optional(number)
})
),
[]
)

do_not_enforce_on_create = optional(bool)
strict_required_status_checks_policy = optional(bool)
})
)

required_deployments = optional(
object({
required_deployment_environments = list(string)
})
)

required_code_scanning = optional(
object({
required_code_scanning_tool = list(
object({
tool = string
alerts_threshold = optional(string)
security_alerts_threshold = optional(string)
})
)
})
)

merge_queue = optional(
object({
check_response_timeout_minutes = optional(number)
grouping_strategy = optional(string)
max_entries_to_build = optional(number)
max_entries_to_merge = optional(number)
merge_method = optional(string)
min_entries_to_merge = optional(number)
min_entries_to_merge_wait_minutes = optional(number)
})
)

branch_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)
})
)

committer_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)
})
)

tag_name_pattern = optional(
object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
})
)

update_allows_fetch_and_merge = optional(bool)

file_path_restriction = optional(
object({
restricted_file_paths = list(string)
})
)

file_extension_restriction = optional(
object({
restricted_file_extensions = list(string)
})
)

max_file_size = optional(
object({
max_file_size = number
})
)

max_file_path_length = optional(
object({
max_file_path_length = number
})
)
})
})
)
|
[
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
],
"conditions": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
},
"enforcement": "active",
"name": "Branch Safety",
"rules": {
"creation": true,
"deletion": true,
"non_fast_forward": true,
"required_linear_history": true,
"required_signatures": true,
"update": true
},
"target": "branch"
},
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
],
"conditions": {
"exclude": [],
"include": [
"~DEFAULT_BRANCH"
]
},
"enforcement": "active",
"name": "Pull Request Gate",
"rules": {
"pull_request": {
"allowed_merge_methods": [
"squash"
],
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": true,
"require_last_push_approval": true,
"required_approving_review_count": 1,
"required_review_thread_resolution": true
}
},
"target": "branch"
},
{
"bypass_actors": [
{
"actor_id": 5,
"actor_type": "RepositoryRole",
"bypass_mode": "always"
}
],
"conditions": {
"exclude": [],
"include": [
"~ALL"
]
},
"enforcement": "active",
"name": "Release Tag Protection",
"rules": {
"deletion": true,
"non_fast_forward": true,
"required_signatures": true
},
"target": "tag"
}
]
| no | | repo\_yaml\_path | Path (relative to the module root) containing the repos/ tree to ingest. Default 'repos' matches the production layout. Overridden by terraform test runs to point at fixture directories under tests/fixtures/. | `string` | `"repos"` | no | -| security\_baseline | Desired security\_and\_analysis baseline the framework should enforce when the owner's github\_security\_capabilities allow it, keyed by visibility. Fully-required matrix. A feature set to true means 'enable this wherever capabilities permit'; false means 'leave this feature unmanaged (do not enable)'. Explicit per-repo security\_and\_analysis YAML still overrides this baseline; per-repo unmanaged\_security\_features overrides both and emits null so the provider omits the feature. |
object({
public = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
private = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
internal = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
})
|
{
"internal": {
"advanced_security": true,
"code_security": true,
"secret_scanning": true,
"secret_scanning_ai_detection": true,
"secret_scanning_non_provider_patterns": true,
"secret_scanning_push_protection": true
},
"private": {
"advanced_security": true,
"code_security": true,
"secret_scanning": true,
"secret_scanning_ai_detection": true,
"secret_scanning_non_provider_patterns": true,
"secret_scanning_push_protection": true
},
"public": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": true,
"secret_scanning_non_provider_patterns": true,
"secret_scanning_push_protection": true
}
}
| no | +| security\_baseline | Desired security\_and\_analysis baseline the framework should enforce when the owner's github\_security\_capabilities allow it, keyed by visibility. Fully-required matrix. A feature set to true means 'enable this wherever capabilities permit'; false means 'leave this feature unmanaged (do not enable)'. Explicit per-repo security\_and\_analysis YAML still overrides this baseline; per-repo unmanaged\_security\_features overrides both and emits null so the provider omits the feature. |
object({
public = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
private = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
internal = object({
advanced_security = bool
code_security = bool
secret_scanning = bool
secret_scanning_push_protection = bool
secret_scanning_ai_detection = bool
secret_scanning_non_provider_patterns = bool
})
})
|
{
"internal": {
"advanced_security": false,
"code_security": false,
"secret_scanning": false,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": false
},
"private": {
"advanced_security": false,
"code_security": false,
"secret_scanning": false,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": false
},
"public": {
"advanced_security": false,
"code_security": false,
"secret_scanning": true,
"secret_scanning_ai_detection": false,
"secret_scanning_non_provider_patterns": false,
"secret_scanning_push_protection": true
}
}
| no | | security\_baseline\_mode | Controls how the framework reconciles repo security\_and\_analysis against github\_security\_capabilities. 'strict' fails plan when a required baseline setting exceeds declared capabilities. 'compatibility' emits an advisory preview via a check block and leaves unsupported settings unset. Default is 'compatibility' to allow non-breaking rollout; flip to 'strict' in the next tagged release. | `string` | `"compatibility"` | no | +| security\_default\_status | Fallback for security features not resolved by unmanaged/excluded, explicit YAML, or enabled baseline: 'disabled' manages them as false; 'unmanaged' emits null. Explicit YAML and unmanaged\_security\_features retain higher precedence. | `string` | `"disabled"` | no | +| security\_pin\_exclude | Fleet-wide security feature names to omit (null), after per-repo unmanaged features and before explicit YAML. Unknown names are rejected by framework validation. | `list(string)` | `[]` | no | ## Outputs | Name | Description | -|------|-------------| +| ---- | ----------- | | all\_repositories | Computed repository map. Non-sensitive so terraform test assertions can inspect normalized values. | | branch\_rulesets | Computed branch rulesets map. Non-sensitive so terraform test assertions can inspect ruleset counts and values. | | locals\_debug | All computed locals for debugging. Marked sensitive to prevent exposure in CI/CD logs. |