From 593a0f44543f22eb6002a4c66e7df3494aee9fba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 16:39:56 -0700 Subject: [PATCH] Bump github.com/conductorone/baton-sdk from 0.1.31 to 0.1.33 (#29) Bumps [github.com/conductorone/baton-sdk](https://github.com/conductorone/baton-sdk) from 0.1.31 to 0.1.33. - [Release notes](https://github.com/conductorone/baton-sdk/releases) - [Commits](https://github.com/conductorone/baton-sdk/compare/v0.1.31...v0.1.33) --- updated-dependencies: - dependency-name: github.com/conductorone/baton-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +- .../baton-sdk/pkg/helpers/helpers.go | 53 ++++++++++++--- .../conductorone/baton-sdk/pkg/sync/syncer.go | 31 +++++++-- .../baton-sdk/pkg/uhttp/wrapper.go | 67 ++++++++++++++----- vendor/modules.txt | 2 +- 6 files changed, 121 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index 0f95c02..ddb93c3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/conductorone/baton-demo go 1.20 require ( - github.com/conductorone/baton-sdk v0.1.31 + github.com/conductorone/baton-sdk v0.1.33 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 go.uber.org/zap v1.26.0 ) diff --git a/go.sum b/go.sum index a2a31e1..9964a07 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/conductorone/baton-sdk v0.1.31 h1:RhCUsXINoleCZ/FrMDXMP1RMhGN6zp+oOeZV6YEOdcI= -github.com/conductorone/baton-sdk v0.1.31/go.mod h1:1VMycIep+HU8JXef2wenT3ECzx1w3Jr3KDQG+L6Mv30= +github.com/conductorone/baton-sdk v0.1.33 h1:0kWu7yCEux+KgUOs1xoo0TFARwN8Tc9/KOP6c4HqdFs= +github.com/conductorone/baton-sdk v0.1.33/go.mod h1:1VMycIep+HU8JXef2wenT3ECzx1w3Jr3KDQG+L6Mv30= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go b/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go index 6fd85cd..b08f689 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go @@ -25,28 +25,33 @@ func SplitFullName(name string) (string, string) { return firstName, lastName } -func ExtractRateLimitData(header *http.Header) (*v2.RateLimitDescription, error) { +func ExtractRateLimitData(statusCode int, header *http.Header) (*v2.RateLimitDescription, error) { if header == nil { return nil, nil } - var l int64 + var rlstatus v2.RateLimitDescription_Status + + var limit int64 var err error - limit := header.Get("X-Ratelimit-Limit") - if limit != "" { - l, err = strconv.ParseInt(limit, 10, 64) + limitStr := header.Get("X-Ratelimit-Limit") + if limitStr != "" { + limit, err = strconv.ParseInt(limitStr, 10, 64) if err != nil { return nil, err } } - var r int64 - remaining := header.Get("X-Ratelimit-Remaining") - if remaining != "" { - r, err = strconv.ParseInt(remaining, 10, 64) + var remaining int64 + remainingStr := header.Get("X-Ratelimit-Remaining") + if remainingStr != "" { + remaining, err = strconv.ParseInt(remainingStr, 10, 64) if err != nil { return nil, err } + if remaining > 0 { + rlstatus = v2.RateLimitDescription_STATUS_OK + } } var resetAt time.Time @@ -60,9 +65,18 @@ func ExtractRateLimitData(header *http.Header) (*v2.RateLimitDescription, error) resetAt = time.Now().Add(time.Second * time.Duration(res)) } + // If we didn't get any rate limit headers and status code is 429, return some sane defaults + if limit == 0 && remaining == 0 && resetAt.IsZero() && statusCode == http.StatusTooManyRequests { + limit = 1 + remaining = 0 + resetAt = time.Now().Add(time.Second * 60) + rlstatus = v2.RateLimitDescription_STATUS_OVERLIMIT + } + return &v2.RateLimitDescription{ - Limit: l, - Remaining: r, + Status: rlstatus, + Limit: limit, + Remaining: remaining, ResetAt: timestamppb.New(resetAt), }, nil } @@ -78,3 +92,20 @@ func IsJSONContentType(contentType string) bool { return true } + +var xmlContentTypes []string = []string{ + "text/xml", + "application/xml", +} + +func IsXMLContentType(contentType string) bool { + // there are some janky APIs out there + normalizedContentType := strings.TrimSpace(strings.ToLower(contentType)) + + for _, xmlContentType := range xmlContentTypes { + if normalizedContentType == xmlContentType { + return true + } + } + return false +} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go b/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go index 3230633..92fef38 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go @@ -11,6 +11,8 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" c1zpb "github.com/conductorone/baton-sdk/pb/c1/c1z/v1" @@ -72,6 +74,25 @@ func (s *syncer) handleProgress(ctx context.Context, a *Action, c int) { } } +func shouldWaitAndRetry(ctx context.Context, err error) bool { + if status.Code(err) != codes.Unavailable { + return false + } + + l := ctxzap.Extract(ctx) + l.Error("retrying operation", zap.Error(err)) + + for { + select { + // TODO: this should back off based on error counts + case <-time.After(1 * time.Second): + return true + case <-ctx.Done(): + return false + } + } +} + // Sync starts the syncing process. The sync process is driven by the action stack that is part of the state object. // For each page of data that is required to be fetched from the connector, a new action is pushed on to the stack. Once // an action is completed, it is popped off of the queue. Before procesing each action, we checkpoint the state object @@ -162,28 +183,28 @@ func (s *syncer) Sync(ctx context.Context) error { case SyncResourceTypesOp: err = s.SyncResourceTypes(ctx) - if err != nil { + if err != nil && !shouldWaitAndRetry(ctx, err) { return err } continue case SyncResourcesOp: err = s.SyncResources(ctx) - if err != nil { + if err != nil && !shouldWaitAndRetry(ctx, err) { return err } continue case SyncEntitlementsOp: err = s.SyncEntitlements(ctx) - if err != nil { + if err != nil && !shouldWaitAndRetry(ctx, err) { return err } continue case SyncGrantsOp: err = s.SyncGrants(ctx) - if err != nil { + if err != nil && !shouldWaitAndRetry(ctx, err) { return err } continue @@ -203,7 +224,7 @@ func (s *syncer) Sync(ctx context.Context) error { } err = s.SyncGrantExpansion(ctx) - if err != nil { + if err != nil && !shouldWaitAndRetry(ctx, err) { return err } continue diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go b/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go index 481c128..2b4a1e2 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go @@ -16,6 +16,8 @@ import ( "google.golang.org/grpc/status" ) +const ContentType = "Content-Type" + type WrapperResponse struct { Header http.Header Body []byte @@ -45,6 +47,9 @@ func NewBaseHttpClient(httpClient *http.Client) *BaseHttpClient { func WithJSONResponse(response interface{}) DoOption { return func(resp *WrapperResponse) error { + if !helpers.IsJSONContentType(resp.Header.Get(ContentType)) { + return fmt.Errorf("unexpected content type for json response: %s", resp.Header.Get(ContentType)) + } return json.Unmarshal(resp.Body, response) } } @@ -59,7 +64,7 @@ func WithErrorResponse(resource ErrorResponse) DoOption { return nil } - if !helpers.IsJSONContentType(resp.Header.Get("Content-Type")) { + if !helpers.IsJSONContentType(resp.Header.Get(ContentType)) { return fmt.Errorf("%v", string(resp.Body)) } @@ -77,7 +82,7 @@ func WithErrorResponse(resource ErrorResponse) DoOption { func WithRatelimitData(resource *v2.RateLimitDescription) DoOption { return func(resp *WrapperResponse) error { - rl, err := helpers.ExtractRateLimitData(&resp.Header) + rl, err := helpers.ExtractRateLimitData(resp.StatusCode, &resp.Header) if err != nil { return err } @@ -85,6 +90,7 @@ func WithRatelimitData(resource *v2.RateLimitDescription) DoOption { resource.Limit = rl.Limit resource.Remaining = rl.Remaining resource.ResetAt = rl.ResetAt + resource.Status = rl.Status return nil } @@ -92,10 +98,26 @@ func WithRatelimitData(resource *v2.RateLimitDescription) DoOption { func WithXMLResponse(response interface{}) DoOption { return func(resp *WrapperResponse) error { + if !helpers.IsXMLContentType(resp.Header.Get(ContentType)) { + return fmt.Errorf("unexpected content type for xml response: %s", resp.Header.Get(ContentType)) + } return xml.Unmarshal(resp.Body, response) } } +func WithResponse(response interface{}) DoOption { + return func(resp *WrapperResponse) error { + if helpers.IsJSONContentType(resp.Header.Get(ContentType)) { + return WithJSONResponse(response)(resp) + } + if helpers.IsXMLContentType(resp.Header.Get(ContentType)) { + return WithXMLResponse(response)(resp) + } + + return status.Error(codes.Unknown, "unsupported content type") + } +} + func (c *BaseHttpClient) Do(req *http.Request, options ...DoOption) (*http.Response, error) { resp, err := c.HttpClient.Do(req) if err != nil { @@ -127,13 +149,34 @@ func (c *BaseHttpClient) Do(req *http.Request, options ...DoOption) (*http.Respo } } + switch resp.StatusCode { + case http.StatusTooManyRequests: + return resp, status.Error(codes.Unavailable, resp.Status) + case http.StatusNotFound: + return resp, status.Error(codes.NotFound, resp.Status) + case http.StatusUnauthorized: + return resp, status.Error(codes.Unauthenticated, resp.Status) + case http.StatusForbidden: + return resp, status.Error(codes.PermissionDenied, resp.Status) + case http.StatusNotImplemented: + return resp, status.Error(codes.Unimplemented, resp.Status) + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return resp, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + return resp, status.Error(codes.Unknown, fmt.Sprintf("unexpected status code: %d", resp.StatusCode)) } return resp, err } +func WithHeader(key, value string) RequestOption { + return func() (io.ReadWriter, map[string]string, error) { + return nil, map[string]string{ + key: value, + }, nil + } +} + func WithJSONBody(body interface{}) RequestOption { return func() (io.ReadWriter, map[string]string, error) { buffer := new(bytes.Buffer) @@ -152,27 +195,15 @@ func WithJSONBody(body interface{}) RequestOption { } func WithAcceptJSONHeader() RequestOption { - return func() (io.ReadWriter, map[string]string, error) { - return nil, map[string]string{ - "Accept": "application/json", - }, nil - } + return WithHeader("Accept", "application/json") } func WithContentTypeJSONHeader() RequestOption { - return func() (io.ReadWriter, map[string]string, error) { - return nil, map[string]string{ - "Content-Type": "application/json", - }, nil - } + return WithHeader("Content-Type", "application/json") } func WithAcceptXMLHeader() RequestOption { - return func() (io.ReadWriter, map[string]string, error) { - return nil, map[string]string{ - "Accept": "application/xml", - }, nil - } + return WithHeader("Accept", "application/xml") } func (c *BaseHttpClient) NewRequest(ctx context.Context, method string, url *url.URL, options ...RequestOption) (*http.Request, error) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 92e9c09..babafd9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -135,7 +135,7 @@ github.com/aws/smithy-go/waiter # github.com/benbjohnson/clock v1.3.5 ## explicit; go 1.15 github.com/benbjohnson/clock -# github.com/conductorone/baton-sdk v0.1.31 +# github.com/conductorone/baton-sdk v0.1.33 ## explicit; go 1.20 github.com/conductorone/baton-sdk/internal/connector github.com/conductorone/baton-sdk/pb/c1/c1z/v1