Skip to content

Commit c2473a7

Browse files
authored
fix(sso): handle unknown team_ids in group mapping CustomizeDiff (#728)
CustomizeDiff in sysdig_sso_group_mapping reads team_ids via diff.Get, which surfaces unknown (known-after-apply) values as empty lists. This causes a false "team_ids must be set when is_for_all_teams is false" error during plan when team_ids references resources not yet created (e.g. sysdig_secure_team.*.id). Switches to diff.GetRawPlan().AsValueMap() with cty .IsKnown() checks to skip validation when values are not yet resolved, deferring to apply-time. Matches existing pattern in resource_sysdig_secure_team. Adds regression test with is_for_all_teams=false + team ID from a forward resource reference.
1 parent 2498632 commit c2473a7

3 files changed

Lines changed: 110 additions & 41 deletions

File tree

sysdig/resource_sysdig_secure_zone_test.go

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func TestAccSysdigZone_basic(t *testing.T) {
6262

6363
func TestAccSysdigSecureZone_LegacyRules(t *testing.T) {
6464
resourceName := "sysdig_secure_zone.legacy"
65+
name := "acc-legacy-" + randomText(5)
6566

6667
resource.Test(t, resource.TestCase{
6768
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
@@ -72,23 +73,24 @@ func TestAccSysdigSecureZone_LegacyRules(t *testing.T) {
7273
},
7374
Steps: []resource.TestStep{
7475
{
75-
Config: testAccSecureZoneLegacy(),
76+
Config: testAccSecureZoneLegacy(name),
7677
Check: resource.ComposeTestCheckFunc(
77-
resource.TestCheckResourceAttr(resourceName, "name", "acc-legacy"),
78+
resource.TestCheckResourceAttr(resourceName, "name", name),
7879
resource.TestCheckResourceAttr(resourceName, "scope.0.target_type", "kubernetes"),
7980
),
8081
},
8182
{
8283
// refresh only
8384
PlanOnly: true,
84-
Config: testAccSecureZoneLegacy(),
85+
Config: testAccSecureZoneLegacy(name),
8586
},
8687
},
8788
})
8889
}
8990

9091
func TestAccSysdigSecureZone_ExpressionOnly(t *testing.T) {
9192
resourceName := "sysdig_secure_zone.expr"
93+
name := "acc-expr-" + randomText(5)
9294

9395
resource.Test(t, resource.TestCase{
9496
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
@@ -99,9 +101,9 @@ func TestAccSysdigSecureZone_ExpressionOnly(t *testing.T) {
99101
},
100102
Steps: []resource.TestStep{
101103
{
102-
Config: testAccSecureZoneExpression(),
104+
Config: testAccSecureZoneExpression(name),
103105
Check: resource.ComposeTestCheckFunc(
104-
resource.TestCheckResourceAttr(resourceName, "name", "acc-expr"),
106+
resource.TestCheckResourceAttr(resourceName, "name", name),
105107
resource.TestCheckResourceAttr(resourceName, "scope.0.target_type", "kubernetes"),
106108
resource.TestCheckResourceAttr(resourceName, "scope.0.expression.#", "2"),
107109
// In SDK v2, optional attributes in nested TypeSet elements are always
@@ -111,14 +113,15 @@ func TestAccSysdigSecureZone_ExpressionOnly(t *testing.T) {
111113
},
112114
{
113115
PlanOnly: true,
114-
Config: testAccSecureZoneExpression(),
116+
Config: testAccSecureZoneExpression(name),
115117
},
116118
},
117119
})
118120
}
119121

120122
func TestAccSysdigSecureZone_MigrateRulesToExpression(t *testing.T) {
121123
resourceName := "sysdig_secure_zone.migrate"
124+
name := "acc-migrate-" + randomText(5)
122125

123126
resource.Test(t, resource.TestCase{
124127
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
@@ -129,25 +132,26 @@ func TestAccSysdigSecureZone_MigrateRulesToExpression(t *testing.T) {
129132
},
130133
Steps: []resource.TestStep{
131134
{
132-
Config: testAccSecureZoneLegacyMigration(),
135+
Config: testAccSecureZoneLegacyMigration(name),
133136
},
134137
{
135-
Config: testAccSecureZoneExpressionMigration(),
138+
Config: testAccSecureZoneExpressionMigration(name),
136139
Check: resource.ComposeTestCheckFunc(
137140
resource.TestCheckResourceAttr(resourceName, "description", "migrated"),
138141
resource.TestCheckResourceAttr(resourceName, "scope.0.expression.#", "2"),
139142
),
140143
},
141144
{
142145
PlanOnly: true,
143-
Config: testAccSecureZoneExpressionMigration(),
146+
Config: testAccSecureZoneExpressionMigration(name),
144147
},
145148
},
146149
})
147150
}
148151

149152
func TestAccSysdigSecureZone_V2RulesOnly(t *testing.T) {
150153
resourceName := "sysdig_secure_zone.v2rules"
154+
name := "acc-v2rules-" + randomText(5)
151155

152156
resource.Test(t, resource.TestCase{
153157
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv, SysdigIBMSecureAPIKeyEnv),
@@ -158,16 +162,16 @@ func TestAccSysdigSecureZone_V2RulesOnly(t *testing.T) {
158162
},
159163
Steps: []resource.TestStep{
160164
{
161-
Config: testAccSecureZoneV2Rules(),
165+
Config: testAccSecureZoneV2Rules(name),
162166
Check: resource.ComposeTestCheckFunc(
163-
resource.TestCheckResourceAttr(resourceName, "name", "acc-v2rules"),
167+
resource.TestCheckResourceAttr(resourceName, "name", name),
164168
resource.TestCheckResourceAttr(resourceName, "scope.0.target_type", "kubernetes"),
165169
resource.TestCheckResourceAttr(resourceName, "scope.0.expression.#", "0"),
166170
),
167171
},
168172
{
169173
PlanOnly: true,
170-
Config: testAccSecureZoneV2Rules(),
174+
Config: testAccSecureZoneV2Rules(name),
171175
},
172176
},
173177
})
@@ -203,24 +207,24 @@ resource "sysdig_secure_zone" "test" {
203207
`, name, description)
204208
}
205209

206-
func testAccSecureZoneLegacy() string {
207-
return `
210+
func testAccSecureZoneLegacy(name string) string {
211+
return fmt.Sprintf(`
208212
resource "sysdig_secure_zone" "legacy" {
209-
name = "acc-legacy"
213+
name = "%s"
210214
description = "legacy rules"
211215
212216
scope {
213217
target_type = "kubernetes"
214218
rules = "agentTags != \"key: value\" and not agentTags contains \"key2: value2\""
215219
}
216220
}
217-
`
221+
`, name)
218222
}
219223

220-
func testAccSecureZoneExpression() string {
221-
return `
224+
func testAccSecureZoneExpression(name string) string {
225+
return fmt.Sprintf(`
222226
resource "sysdig_secure_zone" "expr" {
223-
name = "acc-expr"
227+
name = "%s"
224228
description = "expression test"
225229
226230
scope {
@@ -239,27 +243,27 @@ resource "sysdig_secure_zone" "expr" {
239243
}
240244
}
241245
}
242-
`
246+
`, name)
243247
}
244248

245-
func testAccSecureZoneLegacyMigration() string {
246-
return `
249+
func testAccSecureZoneLegacyMigration(name string) string {
250+
return fmt.Sprintf(`
247251
resource "sysdig_secure_zone" "migrate" {
248-
name = "acc-migrate"
252+
name = "%s"
249253
description = "legacy"
250254
251255
scope {
252256
target_type = "kubernetes"
253257
rules = "agentTags != \"key: value\" and not agentTags contains \"key2: value2\""
254258
}
255259
}
256-
`
260+
`, name)
257261
}
258262

259-
func testAccSecureZoneExpressionMigration() string {
260-
return `
263+
func testAccSecureZoneExpressionMigration(name string) string {
264+
return fmt.Sprintf(`
261265
resource "sysdig_secure_zone" "migrate" {
262-
name = "acc-migrate"
266+
name = "%s"
263267
description = "migrated"
264268
265269
scope {
@@ -278,21 +282,21 @@ resource "sysdig_secure_zone" "migrate" {
278282
}
279283
}
280284
}
281-
`
285+
`, name)
282286
}
283287

284-
func testAccSecureZoneV2Rules() string {
285-
return `
288+
func testAccSecureZoneV2Rules(name string) string {
289+
return fmt.Sprintf(`
286290
resource "sysdig_secure_zone" "v2rules" {
287-
name = "acc-v2rules"
291+
name = "%s"
288292
description = "v2 rules test"
289293
290294
scope {
291295
target_type = "kubernetes"
292296
rules = "agent.tag.key != \"value\" and not agent.tag.key2 contains \"value2\""
293297
}
294298
}
295-
`
299+
`, name)
296300
}
297301

298302
func testAccSecureZoneInvalid() string {

sysdig/resource_sysdig_sso_group_mapping.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,28 @@ func resourceSysdigSSOGroupMapping() *schema.Resource {
3030
Delete: schema.DefaultTimeout(timeout),
3131
},
3232
CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, meta any) error {
33-
teamMaps := diff.Get("team_map").([]any)
34-
if len(teamMaps) > 0 {
35-
teamMap := teamMaps[0].(map[string]any)
36-
isForAllTeams := teamMap["is_for_all_teams"].(bool)
37-
teamIDs := teamMap["team_ids"].([]any)
38-
if !isForAllTeams && len(teamIDs) == 0 {
39-
return fmt.Errorf("team_ids must be set when is_for_all_teams is false")
40-
}
33+
plan := diff.GetRawPlan().AsValueMap()
34+
teamMapPlan := plan["team_map"]
35+
if teamMapPlan.IsNull() || !teamMapPlan.IsKnown() {
36+
return nil
37+
}
38+
teamMapSlice := teamMapPlan.AsValueSlice()
39+
if len(teamMapSlice) == 0 {
40+
return nil
41+
}
42+
first := teamMapSlice[0]
43+
if !first.IsKnown() {
44+
return nil
45+
}
46+
inner := first.AsValueMap()
47+
isForAllTeams := inner["is_for_all_teams"]
48+
teamIDs := inner["team_ids"]
49+
if !isForAllTeams.IsKnown() || !teamIDs.IsKnown() {
50+
return nil
51+
}
52+
if !isForAllTeams.True() && (teamIDs.IsNull() || len(teamIDs.AsValueSlice()) == 0) {
53+
return fmt.Errorf("team_ids must be set when is_for_all_teams is false")
4154
}
42-
4355
return nil
4456
},
4557
Schema: map[string]*schema.Schema{

sysdig/resource_sysdig_sso_group_mapping_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,41 @@ func TestAccSSOGroupMappingCustomRole(t *testing.T) {
131131
})
132132
}
133133

134+
func TestAccSSOGroupMappingTeamIDsFromResource(t *testing.T) {
135+
groupName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
136+
137+
resource.ParallelTest(t, resource.TestCase{
138+
PreCheck: preCheckAnyEnv(t, SysdigSecureApiTokenEnv),
139+
ProviderFactories: map[string]func() (*schema.Provider, error){
140+
"sysdig": func() (*schema.Provider, error) {
141+
return sysdig.Provider(), nil
142+
},
143+
},
144+
Steps: []resource.TestStep{
145+
{
146+
Config: ssoGroupMappingWithTeamIDsConfig(groupName),
147+
Check: resource.ComposeTestCheckFunc(
148+
resource.TestCheckResourceAttr(
149+
"sysdig_sso_group_mapping.test_team_ids",
150+
"group_name",
151+
groupName,
152+
),
153+
resource.TestCheckResourceAttr(
154+
"sysdig_sso_group_mapping.test_team_ids",
155+
"team_map.0.is_for_all_teams",
156+
"false",
157+
),
158+
),
159+
},
160+
{
161+
ResourceName: "sysdig_sso_group_mapping.test_team_ids",
162+
ImportState: true,
163+
ImportStateVerify: true,
164+
},
165+
},
166+
})
167+
}
168+
134169
func ssoGroupMappingAllTeamsConfig(groupName string) string {
135170
return fmt.Sprintf(`
136171
resource "sysdig_sso_group_mapping" "test" {
@@ -163,6 +198,24 @@ resource "sysdig_sso_group_mapping" "test" {
163198
`, groupName)
164199
}
165200

201+
func ssoGroupMappingWithTeamIDsConfig(groupName string) string {
202+
return fmt.Sprintf(`
203+
resource "sysdig_secure_team" "test_team" {
204+
name = "%[1]s-team"
205+
}
206+
207+
resource "sysdig_sso_group_mapping" "test_team_ids" {
208+
group_name = "%[1]s"
209+
standard_team_role = "ROLE_TEAM_STANDARD"
210+
211+
team_map {
212+
is_for_all_teams = false
213+
team_ids = [sysdig_secure_team.test_team.id]
214+
}
215+
}
216+
`, groupName)
217+
}
218+
166219
func ssoGroupMappingCustomRoleConfig(groupName string) string {
167220
return fmt.Sprintf(`
168221
resource "sysdig_custom_role" "test_role" {

0 commit comments

Comments
 (0)