Skip to content

Commit 10d8a0b

Browse files
wrap errors with grpc
1 parent df23961 commit 10d8a0b

File tree

9 files changed

+265
-157
lines changed

9 files changed

+265
-157
lines changed

go.sum

Lines changed: 36 additions & 0 deletions
Large diffs are not rendered by default.

pkg/connector/actions.go

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"strings"
88

99
"github.com/conductorone/baton-sdk/pkg/annotations"
10+
"github.com/conductorone/baton-sdk/pkg/uhttp"
1011
datatransferAdmin "google.golang.org/api/admin/datatransfer/v1"
1112
directoryAdmin "google.golang.org/api/admin/directory/v1"
13+
"google.golang.org/grpc/codes"
1214
"google.golang.org/protobuf/types/known/structpb"
1315
)
1416

@@ -21,17 +23,17 @@ const (
2123
func (c *GoogleWorkspace) updateUserStatus(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
2224
guidField, ok := args.Fields["resource_id"].GetKind().(*structpb.Value_StringValue)
2325
if !ok {
24-
return nil, nil, fmt.Errorf("missing resource ID")
26+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing resource ID")
2527
}
2628

2729
isSuspendedField, ok := args.Fields["is_suspended"].GetKind().(*structpb.Value_BoolValue)
2830
if !ok {
29-
return nil, nil, fmt.Errorf("missing is_suspended")
31+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing is_suspended")
3032
}
3133

3234
userService, err := c.getDirectoryService(ctx, directoryAdmin.AdminDirectoryUserScope)
3335
if err != nil {
34-
return nil, nil, err
36+
return nil, nil, fmt.Errorf("google-workspace: failed to get directory service for updateUserStatus: %w", err)
3537
}
3638

3739
isSuspended := isSuspendedField.BoolValue
@@ -44,7 +46,7 @@ func (c *GoogleWorkspace) updateUserStatus(ctx context.Context, args *structpb.S
4446
ForceSendFields: []string{"Suspended"},
4547
}).Context(ctx).Do()
4648
if err != nil {
47-
return nil, nil, err
49+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to update user status: %s", userId))
4850
}
4951

5052
response := structpb.Struct{
@@ -62,20 +64,20 @@ func (c *GoogleWorkspace) updateUserStatus(ctx context.Context, args *structpb.S
6264
func (c *GoogleWorkspace) disableUserActionHandler(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
6365
guidField, ok := args.Fields["user_id"].GetKind().(*structpb.Value_StringValue)
6466
if !ok {
65-
return nil, nil, fmt.Errorf("missing user ID")
67+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing user ID")
6668
}
6769

6870
userService, err := c.getDirectoryService(ctx, directoryAdmin.AdminDirectoryUserScope)
6971
if err != nil {
70-
return nil, nil, err
72+
return nil, nil, fmt.Errorf("google-workspace: failed to get directory service for disableUser: %w", err)
7173
}
7274

7375
userId := guidField.StringValue
7476

7577
// fetch current to ensure idempotency
7678
u, err := userService.Users.Get(userId).Context(ctx).Do()
7779
if err != nil {
78-
return nil, nil, err
80+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to get user %s for disableUser", userId))
7981
}
8082
if u.Suspended { // already suspended
8183
response := structpb.Struct{Fields: map[string]*structpb.Value{
@@ -92,7 +94,7 @@ func (c *GoogleWorkspace) disableUserActionHandler(ctx context.Context, args *st
9294
},
9395
).Context(ctx).Do()
9496
if err != nil {
95-
return nil, nil, err
97+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to suspend user in disableUser: %s", userId))
9698
}
9799

98100
response := structpb.Struct{Fields: map[string]*structpb.Value{
@@ -105,20 +107,20 @@ func (c *GoogleWorkspace) disableUserActionHandler(ctx context.Context, args *st
105107
func (c *GoogleWorkspace) enableUserActionHandler(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
106108
guidField, ok := args.Fields["user_id"].GetKind().(*structpb.Value_StringValue)
107109
if !ok {
108-
return nil, nil, fmt.Errorf("missing user ID")
110+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing user ID")
109111
}
110112

111113
userService, err := c.getDirectoryService(ctx, directoryAdmin.AdminDirectoryUserScope)
112114
if err != nil {
113-
return nil, nil, err
115+
return nil, nil, fmt.Errorf("google-workspace: failed to get directory service for enableUser: %w", err)
114116
}
115117

116118
userId := guidField.StringValue
117119

118120
// fetch current to ensure idempotency
119121
u, err := userService.Users.Get(userId).Context(ctx).Do()
120122
if err != nil {
121-
return nil, nil, err
123+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to get user %s for enableUser", userId))
122124
}
123125
if !u.Suspended { // already active
124126
response := structpb.Struct{Fields: map[string]*structpb.Value{
@@ -135,7 +137,7 @@ func (c *GoogleWorkspace) enableUserActionHandler(ctx context.Context, args *str
135137
},
136138
).Context(ctx).Do()
137139
if err != nil {
138-
return nil, nil, err
140+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to unsuspend user: %s", userId))
139141
}
140142

141143
response := structpb.Struct{Fields: map[string]*structpb.Value{
@@ -148,30 +150,30 @@ func (c *GoogleWorkspace) enableUserActionHandler(ctx context.Context, args *str
148150
func (c *GoogleWorkspace) changeUserPrimaryEmail(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
149151
guidField, ok := args.Fields["resource_id"].GetKind().(*structpb.Value_StringValue)
150152
if !ok {
151-
return nil, nil, fmt.Errorf("missing resource ID")
153+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing resource ID")
152154
}
153155
newEmailField, ok := args.Fields["new_primary_email"].GetKind().(*structpb.Value_StringValue)
154156
if !ok {
155-
return nil, nil, fmt.Errorf("missing new_primary_email")
157+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing new_primary_email")
156158
}
157159

158160
userId := guidField.StringValue
159161
newPrimary := newEmailField.StringValue
160162

161163
// Validate that newPrimary is a valid email address
162164
if _, err := mail.ParseAddress(newPrimary); err != nil {
163-
return nil, nil, fmt.Errorf("invalid email address '%s': %w", newPrimary, err)
165+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, fmt.Sprintf("google-workspace: invalid email address: %s", newPrimary), err)
164166
}
165167

166168
userService, err := c.getDirectoryService(ctx, directoryAdmin.AdminDirectoryUserScope)
167169
if err != nil {
168-
return nil, nil, err
170+
return nil, nil, fmt.Errorf("google-workspace: failed to get directory service for changeUserPrimaryEmail: %w", err)
169171
}
170172

171173
// fetch current for return payload
172174
u, err := userService.Users.Get(userId).Context(ctx).Do()
173175
if err != nil {
174-
return nil, nil, err
176+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to get user %s for changeUserPrimaryEmail", userId))
175177
}
176178
prev := u.PrimaryEmail
177179
if emailsEqual(prev, newPrimary) { // Already primary email
@@ -191,7 +193,7 @@ func (c *GoogleWorkspace) changeUserPrimaryEmail(ctx context.Context, args *stru
191193
},
192194
).Context(ctx).Do()
193195
if err != nil {
194-
return nil, nil, err
196+
return nil, nil, wrapGoogleApiErrorWithContext(err, fmt.Sprintf("google-workspace: failed to update user primary email: %s", userId))
195197
}
196198

197199
response := structpb.Struct{Fields: map[string]*structpb.Value{
@@ -206,28 +208,28 @@ func (c *GoogleWorkspace) changeUserPrimaryEmail(ctx context.Context, args *stru
206208
func (c *GoogleWorkspace) transferUserDriveFiles(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
207209
sourceField, ok := args.Fields["resource_id"].GetKind().(*structpb.Value_StringValue)
208210
if !ok {
209-
return nil, nil, fmt.Errorf("missing resource_id")
211+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing resource_id")
210212
}
211213
targetField, ok := args.Fields["target_resource_id"].GetKind().(*structpb.Value_StringValue)
212214
if !ok {
213-
return nil, nil, fmt.Errorf("missing target_resource_id")
215+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing target_resource_id")
214216
}
215217

216218
// Validate non-empty and different user keys
217219
src := strings.TrimSpace(sourceField.StringValue)
218220
dst := strings.TrimSpace(targetField.StringValue)
219221
if src == "" || dst == "" {
220-
return nil, nil, fmt.Errorf("resource_id and target_resource_id must be non-empty")
222+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: resource_id and target_resource_id must be non-empty")
221223
}
222224
if strings.EqualFold(src, dst) {
223-
return nil, nil, fmt.Errorf("resource_id and target_resource_id must be different")
225+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: resource_id and target_resource_id must be different")
224226
}
225227

226228
// Build Drive params from privacy_levels
227229
params := []*datatransferAdmin.ApplicationTransferParam{}
228230
levels, err := parseDrivePrivacyLevels(args)
229231
if err != nil {
230-
return nil, nil, err
232+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: failed to parse privacy levels", err)
231233
}
232234
params = append(params, &datatransferAdmin.ApplicationTransferParam{Key: "PRIVACY_LEVEL", Value: levels})
233235

@@ -238,26 +240,26 @@ func (c *GoogleWorkspace) transferUserDriveFiles(ctx context.Context, args *stru
238240
func (c *GoogleWorkspace) transferUserCalendar(ctx context.Context, args *structpb.Struct) (*structpb.Struct, annotations.Annotations, error) {
239241
sourceField, ok := args.Fields["resource_id"].GetKind().(*structpb.Value_StringValue)
240242
if !ok {
241-
return nil, nil, fmt.Errorf("missing resource_id")
243+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing resource_id")
242244
}
243245
targetField, ok := args.Fields["target_resource_id"].GetKind().(*structpb.Value_StringValue)
244246
if !ok {
245-
return nil, nil, fmt.Errorf("missing target_resource_id")
247+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: missing target_resource_id")
246248
}
247249

248250
// Validate non-empty and different user keys
249251
src := strings.TrimSpace(sourceField.StringValue)
250252
dst := strings.TrimSpace(targetField.StringValue)
251253
if src == "" || dst == "" {
252-
return nil, nil, fmt.Errorf("resource_id and target_resource_id must be non-empty")
254+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: resource_id and target_resource_id must be non-empty")
253255
}
254256
if strings.EqualFold(src, dst) {
255-
return nil, nil, fmt.Errorf("resource_id and target_resource_id must be different")
257+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: resource_id and target_resource_id must be different")
256258
}
257259

258260
params := []*datatransferAdmin.ApplicationTransferParam{}
259261
if p, err := buildReleaseResourcesParam(args); err != nil {
260-
return nil, nil, err
262+
return nil, nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: failed to build release resources param", err)
261263
} else if p != nil {
262264
params = append(params, p)
263265
}
@@ -269,7 +271,7 @@ func (c *GoogleWorkspace) transferUserCalendar(ctx context.Context, args *struct
269271
func (c *GoogleWorkspace) dataTransferInsert(ctx context.Context, appID int64, oldOwnerUserId, newOwnerUserId string, params []*datatransferAdmin.ApplicationTransferParam) (*structpb.Struct, annotations.Annotations, error) {
270272
dtService, err := c.getDataTransferService(ctx, datatransferAdmin.AdminDatatransferScope)
271273
if err != nil {
272-
return nil, nil, err
274+
return nil, nil, fmt.Errorf("google-workspace: failed to get data transfer service: %w", err)
273275
}
274276

275277
pageToken := ""
@@ -282,7 +284,7 @@ func (c *GoogleWorkspace) dataTransferInsert(ctx context.Context, appID int64, o
282284
}
283285
transfers, err := listCall.Context(ctx).Do()
284286
if err != nil {
285-
return nil, nil, err
287+
return nil, nil, wrapGoogleApiErrorWithContext(err, "google-workspace: failed to list data transfers")
286288
}
287289
if transfers != nil {
288290
for _, t := range transfers.DataTransfers {
@@ -320,7 +322,7 @@ func (c *GoogleWorkspace) dataTransferInsert(ctx context.Context, appID int64, o
320322

321323
created, err := dtService.Transfers.Insert(transfer).Context(ctx).Do()
322324
if err != nil {
323-
return nil, nil, err
325+
return nil, nil, wrapGoogleApiErrorWithContext(err, "google-workspace: failed to create data transfer")
324326
}
325327

326328
resp := &structpb.Struct{Fields: map[string]*structpb.Value{
@@ -340,7 +342,7 @@ func buildReleaseResourcesParam(args *structpb.Struct) (*datatransferAdmin.Appli
340342
}
341343
b, ok := v.GetKind().(*structpb.Value_BoolValue)
342344
if !ok {
343-
return nil, fmt.Errorf("release_resources must be a boolean")
345+
return nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: release_resources must be a boolean")
344346
}
345347
if !b.BoolValue {
346348
return nil, nil
@@ -361,29 +363,29 @@ func parseDrivePrivacyLevels(args *structpb.Struct) ([]string, error) {
361363
}
362364
ss, ok := v.GetKind().(*structpb.Value_ListValue)
363365
if !ok {
364-
return nil, fmt.Errorf("privacy_levels must be a list of strings: allowed values are private, shared")
366+
return nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: privacy_levels must be a list of strings: allowed values are private, shared")
365367
}
366368
normalized := make([]string, 0, len(ss.ListValue.Values))
367369
seen := map[string]bool{}
368370
for _, lv := range ss.ListValue.Values {
369371
sv, ok := lv.GetKind().(*structpb.Value_StringValue)
370372
if !ok {
371-
return nil, fmt.Errorf("privacy_levels must be a list of strings: allowed values are private, shared")
373+
return nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: privacy_levels must be a list of strings: allowed values are private, shared")
372374
}
373375
s := strings.TrimSpace(strings.ToLower(sv.StringValue))
374376
if s == "" {
375377
continue
376378
}
377379
if !allowed[s] {
378-
return nil, fmt.Errorf("invalid privacy_levels value '%s': allowed values are private, shared", sv.StringValue)
380+
return nil, uhttp.WrapErrors(codes.InvalidArgument, fmt.Sprintf("google-workspace: invalid privacy_levels value '%s': allowed values are private, shared", sv.StringValue))
379381
}
380382
if !seen[s] {
381383
normalized = append(normalized, s)
382384
seen[s] = true
383385
}
384386
}
385387
if len(normalized) == 0 {
386-
return nil, fmt.Errorf("privacy_levels list must include at least one value: private or shared")
388+
return nil, uhttp.WrapErrors(codes.InvalidArgument, "google-workspace: privacy_levels list must include at least one value: private or shared")
387389
}
388390
return normalized, nil
389391
}

0 commit comments

Comments
 (0)