fix: remove API-injected defaults for known-empty allowed_to_* slices in branch protection (issue #6861)
What does this MR do and why?
Fixes #6861 (closed): when allowed_to_push, allowed_to_merge, or allowed_to_unprotect is explicitly set to an empty slice [] in a gitlab_branch_protection resource, the GitLab API silently injects a default maintainer access-level entry. This caused a "Provider produced inconsistent result after apply" error.
Root cause
The GitLab API injects default access-level entries when any of the three allowed_to_* fields are empty on POST /projects/:id/protected_branches. The provider was not removing these injected defaults, so the state read back from the API (with the injected maintainer entry) did not match the planned empty set.
Fix
Two changes to internal/provider/resource_gitlab_branch_protection.go:
1. waitForProtectedBranchAsync — distinguish managed vs unmanaged fields
The poller now checks whether each field is "managed" (explicitly set in config, not null/unknown). For unmanaged fields, the length check is skipped entirely. For managed-but-empty fields, the check is also skipped (the API will inject defaults, which removeAPIInjectedDefaults will clean up).
2. New removeAPIInjectedDefaults helper
Called after waitForProtectedBranchAsync in both Create and Update (when isEE). It issues an UpdateProtectedBranch call to destroy any API-injected entries for fields that are known and empty in the plan:
- Known and empty (
= []in config): the set is not null/unknown with 0 elements → injected defaults are removed - Null or unknown (not defined in config): the set is null/unknown → injected defaults are left in place
This correctly handles the distinction @PatrickRice described: "known and empty" should perform the delete after create/update, whereas "unknown and empty" should not.
Tests
Three regression tests were added in the previous commit (937d3c0f):
TestAccGitlabBranchProtection_emptyAllowedToUnprotect— the originally reported caseTestAccGitlabBranchProtection_emptyAllowedToPushTestAccGitlabBranchProtection_emptyAllowedToMerge
Each test sets the respective allowed_to_* field to an explicit empty slice [] and asserts that the state reflects zero entries.
MR acceptance checklist
- Fix implemented in
resource_gitlab_branch_protection.go - Differentiates between "known and empty" (delete injected defaults) vs "null/unknown" (leave defaults in place)
-
removeAPIInjectedDefaultscalled from bothCreateandUpdateafter the async wait - Three regression tests covering all three affected fields
- Tests are EE-only (skipped on CE) since
allowed_to_*is an EE feature
Closes #6861 (closed)