55 "github.com/permitio/permit-golang/pkg/models"
66 "github.com/permitio/permit-golang/pkg/permit"
77 "github.com/permitio/terraform-provider-permit-io/internal/provider/common"
8+ "github.com/samber/lo"
89)
910
1011type roleClient struct {
@@ -87,7 +88,7 @@ func (c *roleClient) Read(ctx context.Context, key string, resourceKey *string)
8788}
8889
8990func (c * roleClient ) Update (ctx context.Context , plan roleModel ) (roleModel , error ) {
90- permissions , err := common .ConvertElementsToSlice [string ](ctx , plan .Permissions .Elements ())
91+ desiredPermissions , err := common .ConvertElementsToSlice [string ](ctx , plan .Permissions .Elements ())
9192
9293 if err != nil {
9394 return roleModel {}, err
@@ -101,35 +102,104 @@ func (c *roleClient) Update(ctx context.Context, plan roleModel) (roleModel, err
101102
102103 var updatedModel roleModel
103104 if plan .isResourceRole () {
105+ resourceKey := plan .Resource .ValueString ()
106+ roleKey := plan .Key .ValueString ()
107+
108+ // Read current role to get current permissions for diff calculation
109+ currentRole , err := c .client .Api .ResourceRoles .Get (ctx , resourceKey , roleKey )
110+ if err != nil {
111+ return roleModel {}, err
112+ }
113+
114+ // PATCH only name/description/extends — permissions are handled separately
115+ // via dedicated endpoints to avoid server-side errors with large permission sets.
104116 roleUpdate := models.ResourceRoleUpdate {
105117 Name : plan .Name .ValueStringPointer (),
106118 Description : plan .Description .ValueStringPointer (),
107- Permissions : permissions ,
108119 Extends : extends ,
109120 }
110121
111- updatedRole , err := c .client .Api .ResourceRoles .Update (ctx , plan .Resource .ValueString (), plan .Key .ValueString (), roleUpdate )
122+ _ , err = c .client .Api .ResourceRoles .Update (ctx , resourceKey , roleKey , roleUpdate )
123+ if err != nil {
124+ return roleModel {}, err
125+ }
126+
127+ // Compute permission diff and apply incrementally
128+ toRemove , toAdd := lo .Difference (currentRole .Permissions , desiredPermissions )
129+
130+ if len (toRemove ) > 0 {
131+ _ , err = c .client .Api .ResourceRoles .RemovePermissions (
132+ ctx , resourceKey , roleKey ,
133+ * models .NewRemoveRolePermissions (toRemove ),
134+ )
135+ if err != nil {
136+ return roleModel {}, err
137+ }
138+ }
139+
140+ if len (toAdd ) > 0 {
141+ _ , err = c .client .Api .ResourceRoles .AssignPermissions (
142+ ctx , resourceKey , roleKey ,
143+ * models .NewAddRolePermissions (toAdd ),
144+ )
145+ if err != nil {
146+ return roleModel {}, err
147+ }
148+ }
112149
150+ // Read final state
151+ finalRole , err := c .client .Api .ResourceRoles .Get (ctx , resourceKey , roleKey )
113152 if err != nil {
114153 return roleModel {}, err
115154 }
116155
117- updatedModel = tfModelFromResourceRoleRead (plan . Resource . ValueString () , * updatedRole )
156+ updatedModel = tfModelFromResourceRoleRead (resourceKey , * finalRole )
118157 } else {
158+ roleKey := plan .Key .ValueString ()
159+
160+ // Read current role to get current permissions for diff calculation
161+ currentRole , err := c .client .Api .Roles .Get (ctx , roleKey )
162+ if err != nil {
163+ return roleModel {}, err
164+ }
165+
166+ // PATCH only name/description/extends — permissions are handled separately
167+ // via dedicated endpoints to avoid server-side errors with large permission sets.
119168 roleUpdate := models.RoleUpdate {
120169 Name : plan .Name .ValueStringPointer (),
121170 Description : plan .Description .ValueStringPointer (),
122- Permissions : permissions ,
123171 Extends : extends ,
124172 }
125173
126- updatedRole , err := c .client .Api .Roles .Update (ctx , plan .Key .ValueString (), roleUpdate )
174+ _ , err = c .client .Api .Roles .Update (ctx , roleKey , roleUpdate )
175+ if err != nil {
176+ return roleModel {}, err
177+ }
178+
179+ // Compute permission diff and apply incrementally
180+ toRemove , toAdd := lo .Difference (currentRole .Permissions , desiredPermissions )
181+
182+ if len (toRemove ) > 0 {
183+ err = c .client .Api .Roles .RemovePermissions (ctx , roleKey , toRemove )
184+ if err != nil {
185+ return roleModel {}, err
186+ }
187+ }
188+
189+ if len (toAdd ) > 0 {
190+ err = c .client .Api .Roles .AssignPermissions (ctx , roleKey , toAdd )
191+ if err != nil {
192+ return roleModel {}, err
193+ }
194+ }
127195
196+ // Read final state
197+ finalRole , err := c .client .Api .Roles .Get (ctx , roleKey )
128198 if err != nil {
129199 return roleModel {}, err
130200 }
131201
132- updatedModel = tfModelFromRoleRead (* updatedRole )
202+ updatedModel = tfModelFromRoleRead (* finalRole )
133203 }
134204
135205 return updatedModel , nil
0 commit comments