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 case
  • TestAccGitlabBranchProtection_emptyAllowedToPush
  • TestAccGitlabBranchProtection_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)
  • removeAPIInjectedDefaults called from both Create and Update after 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)

Edited by Duo Developer

Merge request reports

Loading