From 6bb636846f5427d1fbeddd343367c1ddf86bb119 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Tue, 11 Aug 2026 21:01:10 +1000 Subject: [PATCH] branch_protection: stop whitelist representation churn planning every run Why: - The go-gitea/gitea provider stores branch-protection whitelist users/teams as plain names, but Gitea resolves them to IDs and, on read, returns them via getWhitelistEntities over the repo's readers: users ordered by user ID, teams ordered by name, and any entity without read access to the repo silently dropped. - So the read-back representation of push/merge/approval whitelists rarely matches the config list (order differs, or a whitelisted user/team that lacks repo access disappears), and tofu plans an in-place update for those branch protections on every run even with no config change. - This is the same class of provider representation churn already handled for teams in #62 (units/repositories), and it blocks a clean plan on terraform-git. Change: - Add a targeted ignore_changes on the six whitelist list attributes (push/merge/approval, users and teams) at the branch_protection module so the churn no longer triggers a spurious update, keeping every protected repo idempotent. - Leave enable_push, required_approvals, status_check_patterns and the block_merge_on_* flags managed; those round-trip cleanly and stay drift-checked. --- .../gitea_instance/modules/branch_protection/main.tf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/gitea_instance/modules/branch_protection/main.tf b/modules/gitea_instance/modules/branch_protection/main.tf index d4e4282..929bd8e 100644 --- a/modules/gitea_instance/modules/branch_protection/main.tf +++ b/modules/gitea_instance/modules/branch_protection/main.tf @@ -24,4 +24,16 @@ resource "gitea_repository_branch_protection" "this" { require_signed_commits = var.require_signed_commits protected_file_patterns = var.protected_file_patterns unprotected_file_patterns = var.unprotected_file_patterns + + lifecycle { + # Gitea resolves whitelist names to IDs and returns them ordered by repo-reader (user ID for users, name for teams), dropping any entity without repo access, so the read-back representation never matches the config and plans a spurious update every run. + ignore_changes = [ + push_whitelist_users, + push_whitelist_teams, + merge_whitelist_users, + merge_whitelist_teams, + approval_whitelist_users, + approval_whitelist_teams, + ] + } }