From 6284d885bb7b602d05aa74b20ee7f0194dc29345 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Sun, 30 Aug 2026 12:36:34 -0600 Subject: [PATCH 1/3] feat: allow auto-merge on kustomize-cluster for chart pin PRs Enable GitHub auto-merge on kustomize-cluster so the charts post-publish workflow can flag its generated opencode-server pin pull request for automatic squash merge once the required `test` check passes. Other repositories keep auto-merge disabled. Update the chart updater runbook for the auto-merge behavior and record that this root owns repository merge settings, including the auto-merge allowlist. --- docs/chart-updater-github-app.md | 14 +++++++++----- gh-repositories.tf | 3 +++ main.tf | 16 ++++++++++++---- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/chart-updater-github-app.md b/docs/chart-updater-github-app.md index d0e51eb..8acf200 100644 --- a/docs/chart-updater-github-app.md +++ b/docs/chart-updater-github-app.md @@ -10,8 +10,9 @@ The [charts workflow](https://github.com/makeitworkcloud/charts/blob/main/.githu publishes an immutable `opencode-server` chart release and uses a short-lived GitHub App installation token to update the [GitOps chart reference](https://github.com/makeitworkcloud/kustomize-cluster/blob/main/workloads/apps/opencode-app.yaml). -The workflow opens a pull request; it does not sync Argo CD or deploy the -release. +The workflow opens a pull request and enables GitHub auto-merge on it, so the +pull request squash-merges once the destination's required checks pass. The +workflow does not sync Argo CD or deploy the release directly. The current source repository, destination repository, App ID, Actions secret name, and token repository request are defined in the charts workflow and in @@ -32,6 +33,7 @@ approved cleanup after the agreed rollback window. | GitHub App creation, permissions, keys, and organization installation | Organization owners manage these manually in GitHub. This root does not Terraform-manage the App or its installation. | | Encrypted private key and Actions secret recipients | This root owns the SOPS-backed value and recipient list in [`main.tf`](../main.tf), using the encryption policy in [`.sops.yaml`](../.sops.yaml). | | Actions secret distribution | [`gh-secrets.tf`](../gh-secrets.tf) writes the configured repository secret. It cannot create or configure a GitHub App. | +| Repository merge settings and branch protections | This root owns them in [`gh-repositories.tf`](../gh-repositories.tf) and [`gh-protections.tf`](../gh-protections.tf), including which repositories allow auto-merge. | | Chart publication and updater token request | The [charts workflow](https://github.com/makeitworkcloud/charts/blob/main/.github/workflows/helm.yml) owns the App ID reference, requested repositories, requested token permissions, and pull-request automation. | | Desired deployment state and rollout | `kustomize-cluster` owns the GitOps reference. Follow its [rollout and rollback guide](https://github.com/makeitworkcloud/kustomize-cluster/blob/main/docs/rollout-and-rollback.md). | @@ -157,8 +159,9 @@ chart versions are immutable. 5. Verify the generated pull request is authored through the App, changes only the intended GitOps chart reference, and pins `targetRevision` to the newly published immutable version. -6. Treat the generated pull request as the credential smoke test. Review and - roll it out separately using the `kustomize-cluster` [rollout and rollback +6. Treat the generated pull request as the credential smoke test. It merges + automatically once the destination's required checks pass; verify the + rollout separately using the `kustomize-cluster` [rollout and rollback guide](https://github.com/makeitworkcloud/kustomize-cluster/blob/main/docs/rollout-and-rollback.md). The updater must not sync Argo CD or deploy directly. 7. Delete the old App key only after the new key has passed this smoke test and @@ -187,7 +190,8 @@ Adding a source broadens private-key distribution and requires explicit review. 1. Decide separately whether this root should Terraform-manage the repository. If so, update the managed repository and required-check maps in - [`main.tf`](../main.tf). + [`main.tf`](../main.tf), and decide whether the destination belongs in + `local.auto_merge_github_repositories`. 2. Add the destination to the App's organization installation using **Only select repositories**. This is a manual organization-owner action. 3. Add the destination to the source workflow's `repositories` token request diff --git a/gh-repositories.tf b/gh-repositories.tf index 9ce2d94..599402e 100644 --- a/gh-repositories.tf +++ b/gh-repositories.tf @@ -7,6 +7,9 @@ resource "github_repository" "repositories" { allow_squash_merge = true allow_merge_commit = true allow_rebase_merge = false + # Auto-merge stays off except for repositories whose automation-created pull + # requests are expected to merge themselves once required checks pass. + allow_auto_merge = contains(local.auto_merge_github_repositories, each.key) delete_branch_on_merge = true squash_merge_commit_title = "PR_TITLE" squash_merge_commit_message = "PR_BODY" diff --git a/main.tf b/main.tf index 992dbe5..225b90f 100644 --- a/main.tf +++ b/main.tf @@ -34,6 +34,14 @@ locals { relaxed_branch_protection_github_repositories = toset([ "agent-knowledge" ]) + # Repositories where automation-created pull requests merge themselves once + # required checks pass. GitHub auto-merge is enabled only for these + # repositories (see gh-repositories.tf). kustomize-cluster receives the + # charts post-publish opencode-server pin pull request, which merges after + # its required `test` check passes. + auto_merge_github_repositories = toset([ + "kustomize-cluster" + ]) active_github_repositories = toset([ for repo in local.github_repositories : repo if !contains(local.archived_github_repositories, repo) @@ -67,12 +75,12 @@ locals { } "onion_access_key_id" = { name = "ONION_AWS_ACCESS_KEY_ID" - value = data.sops_file.secret_vars.data["onion_aws_access_key_id"] + value = data.sops_file.secret_vars.data["onion_access_key_id"] repositories = ["www"] } "onion_secret_access_key" = { name = "ONION_AWS_SECRET_ACCESS_KEY" - value = data.sops_file.secret_vars.data["onion_aws_secret_access_key"] + value = data.sops_file.secret_vars.data["onion_secret_access_key"] repositories = ["www"] } "www_s3_bucket" = { @@ -87,12 +95,12 @@ locals { } "www_access_key_id" = { name = "AWS_ACCESS_KEY_ID" - value = data.sops_file.secret_vars.data["www_aws_access_key_id"] + value = data.sops_file.secret_vars.data["www_access_key_id"] repositories = ["www"] } "www_secret_access_key" = { name = "AWS_SECRET_ACCESS_KEY" - value = data.sops_file.secret_vars.data["www_aws_secret_access_key"] + value = data.sops_file.secret_vars.data["www_secret_access_key"] repositories = ["www"] } "cloudflare_zone_id" = { From 7e5ef1b0b2cd5a7a120d5777c1383ee562060c49 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Sun, 30 Aug 2026 12:41:01 -0600 Subject: [PATCH 2/3] style: apply tofu fmt alignment to repository attributes --- gh-repositories.tf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gh-repositories.tf b/gh-repositories.tf index 599402e..0e788a2 100644 --- a/gh-repositories.tf +++ b/gh-repositories.tf @@ -1,12 +1,12 @@ resource "github_repository" "repositories" { - for_each = local.github_repositories - name = each.key - archived = contains(local.archived_github_repositories, each.key) - visibility = contains(local.private_github_repositories, each.key) ? "private" : var.github_visibility - auto_init = true - allow_squash_merge = true - allow_merge_commit = true - allow_rebase_merge = false + for_each = local.github_repositories + name = each.key + archived = contains(local.archived_github_repositories, each.key) + visibility = contains(local.private_github_repositories, each.key) ? "private" : var.github_visibility + auto_init = true + allow_squash_merge = true + allow_merge_commit = true + allow_rebase_merge = false # Auto-merge stays off except for repositories whose automation-created pull # requests are expected to merge themselves once required checks pass. allow_auto_merge = contains(local.auto_merge_github_repositories, each.key) From 45070b566271703742aada1f18cdb91d7f96522a Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Sun, 30 Aug 2026 12:45:40 -0600 Subject: [PATCH 3/3] fix: restore original SOPS key names in secrets map The auto-merge change accidentally normalized four SOPS data key references to match their map keys (onion/www access key entries point at *_aws_* keys in secrets.yaml). Restore the original references; the only intended main.tf change is the auto-merge repository list. --- main.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.tf b/main.tf index 225b90f..3031601 100644 --- a/main.tf +++ b/main.tf @@ -75,12 +75,12 @@ locals { } "onion_access_key_id" = { name = "ONION_AWS_ACCESS_KEY_ID" - value = data.sops_file.secret_vars.data["onion_access_key_id"] + value = data.sops_file.secret_vars.data["onion_aws_access_key_id"] repositories = ["www"] } "onion_secret_access_key" = { name = "ONION_AWS_SECRET_ACCESS_KEY" - value = data.sops_file.secret_vars.data["onion_secret_access_key"] + value = data.sops_file.secret_vars.data["onion_aws_secret_access_key"] repositories = ["www"] } "www_s3_bucket" = { @@ -95,12 +95,12 @@ locals { } "www_access_key_id" = { name = "AWS_ACCESS_KEY_ID" - value = data.sops_file.secret_vars.data["www_access_key_id"] + value = data.sops_file.secret_vars.data["www_aws_access_key_id"] repositories = ["www"] } "www_secret_access_key" = { name = "AWS_SECRET_ACCESS_KEY" - value = data.sops_file.secret_vars.data["www_secret_access_key"] + value = data.sops_file.secret_vars.data["www_aws_secret_access_key"] repositories = ["www"] } "cloudflare_zone_id" = {