From 5296567c12c8188413fde034efe148b55bdbcda3 Mon Sep 17 00:00:00 2001 From: xnoto Date: Fri, 21 Aug 2026 09:26:48 -0600 Subject: [PATCH 1/2] feat: manage dependabot config via OpenTofu and document branch protection posture - add gh-dependabot.tf generating .github/dependabot.yml for all active repositories via github_repository_file (github-actions everywhere, terraform for OpenTofu roots, docker for images, pip for cflan) - document the intentional branch-protection relaxation for this solo-maintainer personal-dev organization - document dependabot management and repository_file import ID format in AGENTS.md --- AGENTS.md | 20 ++++++++++++++ README.md | 1 + gh-dependabot.tf | 67 +++++++++++++++++++++++++++++++++++++++++++++++ gh-protections.tf | 6 +++++ 4 files changed, 94 insertions(+) create mode 100644 gh-dependabot.tf diff --git a/AGENTS.md b/AGENTS.md index 7273b28..dd92037 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,6 +11,15 @@ Use a feature branch and open a pull request rather than pushing directly to environment gates approve it. Do not push any branch unless explicitly requested. +## Branch Protection + +Branch protection on `main` is intentionally relaxed for this solo-maintainer, +personal-dev organization: no required status check contexts and zero required +approving reviews (see the comment in `gh-protections.tf`). PRs are used for CI +validation, plan output, and change history, not as a review gate. Do not +tighten `contexts` or `required_approving_review_count` unless explicitly +requested. + ## Pre-commit Configuration Pre-commit configuration is centralized at @@ -40,6 +49,16 @@ tracked copy. **Pre-commit failures:** If hooks fail unexpectedly, the canonical config may have changed. Re-run `make test` to refresh it and run the checks. +## Dependency Updates + +Dependabot version updates are managed here in `gh-dependabot.tf` via +`github_repository_file` resources, so all active repositories receive their +`.github/dependabot.yml` from one place. To change update policy, edit the +`dependabot_ecosystems` map; do not hand-edit `.github/dependabot.yml` in +downstream repositories. Pre-commit hook revisions are not covered by +Dependabot: they are owned by the canonical config in +`images/tfroot-runner/pre-commit-config.yaml`. + ## Related Repositories - `images` - Contains tfroot-runner image and canonical pre-commit config @@ -53,3 +72,4 @@ objects: - repositories: `` - `main` branch protections: `:main` - Actions secrets: `/` +- repository files: `/` (append `:` for non-default branches) diff --git a/README.md b/README.md index 0a622ed..d2447b7 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ No modules. | [github_branch_protection.protections](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection) | resource | | [github_membership.admin](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership) | resource | | [github_repository.repositories](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository) | resource | +| [github_repository_file.dependabot](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_file) | resource | | [github_team.admins](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team) | resource | | [github_team.developers](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team) | resource | | [github_team_membership.admins_xnoto](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership) | resource | diff --git a/gh-dependabot.tf b/gh-dependabot.tf new file mode 100644 index 0000000..05d1509 --- /dev/null +++ b/gh-dependabot.tf @@ -0,0 +1,67 @@ +# Dependabot version updates are managed centrally here so every active +# repository receives the same `.github/dependabot.yml` policy. Do not add +# hand-maintained dependabot configs to downstream repositories. +# +# Deliberately not covered: +# - pre-commit hook revisions: owned by images/tfroot-runner/pre-commit-config.yaml +# - tool ARG pins in images/*/Containerfile: Dependabot only updates FROM tags +# - Kubernetes image tags in kustomize-cluster: no Dependabot ecosystem exists + +locals { + dependabot_ecosystems = { + ".github" = ["github-actions"] + "cflan" = ["github-actions", "pip"] + "images" = ["github-actions", "docker"] + "kustomize-cluster" = ["github-actions"] + "shared-workflows" = ["github-actions"] + "terraform-libvirt-domain" = ["github-actions", "terraform"] + "tfroot-aws" = ["github-actions", "terraform"] + "tfroot-cloudflare" = ["github-actions", "terraform"] + "tfroot-github" = ["github-actions", "terraform"] + "tfroot-libvirt" = ["github-actions", "terraform"] + "www" = ["github-actions"] + } + dependabot_docker_directories = ["gh-cli", "tfroot-runner"] + + dependabot_configs = { + for repo, ecosystems in local.dependabot_ecosystems : repo => { + version = 2 + updates = concat( + [for ecosystem in ecosystems : { + package-ecosystem = ecosystem + directory = "/" + schedule = { + interval = "weekly" + } + groups = { + (ecosystem) = { + patterns = ["*"] + } + } + } if ecosystem != "docker"], + [for directory in local.dependabot_docker_directories : { + package-ecosystem = "docker" + directory = "/${directory}" + schedule = { + interval = "weekly" + } + groups = { + docker = { + patterns = ["*"] + } + } + } if contains(ecosystems, "docker")] + ) + } + } +} + +resource "github_repository_file" "dependabot" { + for_each = local.dependabot_configs + + repository = github_repository.repositories[each.key].name + file = ".github/dependabot.yml" + content = "# Managed by tfroot-github (gh-dependabot.tf); local edits are overwritten.\n${yamlencode(each.value)}" + commit_message = "chore: sync managed dependabot configuration" + overwrite_on_create = true +} diff --git a/gh-protections.tf b/gh-protections.tf index e3d4b7e..10a8d1d 100644 --- a/gh-protections.tf +++ b/gh-protections.tf @@ -1,3 +1,9 @@ +# Branch protection here is intentionally relaxed for a solo-maintainer, +# personal-dev organization: `contexts` is empty (CI is advisory, not a merge +# gate) and `required_approving_review_count` is zero. The PR workflow exists +# for CI validation, plan output, and change history — not review ceremony. +# If collaborators join or a repo gains external contributors, tighten +# `contexts` and `required_approving_review_count` at that time. resource "github_branch_protection" "protections" { for_each = toset([for repo in local.github_repositories : repo if !contains(local.archived_github_repositories, repo)]) repository_id = github_repository.repositories[each.key].node_id From 5a460e711ee6d987d70a59b8db0927d13185ad7f Mon Sep 17 00:00:00 2001 From: xnoto Date: Fri, 21 Aug 2026 09:34:18 -0600 Subject: [PATCH 2/2] fix: use dedicated opentofu dependabot ecosystem GitHub shipped a native opentofu package-ecosystem on 2025-12-16. Using terraform for OpenTofu repos was the pre-GA workaround and has known issues with OpenTofu >= 1.8. Also documents that lock files are not git-tracked here, so only .tf version constraints are bumped. --- gh-dependabot.tf | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gh-dependabot.tf b/gh-dependabot.tf index 05d1509..b88b011 100644 --- a/gh-dependabot.tf +++ b/gh-dependabot.tf @@ -2,6 +2,10 @@ # repository receives the same `.github/dependabot.yml` policy. Do not add # hand-maintained dependabot configs to downstream repositories. # +# OpenTofu roots use the dedicated `opentofu` ecosystem (GA since 2025-12-16), +# not `terraform`. Lock files are not git-tracked in these repos, so only +# version constraints in .tf files are bumped. +# # Deliberately not covered: # - pre-commit hook revisions: owned by images/tfroot-runner/pre-commit-config.yaml # - tool ARG pins in images/*/Containerfile: Dependabot only updates FROM tags @@ -14,11 +18,11 @@ locals { "images" = ["github-actions", "docker"] "kustomize-cluster" = ["github-actions"] "shared-workflows" = ["github-actions"] - "terraform-libvirt-domain" = ["github-actions", "terraform"] - "tfroot-aws" = ["github-actions", "terraform"] - "tfroot-cloudflare" = ["github-actions", "terraform"] - "tfroot-github" = ["github-actions", "terraform"] - "tfroot-libvirt" = ["github-actions", "terraform"] + "terraform-libvirt-domain" = ["github-actions", "opentofu"] + "tfroot-aws" = ["github-actions", "opentofu"] + "tfroot-cloudflare" = ["github-actions", "opentofu"] + "tfroot-github" = ["github-actions", "opentofu"] + "tfroot-libvirt" = ["github-actions", "opentofu"] "www" = ["github-actions"] } dependabot_docker_directories = ["gh-cli", "tfroot-runner"]