Skip to content

Commit b7a5065

Browse files
committed
fix: don't update optional, unset fields of okta_brand
1 parent 87072bb commit b7a5065

2 files changed

Lines changed: 90 additions & 9 deletions

File tree

okta/services/idaas/resource_okta_brand.go

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -337,25 +337,51 @@ func buildCreateBrandRequest(model brandResourceModel) (okta.CreateBrandRequest,
337337
}
338338

339339
func buildUpdateBrandRequest(model brandResourceModel, emailDomainID *string) (okta.BrandRequest, error) {
340+
// mandatory fields
341+
brandRequest := okta.BrandRequest{
342+
Name: model.Name.ValueStringPointer(),
343+
EmailDomainId: emailDomainID,
344+
}
345+
346+
// Only include optional fields if they are not null
347+
if !model.AgreeToCustomPrivacyPolicy.IsNull() {
348+
brandRequest.AgreeToCustomPrivacyPolicy = model.AgreeToCustomPrivacyPolicy.ValueBoolPointer()
349+
}
350+
351+
if !model.CustomPrivacyPolicyURL.IsNull() {
352+
brandRequest.CustomPrivacyPolicyUrl = model.CustomPrivacyPolicyURL.ValueStringPointer()
353+
}
354+
355+
if !model.Locale.IsNull() {
356+
brandRequest.Locale = model.Locale.ValueStringPointer()
357+
}
358+
359+
if !model.RemovePoweredByOkta.IsNull() {
360+
brandRequest.RemovePoweredByOkta = model.RemovePoweredByOkta.ValueBoolPointer()
361+
}
362+
363+
// Handle DefaultApp - only include if at least one field is set
340364
defaultApp := &okta.DefaultApp{}
365+
hasDefaultAppFields := false
366+
341367
if !model.DefaultAppAppInstanceID.IsNull() && model.DefaultAppAppInstanceID.ValueString() != "" {
342368
defaultApp.AppInstanceId = model.DefaultAppAppInstanceID.ValueStringPointer()
369+
hasDefaultAppFields = true
343370
}
344371
if !model.DefaultAppAppLinkName.IsNull() && model.DefaultAppAppLinkName.ValueString() != "" {
345372
defaultApp.AppLinkName = model.DefaultAppAppLinkName.ValueStringPointer()
373+
hasDefaultAppFields = true
346374
}
347375
if !model.DefaultAppClassicApplicationURI.IsNull() && model.DefaultAppClassicApplicationURI.ValueString() != "" {
348376
defaultApp.ClassicApplicationUri = model.DefaultAppClassicApplicationURI.ValueStringPointer()
377+
hasDefaultAppFields = true
349378
}
350-
return okta.BrandRequest{
351-
Name: model.Name.ValueStringPointer(),
352-
AgreeToCustomPrivacyPolicy: model.AgreeToCustomPrivacyPolicy.ValueBoolPointer(),
353-
CustomPrivacyPolicyUrl: model.CustomPrivacyPolicyURL.ValueStringPointer(),
354-
DefaultApp: defaultApp,
355-
EmailDomainId: emailDomainID,
356-
Locale: model.Locale.ValueStringPointer(),
357-
RemovePoweredByOkta: model.RemovePoweredByOkta.ValueBoolPointer(),
358-
}, nil
379+
380+
if hasDefaultAppFields {
381+
brandRequest.DefaultApp = defaultApp
382+
}
383+
384+
return brandRequest, nil
359385
}
360386

361387
func mapBrandToState(data *okta.BrandWithEmbedded, state *brandResourceModel) diag.Diagnostics {

okta/services/idaas/resource_okta_brand_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,58 @@ resource okta_brand test{
172172
},
173173
})
174174
}
175+
176+
// TestAccResourceOktaBrand_minimal_update verifies that updating a brand with only one optional field
177+
// doesn't accidentally send other null/empty optional fields to the API
178+
func TestAccResourceOktaBrand_minimal_update(t *testing.T) {
179+
mgr := newFixtureManager("resources", resources.OktaIDaaSBrand, t.Name())
180+
resourceName := fmt.Sprintf("%s.test", resources.OktaIDaaSBrand)
181+
182+
// Step 1: Create with minimal config (only name)
183+
step1 := `
184+
resource okta_brand test{
185+
name = "testAcc-replace_with_uuid"
186+
}`
187+
188+
// Step 2: Update by adding only one optional field
189+
step2 := `
190+
resource okta_brand test{
191+
name = "testAcc-replace_with_uuid"
192+
remove_powered_by_okta = true
193+
}`
194+
195+
acctest.OktaResourceTest(t, resource.TestCase{
196+
PreCheck: acctest.AccPreCheck(t),
197+
ErrorCheck: testAccErrorChecks(t),
198+
CheckDestroy: nil,
199+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactoriesForTestAcc(t),
200+
Steps: []resource.TestStep{
201+
{
202+
Config: mgr.ConfigReplace(step1),
203+
Check: resource.ComposeAggregateTestCheckFunc(
204+
resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("testAcc-%d", mgr.Seed)),
205+
// Verify optional fields are not set
206+
resource.TestCheckNoResourceAttr(resourceName, "custom_privacy_policy_url"),
207+
resource.TestCheckNoResourceAttr(resourceName, "email_domain_id"),
208+
resource.TestCheckNoResourceAttr(resourceName, "default_app_app_instance_id"),
209+
resource.TestCheckNoResourceAttr(resourceName, "default_app_app_link_name"),
210+
resource.TestCheckNoResourceAttr(resourceName, "default_app_classic_application_uri"),
211+
),
212+
},
213+
{
214+
Config: mgr.ConfigReplace(step2),
215+
Check: resource.ComposeAggregateTestCheckFunc(
216+
resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("testAcc-%d", mgr.Seed)),
217+
// Verify the updated field is set
218+
resource.TestCheckResourceAttr(resourceName, "remove_powered_by_okta", "true"),
219+
// Verify other optional fields remain unset after update
220+
resource.TestCheckNoResourceAttr(resourceName, "custom_privacy_policy_url"),
221+
resource.TestCheckNoResourceAttr(resourceName, "email_domain_id"),
222+
resource.TestCheckNoResourceAttr(resourceName, "default_app_app_instance_id"),
223+
resource.TestCheckNoResourceAttr(resourceName, "default_app_app_link_name"),
224+
resource.TestCheckNoResourceAttr(resourceName, "default_app_classic_application_uri"),
225+
),
226+
},
227+
},
228+
})
229+
}

0 commit comments

Comments
 (0)