Skip to content

Commit 9f01eeb

Browse files
fix: migrate trait profile/status to resource-level APIs (#143)
Resolve golangci-lint SA1019 failures on main by using WithResourceProfile/WithResourceStatus and GetProfile/GetStatus instead of deprecated trait-level profile and status APIs. Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
1 parent b61a6c8 commit 9f01eeb

3 files changed

Lines changed: 85 additions & 56 deletions

File tree

pkg/bcel/bcel.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,18 +133,12 @@ func resourceToCELMap(resource *v2.Resource) map[string]any {
133133
"DisplayName": resource.DisplayName,
134134
}
135135

136-
if t, err := sdkResource.GetGroupTrait(resource); err == nil && t.GetProfile() != nil {
137-
out["profile"] = t.GetProfile().AsMap()
138-
} else if t, err := sdkResource.GetUserTrait(resource); err == nil && t.GetProfile() != nil {
139-
out["profile"] = t.GetProfile().AsMap()
140-
} else if t, err := sdkResource.GetRoleTrait(resource); err == nil && t.GetProfile() != nil {
141-
out["profile"] = t.GetProfile().AsMap()
142-
} else if t, err := sdkResource.GetAppTrait(resource); err == nil && t.GetProfile() != nil {
143-
out["profile"] = t.GetProfile().AsMap()
144-
}
145-
146-
// Empty default so `has(resource.profile.X)` is well-defined for optional fields.
147-
if _, exists := out["profile"]; !exists {
136+
// Profile lives on Resource (trait-level profile is deprecated SA1019).
137+
// GetProfile reads resource-level first and falls back to legacy trait fields.
138+
if profile := sdkResource.GetProfile(resource); profile != nil {
139+
out["profile"] = profile.AsMap()
140+
} else {
141+
// Empty default so `has(resource.profile.X)` is well-defined for optional fields.
148142
out["profile"] = map[string]any{}
149143
}
150144

pkg/bsql/nhi_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,17 @@ func TestMapResource_AgentTrait(t *testing.T) {
171171

172172
at, err := sdkResource.GetAgentTrait(r)
173173
require.NoError(t, err)
174-
require.Equal(t, v2.AgentTrait_AGENT_STATUS_READY, at.GetStatus())
174+
// Status and profile live on Resource (trait-level getters are deprecated SA1019).
175+
// Agent READY maps to RESOURCE_STATUS_ENABLED (identical enum values).
176+
st := sdkResource.GetStatus(r)
177+
require.NotNil(t, st)
178+
require.Equal(t, v2.Status_RESOURCE_STATUS_ENABLED, st.GetStatus())
175179
require.NotNil(t, at.GetIdentityResourceId())
176180
require.Equal(t, "user", at.GetIdentityResourceId().GetResourceType())
177181
require.Equal(t, "svc-acct-1", at.GetIdentityResourceId().GetResource())
178-
require.Equal(t, "claude-opus", at.GetProfile().GetFields()["model"].GetStringValue())
182+
profile := sdkResource.GetProfile(r)
183+
require.NotNil(t, profile)
184+
require.Equal(t, "claude-opus", profile.GetFields()["model"].GetStringValue())
179185
}
180186

181187
// Graceful degradation — a plain user resource emits only a UserTrait, no

pkg/bsql/resources.go

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -101,45 +101,47 @@ func (s *SQLSyncer) mapUserTrait(ctx context.Context, r *v2.Resource, rowMap map
101101
opts = append(opts, sdkResource.WithEmail(v, primary))
102102
}
103103

104-
// Status
104+
// Status lives on Resource (trait-level status options are deprecated SA1019).
105+
var resourceStatus *v2.Status_ResourceStatus
106+
var statusDetails string
105107
if mappings.Status != "" {
106108
statusValue, err := s.env.EvaluateString(ctx, mappings.Status, inputs)
107109
if err != nil {
108110
return err
109111
}
110112

111-
var status v2.UserTrait_Status_Status
113+
var status v2.Status_ResourceStatus
112114
switch strings.ToLower(statusValue) {
113115
case "active":
114-
status = v2.UserTrait_Status_STATUS_ENABLED
116+
status = v2.Status_RESOURCE_STATUS_ENABLED
115117
case "enabled":
116-
status = v2.UserTrait_Status_STATUS_ENABLED
118+
status = v2.Status_RESOURCE_STATUS_ENABLED
117119
case "disabled":
118-
status = v2.UserTrait_Status_STATUS_DISABLED
120+
status = v2.Status_RESOURCE_STATUS_DISABLED
119121
case "inactive":
120-
status = v2.UserTrait_Status_STATUS_DISABLED
122+
status = v2.Status_RESOURCE_STATUS_DISABLED
121123
case "suspended":
122-
status = v2.UserTrait_Status_STATUS_DISABLED
124+
status = v2.Status_RESOURCE_STATUS_DISABLED
123125
case "locked":
124-
status = v2.UserTrait_Status_STATUS_DISABLED
126+
status = v2.Status_RESOURCE_STATUS_DISABLED
125127
case "deleted":
126-
status = v2.UserTrait_Status_STATUS_DELETED
128+
status = v2.Status_RESOURCE_STATUS_DELETED
127129
default:
128130
l.Warn("unexpected status value in mapping", zap.String("status", statusValue))
129-
status = v2.UserTrait_Status_STATUS_UNSPECIFIED
131+
status = v2.Status_RESOURCE_STATUS_UNSPECIFIED
130132
}
133+
resourceStatus = &status
131134

132135
if mappings.StatusDetails != "" {
133136
v, err := s.env.EvaluateString(ctx, mappings.StatusDetails, inputs)
134137
if err != nil {
135138
return err
136139
}
137-
opts = append(opts, sdkResource.WithDetailedStatus(status, v))
138-
} else {
139-
opts = append(opts, sdkResource.WithStatus(status))
140+
statusDetails = v
140141
}
141142
}
142143

144+
// Profile lives on Resource (trait-level profile options are deprecated SA1019).
143145
profile := make(map[string]interface{})
144146
for profileKey, profileValue := range mappings.Profile {
145147
v, err := s.env.EvaluateString(ctx, profileValue, inputs)
@@ -149,10 +151,6 @@ func (s *SQLSyncer) mapUserTrait(ctx context.Context, r *v2.Resource, rowMap map
149151
profile[profileKey] = v
150152
}
151153

152-
if len(profile) > 0 {
153-
opts = append(opts, sdkResource.WithUserProfile(profile))
154-
}
155-
156154
// Last Login
157155
if mappings.LastLogin != "" {
158156
lastLoginValue, err := s.env.EvaluateString(ctx, mappings.LastLogin, inputs)
@@ -271,6 +269,17 @@ func (s *SQLSyncer) mapUserTrait(ctx context.Context, r *v2.Resource, rowMap map
271269
annos.Update(t)
272270
r.Annotations = annos
273271

272+
if resourceStatus != nil {
273+
if err := sdkResource.WithResourceStatus(*resourceStatus, statusDetails)(r); err != nil {
274+
return err
275+
}
276+
}
277+
if len(profile) > 0 {
278+
if err := sdkResource.WithResourceProfile(profile)(r); err != nil {
279+
return err
280+
}
281+
}
282+
274283
// Annotation applied
275284

276285
return nil
@@ -291,6 +300,7 @@ func (s *SQLSyncer) mapAppTrait(ctx context.Context, r *v2.Resource, rowMap map[
291300
opts = append(opts, sdkResource.WithAppHelpURL(v))
292301
}
293302

303+
// Profile lives on Resource (trait-level profile options are deprecated SA1019).
294304
profile := make(map[string]interface{})
295305
for profileKey, profileValue := range mappings.Profile {
296306
v, err := s.env.EvaluateString(ctx, profileValue, inputs)
@@ -300,10 +310,6 @@ func (s *SQLSyncer) mapAppTrait(ctx context.Context, r *v2.Resource, rowMap map[
300310
profile[profileKey] = v
301311
}
302312

303-
if len(profile) > 0 {
304-
opts = append(opts, sdkResource.WithAppProfile(profile))
305-
}
306-
307313
t, err := sdkResource.NewAppTrait(opts...)
308314
if err != nil {
309315
return err
@@ -313,6 +319,12 @@ func (s *SQLSyncer) mapAppTrait(ctx context.Context, r *v2.Resource, rowMap map[
313319
annos.Update(t)
314320
r.Annotations = annos
315321

322+
if len(profile) > 0 {
323+
if err := sdkResource.WithResourceProfile(profile)(r); err != nil {
324+
return err
325+
}
326+
}
327+
316328
return nil
317329
}
318330

@@ -321,8 +333,7 @@ func (s *SQLSyncer) mapGroupTrait(ctx context.Context, r *v2.Resource, rowMap ma
321333

322334
mappings := s.config.List.Map.Traits.Group
323335

324-
var opts []sdkResource.GroupTraitOption
325-
336+
// Profile lives on Resource (trait-level profile options are deprecated SA1019).
326337
profile := make(map[string]interface{})
327338
for profileKey, profileValue := range mappings.Profile {
328339
v, err := s.env.EvaluateString(ctx, profileValue, inputs)
@@ -331,11 +342,8 @@ func (s *SQLSyncer) mapGroupTrait(ctx context.Context, r *v2.Resource, rowMap ma
331342
}
332343
profile[profileKey] = v
333344
}
334-
if len(profile) > 0 {
335-
opts = append(opts, sdkResource.WithGroupProfile(profile))
336-
}
337345

338-
t, err := sdkResource.NewGroupTrait(opts...)
346+
t, err := sdkResource.NewGroupTrait()
339347
if err != nil {
340348
return err
341349
}
@@ -344,6 +352,12 @@ func (s *SQLSyncer) mapGroupTrait(ctx context.Context, r *v2.Resource, rowMap ma
344352
annos.Update(t)
345353
r.Annotations = annos
346354

355+
if len(profile) > 0 {
356+
if err := sdkResource.WithResourceProfile(profile)(r); err != nil {
357+
return err
358+
}
359+
}
360+
347361
return nil
348362
}
349363

@@ -352,8 +366,7 @@ func (s *SQLSyncer) mapRoleTrait(ctx context.Context, r *v2.Resource, rowMap map
352366

353367
mappings := s.config.List.Map.Traits.Role
354368

355-
var opts []sdkResource.RoleTraitOption
356-
369+
// Profile lives on Resource (trait-level profile options are deprecated SA1019).
357370
profile := make(map[string]interface{})
358371
for profileKey, profileValue := range mappings.Profile {
359372
v, err := s.env.EvaluateString(ctx, profileValue, inputs)
@@ -362,11 +375,8 @@ func (s *SQLSyncer) mapRoleTrait(ctx context.Context, r *v2.Resource, rowMap map
362375
}
363376
profile[profileKey] = v
364377
}
365-
if len(profile) > 0 {
366-
opts = append(opts, sdkResource.WithRoleProfile(profile))
367-
}
368378

369-
t, err := sdkResource.NewRoleTrait(opts...)
379+
t, err := sdkResource.NewRoleTrait()
370380
if err != nil {
371381
return err
372382
}
@@ -375,6 +385,12 @@ func (s *SQLSyncer) mapRoleTrait(ctx context.Context, r *v2.Resource, rowMap map
375385
annos.Update(t)
376386
r.Annotations = annos
377387

388+
if len(profile) > 0 {
389+
if err := sdkResource.WithResourceProfile(profile)(r); err != nil {
390+
return err
391+
}
392+
}
393+
378394
return nil
379395
}
380396

@@ -467,25 +483,29 @@ func (s *SQLSyncer) mapAgentTrait(ctx context.Context, r *v2.Resource, rowMap ma
467483

468484
var opts []sdkResource.AgentTraitOption
469485

486+
// Status lives on Resource (trait-level status options are deprecated SA1019).
487+
// AgentTrait_AgentStatus and Status_ResourceStatus share the same numeric values
488+
// (READY maps to ENABLED).
489+
var resourceStatus *v2.Status_ResourceStatus
470490
if mappings.Status != "" {
471491
v, err := s.env.EvaluateString(ctx, mappings.Status, inputs)
472492
if err != nil {
473493
return err
474494
}
475495

476-
var status v2.AgentTrait_AgentStatus
496+
var status v2.Status_ResourceStatus
477497
switch strings.ToLower(v) {
478498
case "ready", "active", "enabled":
479-
status = v2.AgentTrait_AGENT_STATUS_READY
499+
status = v2.Status_RESOURCE_STATUS_ENABLED
480500
case "disabled", "inactive":
481-
status = v2.AgentTrait_AGENT_STATUS_DISABLED
501+
status = v2.Status_RESOURCE_STATUS_DISABLED
482502
case "deleted":
483-
status = v2.AgentTrait_AGENT_STATUS_DELETED
503+
status = v2.Status_RESOURCE_STATUS_DELETED
484504
default:
485505
l.Warn("unexpected agent status value in mapping", zap.String("status", v))
486-
status = v2.AgentTrait_AGENT_STATUS_UNSPECIFIED
506+
status = v2.Status_RESOURCE_STATUS_UNSPECIFIED
487507
}
488-
opts = append(opts, sdkResource.WithAgentStatus(status))
508+
resourceStatus = &status
489509
}
490510

491511
if mappings.IdentityResourceID != "" {
@@ -512,6 +532,7 @@ func (s *SQLSyncer) mapAgentTrait(ctx context.Context, r *v2.Resource, rowMap ma
512532
}
513533
}
514534

535+
// Profile lives on Resource (trait-level profile options are deprecated SA1019).
515536
profile := make(map[string]interface{})
516537
for profileKey, profileValue := range mappings.Profile {
517538
v, err := s.env.EvaluateString(ctx, profileValue, inputs)
@@ -520,9 +541,6 @@ func (s *SQLSyncer) mapAgentTrait(ctx context.Context, r *v2.Resource, rowMap ma
520541
}
521542
profile[profileKey] = v
522543
}
523-
if len(profile) > 0 {
524-
opts = append(opts, sdkResource.WithAgentProfile(profile))
525-
}
526544

527545
t, err := sdkResource.NewAgentTrait(opts...)
528546
if err != nil {
@@ -533,6 +551,17 @@ func (s *SQLSyncer) mapAgentTrait(ctx context.Context, r *v2.Resource, rowMap ma
533551
annos.Update(t)
534552
r.Annotations = annos
535553

554+
if resourceStatus != nil {
555+
if err := sdkResource.WithResourceStatus(*resourceStatus, "")(r); err != nil {
556+
return err
557+
}
558+
}
559+
if len(profile) > 0 {
560+
if err := sdkResource.WithResourceProfile(profile)(r); err != nil {
561+
return err
562+
}
563+
}
564+
536565
return nil
537566
}
538567

0 commit comments

Comments
 (0)