-
Notifications
You must be signed in to change notification settings - Fork 0
[BB-1755, BB-1771]Add retry logic for not found errors in connector methods and fix missed grants with oauth #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -189,50 +189,48 @@ func (g *groupBuilder) Grants(ctx context.Context, resource *v2.Resource, pToken | |||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: failed to parse group resource id: %w", err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| groupTrait, err := rs.GetGroupTrait(resource) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return nil, "", nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| var workspaceId string | ||||||||||||||||||||||||||||
| isWorkspaceGroup := parentId.ResourceType == workspaceResourceType.Id | ||||||||||||||||||||||||||||
| if isWorkspaceGroup { | ||||||||||||||||||||||||||||
| workspaceId = parentId.Resource | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // membership grants | ||||||||||||||||||||||||||||
| membersPayload, ok := rs.GetProfileStringValue(groupTrait.Profile, "members") | ||||||||||||||||||||||||||||
| if ok { | ||||||||||||||||||||||||||||
| members := strings.Split(membersPayload, ",") | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| for _, m := range members { | ||||||||||||||||||||||||||||
| pp := strings.Split(m, "/") | ||||||||||||||||||||||||||||
| if len(pp) != 2 { | ||||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: invalid member format of %s: %w", m, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| // Always fetch the group with members attribute to ensure we get the members | ||||||||||||||||||||||||||||
| // regardless of authentication type (OAuth vs personal access token) | ||||||||||||||||||||||||||||
| group, _, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource, databricks.NewGroupAttrVars()) | ||||||||||||||||||||||||||||
FeliLucero1 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId.Resource, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+199
to
+204
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apply retry wrapper consistently with Grant and Revoke methods. The Apply this diff: group, rateLimitData, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource, databricks.NewGroupAttrVars())
if err != nil {
+ err = makeRetryableIfNotFound(err)
return nil, "", nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId.Resource, err)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| memberType, memberID := pp[0], pp[1] | ||||||||||||||||||||||||||||
| var resourceId *v2.ResourceId | ||||||||||||||||||||||||||||
| var anns []protoreflect.ProtoMessage | ||||||||||||||||||||||||||||
| for _, member := range group.Members { | ||||||||||||||||||||||||||||
| // member.Ref contains the type and ID separated by "/", e.g., "Users/123" or "Groups/456" | ||||||||||||||||||||||||||||
| pp := strings.Split(member.Ref, "/") | ||||||||||||||||||||||||||||
| if len(pp) != 2 { | ||||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: invalid member format of %s", member.Ref) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| switch memberType { | ||||||||||||||||||||||||||||
| case "Users": | ||||||||||||||||||||||||||||
| resourceId = &v2.ResourceId{ResourceType: userResourceType.Id, Resource: memberID} | ||||||||||||||||||||||||||||
| case "Groups": | ||||||||||||||||||||||||||||
| rid, expandAnnotation, err := groupGrantExpansion(ctx, memberID, parentId) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return rv, "", nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| resourceId = rid | ||||||||||||||||||||||||||||
| anns = append(anns, expandAnnotation) | ||||||||||||||||||||||||||||
| case "ServicePrincipals": | ||||||||||||||||||||||||||||
| resourceId = &v2.ResourceId{ResourceType: servicePrincipalResourceType.Id, Resource: memberID} | ||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: invalid member type: %s", memberType) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| memberType, memberID := pp[0], pp[1] | ||||||||||||||||||||||||||||
| var resourceId *v2.ResourceId | ||||||||||||||||||||||||||||
| var anns []protoreflect.ProtoMessage | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| rv = append(rv, grant.NewGrant(resource, groupMemberEntitlement, resourceId, grant.WithAnnotation(anns...))) | ||||||||||||||||||||||||||||
| switch memberType { | ||||||||||||||||||||||||||||
| case "Users": | ||||||||||||||||||||||||||||
| resourceId = &v2.ResourceId{ResourceType: userResourceType.Id, Resource: memberID} | ||||||||||||||||||||||||||||
| case "Groups": | ||||||||||||||||||||||||||||
| rid, expandAnnotation, err := groupGrantExpansion(ctx, memberID, parentId) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| return rv, "", nil, err | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| resourceId = rid | ||||||||||||||||||||||||||||
| anns = append(anns, expandAnnotation) | ||||||||||||||||||||||||||||
| case "ServicePrincipals": | ||||||||||||||||||||||||||||
| resourceId = &v2.ResourceId{ResourceType: servicePrincipalResourceType.Id, Resource: memberID} | ||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||
| return nil, "", nil, fmt.Errorf("databricks-connector: invalid member type: %s", memberType) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| rv = append(rv, grant.NewGrant(resource, groupMemberEntitlement, resourceId, grant.WithAnnotation(anns...))) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // role permissions grants | ||||||||||||||||||||||||||||
|
|
@@ -306,8 +304,9 @@ func (g *groupBuilder) Grant(ctx context.Context, principal *v2.Resource, entitl | |||||||||||||||||||||||||||
| membershipEntitlementID := ent.NewEntitlementID(entitlement.Resource, groupMemberEntitlement) | ||||||||||||||||||||||||||||
| managerEntitlementID := ent.NewEntitlementID(entitlement.Resource, groupManagerEntitlement) | ||||||||||||||||||||||||||||
| if entitlement.Id == membershipEntitlementID { | ||||||||||||||||||||||||||||
| group, _, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource) | ||||||||||||||||||||||||||||
| group, _, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource, databricks.NewGroupAttrVars()) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| err = makeRetryableIfNotFound(err) | ||||||||||||||||||||||||||||
| return nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId.Resource, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
@@ -449,8 +448,9 @@ func (g *groupBuilder) Revoke(ctx context.Context, grant *v2.Grant) (annotations | |||||||||||||||||||||||||||
| membershipEntitlementID := ent.NewEntitlementID(entitlement.Resource, groupMemberEntitlement) | ||||||||||||||||||||||||||||
| managerEntitlementID := ent.NewEntitlementID(entitlement.Resource, groupManagerEntitlement) | ||||||||||||||||||||||||||||
| if entitlement.Id == membershipEntitlementID { | ||||||||||||||||||||||||||||
| group, _, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource) | ||||||||||||||||||||||||||||
| group, _, err := g.client.GetGroup(ctx, workspaceId, groupId.Resource, databricks.NewGroupAttrVars()) | ||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||
| err = makeRetryableIfNotFound(err) | ||||||||||||||||||||||||||||
| return nil, fmt.Errorf("databricks-connector: failed to get group %s: %w", groupId.Resource, err) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ import ( | |
|
|
||
| v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2" | ||
| "github.com/conductorone/baton-sdk/pkg/uhttp" | ||
| "google.golang.org/grpc/codes" | ||
| "google.golang.org/grpc/status" | ||
|
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify the gRPC library version. The imports are necessary for the new error handling, but the library context indicates Run the following script to check the gRPC version in use: 🏁 Script executed: #!/bin/bash
# Check the version of google.golang.org/grpc in go.mod
cat go.mod | grep "google.golang.org/grpc"Length of output: 144 💡 Result: Short answer: don't use a -dev module version in production. The "-dev" suffix denotes a development (unpublished/unstable) build; use an official tagged release (for example v1.73.0 or a later non-dev release) and pin that version after testing. [1][2][3] Details and sources:
If you want, I can look up the latest non-dev grpc-go release right now and suggest the exact module line to put in go.mod. 🌐 Web query: 💡 Result: grpc-go v1.73.0 (stable) was released on June 5, 2025. [1][2] Sources: Address the development version dependency before production use. The gRPC library version 🤖 Prompt for AI Agents |
||
| ) | ||
|
|
||
| const ( | ||
|
|
@@ -195,7 +197,7 @@ func (c *Client) FindUserID( | |
| } | ||
|
|
||
| if len(users) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("user not found: %s", username)) | ||
| } | ||
|
|
||
| return users[0].ID, ratelimitData, nil | ||
|
|
@@ -222,7 +224,7 @@ func (c *Client) FindUsername( | |
| } | ||
|
|
||
| if len(users) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("user not found: %s", userID)) | ||
| } | ||
|
|
||
| return users[0].UserName, ratelimitData, nil | ||
|
|
@@ -254,7 +256,7 @@ func (c *Client) ListGroups( | |
| return res.Resources, res.Total, ratelimitData, nil | ||
| } | ||
|
|
||
| func (c *Client) GetGroup(ctx context.Context, workspaceId, groupId string) ( | ||
| func (c *Client) GetGroup(ctx context.Context, workspaceId, groupId string, vars ...Vars) ( | ||
| *Group, | ||
| *v2.RateLimitDescription, | ||
| error, | ||
|
|
@@ -267,7 +269,7 @@ func (c *Client) GetGroup(ctx context.Context, workspaceId, groupId string) ( | |
| } | ||
|
|
||
| var res *Group | ||
| ratelimitData, err := c.Get(ctx, u, &res) | ||
| ratelimitData, err := c.Get(ctx, u, &res, vars...) | ||
| if err != nil { | ||
| return nil, ratelimitData, err | ||
| } | ||
|
|
@@ -307,7 +309,7 @@ func (c *Client) FindGroupID( | |
| } | ||
|
|
||
| if len(groups) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("group not found: %s", displayName)) | ||
| } | ||
|
|
||
| return groups[0].ID, ratelimitData, nil | ||
|
|
@@ -334,7 +336,7 @@ func (c *Client) FindGroupDisplayName( | |
| } | ||
|
|
||
| if len(groups) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("group not found: %s", groupID)) | ||
| } | ||
|
|
||
| return groups[0].DisplayName, ratelimitData, nil | ||
|
|
@@ -425,7 +427,7 @@ func (c *Client) FindServicePrincipalID( | |
| } | ||
|
|
||
| if len(servicePrincipals) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("service principal not found: %s", appID)) | ||
| } | ||
|
|
||
| return servicePrincipals[0].ID, ratelimitData, nil | ||
|
|
@@ -452,7 +454,7 @@ func (c *Client) FindServicePrincipalAppID( | |
| } | ||
|
|
||
| if len(servicePrincipals) == 0 { | ||
| return "", ratelimitData, err | ||
| return "", ratelimitData, status.Error(codes.NotFound, fmt.Sprintf("service principal not found: %s", servicePrincipalID)) | ||
| } | ||
|
|
||
| return servicePrincipals[0].ApplicationID, ratelimitData, nil | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@FeliLucero1 was the group trait missing members? or just didn't include them at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used to lose some
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that the users It wasn't losing were users who had permissions over the group but weren't members of it, therefore It was losing all members