Skip to content
93 changes: 70 additions & 23 deletions github/util_v4_branch_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"sort"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -258,6 +259,7 @@ func branchProtectionResourceData(d *schema.ResourceData, meta interface{}) (Bra
pushActorIDs = append(pushActorIDs, v.(string))
}
if len(pushActorIDs) > 0 {
sort.Strings(pushActorIDs)
data.PushActorIDs = pushActorIDs
}
}
Expand Down Expand Up @@ -460,33 +462,53 @@ func setBypassPullRequestActorIDs(actors []BypassPullRequestActorTypes, data Bra

func setPushActorIDs(actors []PushActorTypes, data BranchProtectionResourceData, meta interface{}) []string {
pushActors := make([]string, 0, len(actors))

orgName := meta.(*Owner).name

// Create a map to track seen IDs to prevent duplicates
seenIDs := make(map[string]struct{})

for _, a := range actors {
IsID := false
for _, v := range data.PushActorIDs {
if (a.Actor.Team.ID != nil && a.Actor.Team.ID.(string) == v) || (a.Actor.User.ID != nil && a.Actor.User.ID.(string) == v) || (a.Actor.App.ID != nil && a.Actor.App.ID.(string) == v) {
pushActors = append(pushActors, v)
IsID = true
break
}
var id string
if a.Actor.Team.ID != nil {
id = a.Actor.Team.ID.(string)
} else if a.Actor.User.ID != nil {
id = a.Actor.User.ID.(string)
} else if a.Actor.App.ID != nil {
id = a.Actor.App.ID.(string)
} else if a.Actor.Team.Slug != "" {
formattedID = orgName + "/" + string(a.Actor.Team.Slug)
} else if a.Actor.User.Login != "" {
formattedID = "/" + string(a.Actor.User.Login)
}
if !IsID {
if a.Actor.Team.Slug != "" {
pushActors = append(pushActors, orgName+"/"+string(a.Actor.Team.Slug))
continue
}
if a.Actor.User.Login != "" {
pushActors = append(pushActors, "/"+string(a.Actor.User.Login))
continue
}
if a.Actor.App != (Actor{}) {
pushActors = append(pushActors, a.Actor.App.ID.(string))

if id != "" {
if _, exists := seenIDs[id]; !exists {
pushActors = append(pushActors, id)
seenIDs[id] = struct{}{}
}
}
}
return pushActors

// Sort for consistent ordering
sort.Strings(pushActors)

// Validate against provided IDs
idMap := make(map[string]bool)
for _, v := range data.PushActorIDs {
idMap[v] = true
}

// Only keep IDs that were in the original PushActorIDs
validPushActors := make([]string, 0, len(pushActors))
for _, actor := range pushActors {
if idMap[actor] {
validPushActors = append(validPushActors, actor)
}
}

sort.Strings(validPushActors)
log.Printf("[DEBUG] Final sorted and validated pushActors: %v", validPushActors)
return validPushActors
}

func setApprovingReviews(protection BranchProtectionRule, data BranchProtectionResourceData, meta interface{}) interface{} {
Expand Down Expand Up @@ -538,13 +560,19 @@ func setPushes(protection BranchProtectionRule, data BranchProtectionResourceDat
pushAllowances := protection.PushAllowances.Nodes
pushActors := setPushActorIDs(pushAllowances, data, meta)

// If we have no push actors but restrictions are enabled, return an empty list
// rather than nil to prevent drift
if len(pushActors) == 0 && protection.RestrictsPushes {
log.Printf("[DEBUG] No push actors found, returning empty list")
pushActors = make([]string, 0)
}

restrictsPushes := []interface{}{
map[string]interface{}{
PROTECTION_BLOCKS_CREATIONS: protection.BlocksCreations,
PROTECTION_PUSH_ALLOWANCES: pushActors,
},
}

return restrictsPushes
}

Expand Down Expand Up @@ -611,15 +639,34 @@ func getBranchProtectionID(repoID githubv4.ID, pattern string, meta interface{})

func getActorIds(data []string, meta interface{}) ([]string, error) {
var actors []string
log.Printf("[DEBUG] getActorIds input data: %v", data)

// Create a map to track processed IDs and prevent duplicates
seen := make(map[string]bool)

for _, v := range data {
if v == "" {
continue
}

id, err := getNodeIDv4(v, meta)
if err != nil {
log.Printf("[DEBUG] Error getting node ID for %s: %v", v, err)
return []string{}, err
}
log.Printf("[DEBUG] Retrieved node ID for user/team : %s - node ID : %s", v, id)
actors = append(actors, id)

log.Printf("[DEBUG] Retrieved node ID for user/team: %s - node ID: %s", v, id)

if !seen[id] {
actors = append(actors, id)
seen[id] = true
} else {
log.Printf("[DEBUG] Skipping duplicate ID: %s", id)
}
}

sort.Strings(actors)
log.Printf("[DEBUG] Final sorted actor IDs: %v", actors)
return actors, nil
}

Expand Down