diff --git a/go.mod b/go.mod index 2565a82..f7a9034 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/conductorone/baton-vgs go 1.22.1 require ( - github.com/conductorone/baton-sdk v0.2.20 + github.com/conductorone/baton-sdk v0.2.23 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 21963a5..8e6c03e 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/conductorone/baton-sdk v0.2.20 h1:IpXur6BYJkePwDqOv3AsTP5oFeIDEzgtMvo7FSlOTzE= -github.com/conductorone/baton-sdk v0.2.20/go.mod h1:hmd/Oz3DPIKD+9QmkusZaA18ZoiinnTDdrxh2skcdUc= +github.com/conductorone/baton-sdk v0.2.23 h1:52TzmvBypE0MLXFoUeYp51g1SFmbnq7qGVdt3d2OEQc= +github.com/conductorone/baton-sdk v0.2.23/go.mod h1:hmd/Oz3DPIKD+9QmkusZaA18ZoiinnTDdrxh2skcdUc= 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/internal/connector/connector_server_unix.go b/vendor/github.com/conductorone/baton-sdk/internal/connector/connector_server_unix.go index ed4e03e..ab7f121 100644 --- a/vendor/github.com/conductorone/baton-sdk/internal/connector/connector_server_unix.go +++ b/vendor/github.com/conductorone/baton-sdk/internal/connector/connector_server_unix.go @@ -14,6 +14,11 @@ import ( "go.uber.org/zap" ) +func getPort(listener net.Listener) uint32 { + //nolint:gosec // No risk of overflow because `Port` is 16-bit. + return uint32(listener.Addr().(*net.TCPAddr).Port) +} + func (cw *wrapper) setupListener(ctx context.Context) (uint32, *os.File, error) { l := ctxzap.Extract(ctx) @@ -25,7 +30,7 @@ func (cw *wrapper) setupListener(ctx context.Context) (uint32, *os.File, error) if err != nil { return 0, nil, err } - listenPort := uint32(listener.Addr().(*net.TCPAddr).Port) + listenPort := getPort(listener) listenerFile, err := listener.File() if err != nil { return 0, nil, err @@ -58,7 +63,7 @@ func (cw *wrapper) getListener(ctx context.Context, serverCfg *connectorwrapperV return nil, err } - listenPort := uint32(listener.Addr().(*net.TCPAddr).Port) + listenPort := getPort(listener) if listenPort != serverCfg.ListenPort { return nil, fmt.Errorf("listen port mismatch: %d != %d", listenPort, serverCfg.ListenPort) } diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/annotations/annotations.go b/vendor/github.com/conductorone/baton-sdk/pkg/annotations/annotations.go index 19eda94..e1284bd 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/annotations/annotations.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/annotations/annotations.go @@ -10,7 +10,7 @@ import ( type Annotations []*anypb.Any -// Convenience function to create annotations. +// New - Convenience function to create annotations. func New(msgs ...proto.Message) Annotations { annos := Annotations{} for _, msg := range msgs { diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/config/config.go b/vendor/github.com/conductorone/baton-sdk/pkg/config/config.go index 45d2b09..2a19a42 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/config/config.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/config/config.go @@ -157,6 +157,8 @@ func DefineConfiguration( mainCMD.MarkFlagsOneRequired(listFieldConstrainsAsStrings(constrain)...) case field.Dependents: // do nothing + default: + return nil, nil, fmt.Errorf("invalid config") } } diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/dotc1z/decoder.go b/vendor/github.com/conductorone/baton-sdk/pkg/dotc1z/decoder.go index ee27fd0..dcef25d 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/dotc1z/decoder.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/dotc1z/decoder.go @@ -14,8 +14,8 @@ import ( ) const ( - defaultMaxDecodedSize = 2 * 1024 * 1024 * 1024 // 2GiB - defaultDecoderMaxMemory = 32 * 1024 * 1024 // 32MiB + defaultMaxDecodedSize = 3 * 1024 * 1024 * 1024 // 3GiB + defaultDecoderMaxMemory = 128 * 1024 * 1024 // 128MiB maxDecodedSizeEnvVar = "BATON_DECODER_MAX_DECODED_SIZE_MB" maxDecoderMemorySizeEnv = "BATON_DECODER_MAX_MEMORY_MB" ) @@ -24,8 +24,8 @@ var C1ZFileHeader = []byte("C1ZF\x00") var ( ErrInvalidFile = fmt.Errorf("c1z: invalid file") - ErrMaxSizeExceeded = errors.New("c1z: max decoded size exceeded, increase DecoderMaxDecodedSize") - ErrWindowSizeExceeded = errors.New("c1z: window size exceeded, increase DecoderMaxMemory") + ErrMaxSizeExceeded = fmt.Errorf("c1z: max decoded size exceeded, increase DecoderMaxDecodedSize using %v environment variable", maxDecodedSizeEnvVar) + ErrWindowSizeExceeded = fmt.Errorf("c1z: window size exceeded, increase DecoderMaxMemory using %v environment variable", maxDecoderMemorySizeEnv) ) // ReadHeader reads len(C1ZFileHeader) bytes from the given io.Reader and compares them to C1ZFileHeader, returning an error if they don't match. diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/field/fields.go b/vendor/github.com/conductorone/baton-sdk/pkg/field/fields.go index 4413407..006d6e3 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/field/fields.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/field/fields.go @@ -51,7 +51,7 @@ func (s SchemaField) String() (string, error) { return value, nil } -// StringSlice retuns the default value as a string array. +// StringSlice returns the default value as a string array. func (s SchemaField) StringSlice() ([]string, error) { value, ok := s.DefaultValue.([]string) if !ok { diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/field/relationships.go b/vendor/github.com/conductorone/baton-sdk/pkg/field/relationships.go index 769f822..6e589b6 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/field/relationships.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/field/relationships.go @@ -3,7 +3,8 @@ package field type Relationship int const ( - RequiredTogether Relationship = iota + 1 + Invalid Relationship = iota + RequiredTogether MutuallyExclusive AtLeastOne Dependents @@ -15,31 +16,87 @@ type SchemaFieldRelationship struct { ExpectedFields []SchemaField } +func countFieldNames(fields ...SchemaField) int { + seen := map[string]bool{} + for _, field := range fields { + seen[field.FieldName] = true + } + return len(seen) +} + +// FieldsRequiredTogether - the provided fields are valid if and only if every +// provided field is present. func FieldsRequiredTogether(fields ...SchemaField) SchemaFieldRelationship { + count := countFieldNames(fields...) + if len(fields) > count || count <= 1 { + return SchemaFieldRelationship{Kind: Invalid} + } return SchemaFieldRelationship{ Kind: RequiredTogether, Fields: fields, } } +// FieldsMutuallyExclusive - the provided fields are valid if and only if at +// most one field is present. func FieldsMutuallyExclusive(fields ...SchemaField) SchemaFieldRelationship { + seen := map[string]bool{} + for _, field := range fields { + if field.Required { + return SchemaFieldRelationship{Kind: Invalid} + } + seen[field.FieldName] = true + } + if len(fields) > len(seen) || len(seen) <= 1 { + return SchemaFieldRelationship{Kind: Invalid} + } return SchemaFieldRelationship{ Kind: MutuallyExclusive, Fields: fields, } } +// FieldsAtLeastOneUsed - the provided fields are valid if and only if at least +// one field is present. func FieldsAtLeastOneUsed(fields ...SchemaField) SchemaFieldRelationship { + count := countFieldNames(fields...) + if len(fields) > count || count <= 1 { + return SchemaFieldRelationship{Kind: Invalid} + } return SchemaFieldRelationship{ Kind: AtLeastOne, Fields: fields, } } -func FieldsDependentOn(dependent []SchemaField, expected []SchemaField) SchemaFieldRelationship { +// FieldsDependentOn - the provided fields are valid if and only if every field +// in `required` are also present. +func FieldsDependentOn(fields []SchemaField, required []SchemaField) SchemaFieldRelationship { + seen0 := map[string]bool{} + for _, field := range fields { + seen0[field.FieldName] = true + } + if len(fields) > len(seen0) || + len(seen0) == 0 { + return SchemaFieldRelationship{Kind: Invalid} + } + + seen1 := map[string]bool{} + for _, field := range required { + if _, ok := seen0[field.FieldName]; ok { + return SchemaFieldRelationship{Kind: Invalid} + } + seen1[field.FieldName] = true + } + + if len(required) > len(seen1) || + len(seen1) == 0 { + return SchemaFieldRelationship{Kind: Invalid} + } + return SchemaFieldRelationship{ Kind: Dependents, - Fields: dependent, - ExpectedFields: expected, + Fields: fields, + ExpectedFields: required, } } diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/field/validation.go b/vendor/github.com/conductorone/baton-sdk/pkg/field/validation.go index 05812b5..06cd2ca 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/field/validation.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/field/validation.go @@ -5,6 +5,7 @@ import ( "reflect" "strings" + "github.com/conductorone/baton-sdk/pkg/ustrings" "github.com/spf13/viper" ) @@ -29,11 +30,8 @@ func (e *ErrConfigurationMissingFields) Push(err error) { // Validate perform validation of field requirement and constraints // relationships after the configuration is read. // We don't check the following: -// - if required fields are mutually exclusive -// - repeated fields (by name) are defined // - if sets of fields are mutually exclusive and required // together at the same time -// - if fields depedent on themselves func Validate(c Configuration, v *viper.Viper) error { present := make(map[string]int) missingFieldsError := &ErrConfigurationMissingFields{} @@ -59,7 +57,13 @@ func Validate(c Configuration, v *viper.Viper) error { } if f.Required && !isNonZero { - missingFieldsError.Push(fmt.Errorf("field %s of type %s is marked as required but it has a zero-value", f.FieldName, f.FieldType)) + missingFieldsError.Push( + fmt.Errorf( + "field %s of type %s is marked as required but it has a zero-value", + f.FieldName, + f.FieldType, + ), + ) } } @@ -83,23 +87,39 @@ func validateConstraints(fieldsPresent map[string]int, relationships []SchemaFie expected += fieldsPresent[e.FieldName] } - if present > 1 && relationship.Kind == MutuallyExclusive { - return makeMutuallyExclusiveError(fieldsPresent, relationship) - } - if present > 0 && present < len(relationship.Fields) && relationship.Kind == RequiredTogether { - return makeNeededTogetherError(fieldsPresent, relationship) - } - if present == 0 && relationship.Kind == AtLeastOne { - return makeAtLeastOneError(fieldsPresent, relationship) - } - if present > 0 && expected != len(relationship.ExpectedFields) && relationship.Kind == Dependents { - return makeDependentFieldsError(fieldsPresent, relationship) + switch relationship.Kind { + case MutuallyExclusive: + if present > 1 { + return makeMutuallyExclusiveError(fieldsPresent, relationship) + } + case RequiredTogether: + if present > 0 && present < len(relationship.Fields) { + return makeNeededTogetherError(fieldsPresent, relationship) + } + case AtLeastOne: + if present == 0 { + return makeAtLeastOneError(fieldsPresent, relationship) + } + case Dependents: + if present > 0 && expected != len(relationship.ExpectedFields) { + return makeDependentFieldsError(fieldsPresent, relationship) + } + default: + return fmt.Errorf("invalid relationship constraint") } } return nil } +func nice(elements []string) string { + return ustrings.OxfordizeList( + elements, + ustrings.WithInnerWrappers(ustrings.SingleQuotes), + ustrings.WithOuterWrappers(ustrings.Parentheses), + ) +} + func makeMutuallyExclusiveError(fields map[string]int, relation SchemaFieldRelationship) error { var found []string for _, f := range relation.Fields { @@ -108,7 +128,10 @@ func makeMutuallyExclusiveError(fields map[string]int, relation SchemaFieldRelat } } - return fmt.Errorf("fields marked as mutually exclusive were set: %s", strings.Join(found, ", ")) + return fmt.Errorf( + "fields marked as mutually exclusive were set: %s", + nice(found), + ) } func makeNeededTogetherError(fields map[string]int, relation SchemaFieldRelationship) error { @@ -119,7 +142,10 @@ func makeNeededTogetherError(fields map[string]int, relation SchemaFieldRelation } } - return fmt.Errorf("fields marked as needed together are missing: %s", strings.Join(found, ", ")) + return fmt.Errorf( + "fields marked as needed together are missing: %s", + nice(found), + ) } func makeAtLeastOneError(fields map[string]int, relation SchemaFieldRelationship) error { @@ -130,7 +156,10 @@ func makeAtLeastOneError(fields map[string]int, relation SchemaFieldRelationship } } - return fmt.Errorf("at least one field was expected, any of: %s", strings.Join(found, ", ")) + return fmt.Errorf( + "at least one field was expected, any of: %s", + nice(found), + ) } func makeDependentFieldsError(fields map[string]int, relation SchemaFieldRelationship) error { @@ -148,6 +177,9 @@ func makeDependentFieldsError(fields map[string]int, relation SchemaFieldRelatio } } - return fmt.Errorf("set fields %s are dependent on %s being set", - strings.Join(foundDependent, ", "), strings.Join(notfoundExpected, ", ")) + return fmt.Errorf( + "set fields %s are dependent on %s being set", + nice(foundDependent), + nice(notfoundExpected), + ) } diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/grpc.go b/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/grpc.go index 5f58598..0483b96 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/grpc.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/grpc.go @@ -83,7 +83,7 @@ func getRatelimitDescriptors(ctx context.Context, method string, in interface{}, return ret } -// UnaryServerInterceptor returns a new unary server interceptors that adds zap.Logger to the context. +// UnaryInterceptor returns a new unary server interceptors that adds zap.Logger to the context. func UnaryInterceptor(now func() time.Time, descriptors ...*ratelimitV1.RateLimitDescriptors_Entry) grpc.UnaryClientInterceptor { return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { // If this is a call to the rate limit service, skip it diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go b/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/http.go similarity index 77% rename from vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go rename to vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/http.go index b4da5ed..9db8c5b 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/helpers/helpers.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/ratelimit/http.go @@ -1,30 +1,14 @@ -package helpers +package ratelimit import ( "net/http" "strconv" - "strings" "time" v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2" "google.golang.org/protobuf/types/known/timestamppb" ) -func SplitFullName(name string) (string, string) { - names := strings.SplitN(name, " ", 2) - var firstName, lastName string - - switch len(names) { - case 1: - firstName = names[0] - case 2: - firstName = names[0] - lastName = names[1] - } - - return firstName, lastName -} - var limitHeaders = []string{ "X-Ratelimit-Limit", "Ratelimit-Limit", @@ -141,32 +125,3 @@ func ExtractRateLimitData(statusCode int, header *http.Header) (*v2.RateLimitDes ResetAt: timestamppb.New(resetAt), }, nil } - -func IsJSONContentType(contentType string) bool { - if !strings.HasPrefix(contentType, "application") { - return false - } - - if !strings.Contains(contentType, "json") { - return false - } - - 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 strings.HasPrefix(normalizedContentType, xmlContentType) { - return true - } - } - return false -} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/sdk/version.go b/vendor/github.com/conductorone/baton-sdk/pkg/sdk/version.go index f4f0871..e4b3762 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/sdk/version.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/sdk/version.go @@ -1,3 +1,3 @@ package sdk -const Version = "v0.2.19" +const Version = "v0.2.22" 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 a0dc21e..dc97a73 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/sync/syncer.go @@ -79,7 +79,9 @@ func (s *syncer) handleInitialActionForStep(ctx context.Context, a Action) { func (s *syncer) handleProgress(ctx context.Context, a *Action, c int) { if s.progressHandler != nil { - s.progressHandler(NewProgress(a, uint32(c))) + //nolint:gosec // No risk of overflow because `c` is a slice length. + count := uint32(c) + s.progressHandler(NewProgress(a, count)) } } @@ -1433,9 +1435,12 @@ func (s *syncer) loadStore(ctx context.Context) error { // Close closes the datastorage to ensure it is updated on disk. func (s *syncer) Close(ctx context.Context) error { - err := s.store.Close() - if err != nil { - return fmt.Errorf("error closing store: %w", err) + var err error + if s.store != nil { + err = s.store.Close() + if err != nil { + return fmt.Errorf("error closing store: %w", err) + } } if s.c1zManager != nil { diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/full_sync.go b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/full_sync.go index e5dd447..e214b76 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/full_sync.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/full_sync.go @@ -5,6 +5,7 @@ import ( "errors" "io" "os" + "path/filepath" v1 "github.com/conductorone/baton-sdk/pb/c1/connectorapi/baton/v1" "github.com/conductorone/baton-sdk/pkg/annotations" @@ -130,6 +131,11 @@ func (c *fullSyncTaskHandler) HandleTask(ctx context.Context) error { return c.helpers.FinishTask(ctx, nil, nil, err) } + err = uploadDebugLogs(ctx, c.helpers) + if err != nil { + return c.helpers.FinishTask(ctx, nil, nil, err) + } + return c.helpers.FinishTask(ctx, nil, nil, nil) } @@ -140,3 +146,39 @@ func newFullSyncTaskHandler(task *v1.Task, helpers fullSyncHelpers, skipFullSync skipFullSync: skipFullSync, } } + +func uploadDebugLogs(ctx context.Context, helper fullSyncHelpers) error { + l := ctxzap.Extract(ctx) + + debugfilelocation := filepath.Join(helper.TempDir(), "debug.log") + + _, err := os.Stat(debugfilelocation) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + l.Warn("debug log file does not exists", zap.Error(err)) + return nil + } + return err + } else { + debugfile, err := os.Open(debugfilelocation) + if err != nil { + return err + } + defer debugfile.Close() + + l.Info("uploading debug logs", zap.String("file", debugfilelocation)) + err = helper.Upload(ctx, debugfile) + + if err != nil { + return err + } + defer func() { + err := os.Remove(debugfilelocation) + if err != nil { + l.Error("failed to delete file with debug logs", zap.Error(err), zap.String("file", debugfilelocation)) + } + }() + + return nil + } +} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/manager.go b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/manager.go index 7252a07..633e10d 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/manager.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/manager.go @@ -178,6 +178,7 @@ func (c *c1ApiTaskManager) finishTask(ctx context.Context, task *v1.Task, resp p _, rpcErr := c.serviceClient.FinishTask(finishCtx, &v1.BatonServiceFinishTaskRequest{ TaskId: task.GetId(), Status: &pbstatus.Status{ + //nolint:gosec // No risk of overflow because `Code` is a small enum. Code: int32(statusErr.Code()), Message: statusErr.Message(), }, @@ -233,25 +234,18 @@ func (c *c1ApiTaskManager) Process(ctx context.Context, task *v1.Task, cc types. switch tasks.GetType(task) { case taskTypes.FullSyncType: handler = newFullSyncTaskHandler(task, tHelpers, c.skipFullSync) - case taskTypes.HelloType: handler = newHelloTaskHandler(task, tHelpers) - case taskTypes.GrantType: handler = newGrantTaskHandler(task, tHelpers) - case taskTypes.RevokeType: handler = newRevokeTaskHandler(task, tHelpers) - case taskTypes.CreateAccountType: handler = newCreateAccountTaskHandler(task, tHelpers) - case taskTypes.CreateResourceType: handler = newCreateResourceTaskHandler(task, tHelpers) - case taskTypes.DeleteResourceType: handler = newDeleteResourceTaskHandler(task, tHelpers) - case taskTypes.RotateCredentialsType: handler = newRotateCredentialsTaskHandler(task, tHelpers) case taskTypes.CreateTicketType: diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/service_client.go b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/service_client.go index 0922e68..d483cf2 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/service_client.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/tasks/c1api/service_client.go @@ -171,13 +171,17 @@ func (c *c1ServiceClient) Upload(ctx context.Context, task *v1.Task, r io.ReadSe return err } - chunkCount := uint64(math.Ceil(float64(rLen) / float64(fileChunkSize))) - for i := uint64(0); i < chunkCount; i++ { - l.Debug("sending upload chunk", zap.Uint64("chunk", i), zap.Uint64("total_chunks", chunkCount)) + chunkCount := int(math.Ceil(float64(rLen) / float64(fileChunkSize))) + for i := 0; i < chunkCount; i++ { + l.Debug( + "sending upload chunk", + zap.Int("chunk", i), + zap.Int("total_chunks", chunkCount), + ) chunkSize := fileChunkSize if i == chunkCount-1 { - chunkSize = int(rLen) - int(i)*fileChunkSize + chunkSize = int(rLen) - i*fileChunkSize } chunk := make([]byte, chunkSize) diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/parse.go b/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/parse.go new file mode 100644 index 0000000..f5e41ab --- /dev/null +++ b/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/parse.go @@ -0,0 +1,18 @@ +package resource + +import "strings" + +// SplitFullName looks for the first ` `, everything to the left is first name, +// everything to the right is last name. +func SplitFullName(name string) (string, string) { + names := strings.SplitN(name, " ", 2) + var firstName, lastName string + if len(names) > 0 { + firstName = names[0] + } + if len(names) > 1 { + lastName = names[1] + } + + return firstName, lastName +} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/user_trait.go b/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/user_trait.go index 7c10480..aefcdc7 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/user_trait.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/types/resource/user_trait.go @@ -45,6 +45,7 @@ func WithEmail(email string, primary bool) UserTraitOption { return nil } } + func WithUserLogin(login string, aliases ...string) UserTraitOption { return func(ut *v2.UserTrait) error { if login == "" { diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/contenttype.go b/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/contenttype.go new file mode 100644 index 0000000..cbad981 --- /dev/null +++ b/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/contenttype.go @@ -0,0 +1,25 @@ +package uhttp + +import "strings" + +var xmlContentTypes []string = []string{ + "text/xml", + "application/xml", +} + +func IsJSONContentType(contentType string) bool { + return strings.HasPrefix(contentType, "application") && + strings.Contains(contentType, "json") +} + +func IsXMLContentType(contentType string) bool { + // there are some janky APIs out there + normalizedContentType := strings.TrimSpace(strings.ToLower(contentType)) + + for _, xmlContentType := range xmlContentTypes { + if strings.HasPrefix(normalizedContentType, xmlContentType) { + return true + } + } + return false +} 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 2ae024b..c658210 100644 --- a/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go +++ b/vendor/github.com/conductorone/baton-sdk/pkg/uhttp/wrapper.go @@ -14,7 +14,7 @@ import ( "strconv" v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2" - "github.com/conductorone/baton-sdk/pkg/helpers" + "github.com/conductorone/baton-sdk/pkg/ratelimit" "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" "go.uber.org/zap" "google.golang.org/grpc/codes" @@ -28,6 +28,8 @@ const ( applicationFormUrlencoded = "application/x-www-form-urlencoded" applicationVndApiJSON = "application/vnd.api+json" acceptHeader = "Accept" + cacheTTLMaximum = 31536000 // 31536000 seconds = one year + cacheTTLDefault = 3600 // 3600 seconds = one hour ) type WrapperResponse struct { @@ -68,6 +70,22 @@ func NewBaseHttpClient(httpClient *http.Client) *BaseHttpClient { return client } +// getCacheTTL read the `BATON_HTTP_CACHE_TTL` environment variable and return +// the value as a number of seconds between 0 and an arbitrary maximum. Note: +// this means that passing a value of `-1` will set the TTL to zero rather than +// infinity. +func getCacheTTL() int32 { + cacheTTL, err := strconv.ParseInt(os.Getenv("BATON_HTTP_CACHE_TTL"), 10, 64) + if err != nil { + cacheTTL = cacheTTLDefault // seconds + } + + cacheTTL = min(cacheTTLMaximum, max(0, cacheTTL)) + + //nolint:gosec // No risk of overflow because we have a low maximum. + return int32(cacheTTL) +} + func NewBaseHttpClientWithContext(ctx context.Context, httpClient *http.Client) (*BaseHttpClient, error) { l := ctxzap.Extract(ctx) disableCache, err := strconv.ParseBool(os.Getenv("BATON_DISABLE_HTTP_CACHE")) @@ -78,15 +96,10 @@ func NewBaseHttpClientWithContext(ctx context.Context, httpClient *http.Client) if err != nil { cacheMaxSize = 128 // MB } - cacheTTL, err := strconv.ParseInt(os.Getenv("BATON_HTTP_CACHE_TTL"), 10, 64) - if err != nil { - cacheTTL = 3600 // seconds - } - var ( config = CacheConfig{ LogDebug: l.Level().Enabled(zap.DebugLevel), - CacheTTL: int32(cacheTTL), // seconds + CacheTTL: getCacheTTL(), // seconds CacheMaxSize: int(cacheMaxSize), // MB DisableCache: disableCache, } @@ -115,7 +128,7 @@ func NewBaseHttpClientWithContext(ctx context.Context, httpClient *http.Client) // status code 204 No Content), then pass a `nil` to `response`. func WithJSONResponse(response interface{}) DoOption { return func(resp *WrapperResponse) error { - if !helpers.IsJSONContentType(resp.Header.Get(ContentType)) { + if !IsJSONContentType(resp.Header.Get(ContentType)) { return fmt.Errorf("unexpected content type for json response: %s", resp.Header.Get(ContentType)) } if response == nil && len(resp.Body) == 0 { @@ -139,7 +152,7 @@ func WithErrorResponse(resource ErrorResponse) DoOption { return nil } - if !helpers.IsJSONContentType(resp.Header.Get(ContentType)) { + if !IsJSONContentType(resp.Header.Get(ContentType)) { return fmt.Errorf("%v", string(resp.Body)) } @@ -157,7 +170,7 @@ func WithErrorResponse(resource ErrorResponse) DoOption { func WithRatelimitData(resource *v2.RateLimitDescription) DoOption { return func(resp *WrapperResponse) error { - rl, err := helpers.ExtractRateLimitData(resp.StatusCode, &resp.Header) + rl, err := ratelimit.ExtractRateLimitData(resp.StatusCode, &resp.Header) if err != nil { return err } @@ -173,7 +186,7 @@ func WithRatelimitData(resource *v2.RateLimitDescription) DoOption { func WithXMLResponse(response interface{}) DoOption { return func(resp *WrapperResponse) error { - if !helpers.IsXMLContentType(resp.Header.Get(ContentType)) { + if !IsXMLContentType(resp.Header.Get(ContentType)) { return fmt.Errorf("unexpected content type for xml response: %s", resp.Header.Get(ContentType)) } if response == nil && len(resp.Body) == 0 { @@ -189,10 +202,10 @@ func WithXMLResponse(response interface{}) DoOption { func WithResponse(response interface{}) DoOption { return func(resp *WrapperResponse) error { - if helpers.IsJSONContentType(resp.Header.Get(ContentType)) { + if IsJSONContentType(resp.Header.Get(ContentType)) { return WithJSONResponse(response)(resp) } - if helpers.IsXMLContentType(resp.Header.Get(ContentType)) { + if IsXMLContentType(resp.Header.Get(ContentType)) { return WithXMLResponse(response)(resp) } diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/cli.go b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/cli.go new file mode 100644 index 0000000..44c8252 --- /dev/null +++ b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/cli.go @@ -0,0 +1,59 @@ +package ustrings + +import ( + "fmt" + "strings" +) + +const ( + flagSeparator = " " + flagPrefix = "--" + flagListSeparator = "," + flagDefaultValue = "true" +) + +func handleEmptyFlag(currentFlag string, output map[string]string) error { + if currentFlag != "" { + if _, ok := output[currentFlag]; ok { + return fmt.Errorf("duplicate flag has no value: %s", currentFlag) + } + output[currentFlag] = flagDefaultValue + } + return nil +} + +// ParseFlags - convert command line flags to a map of keys to strings. +func ParseFlags(expression string) (map[string]string, error) { + output := make(map[string]string) + trimmed := strings.TrimSpace(expression) + if trimmed == "" { + return output, nil + } + tokens := strings.Split(trimmed, flagSeparator) + currentFlag := "" + for _, token := range tokens { + if strings.HasPrefix(token, flagPrefix) { + err := handleEmptyFlag(currentFlag, output) + if err != nil { + return nil, err + } + currentFlag = strings.TrimPrefix(token, flagPrefix) + } else { + if currentFlag == "" { + return nil, fmt.Errorf("got a value without a flag: %s", token) + } + toAdd := TrimQuotes(token) + if found, ok := output[currentFlag]; ok { + toAdd = found + flagListSeparator + token + } + output[currentFlag] = toAdd + currentFlag = "" + } + } + // Clean up final flag if it exists. + err := handleEmptyFlag(currentFlag, output) + if err != nil { + return nil, err + } + return output, nil +} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/oxford.go b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/oxford.go new file mode 100644 index 0000000..264e566 --- /dev/null +++ b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/oxford.go @@ -0,0 +1,107 @@ +package ustrings + +import ( + "fmt" + "strings" +) + +const ( + ConjunctionDefault = "and" + SeparatorDefault = "," + WrappersDefault = Empty + EmptyListMessageDefault = "" +) + +type OxfordConfigs struct { + conjunction string + separator string + wrappersInner WrapOption + wrappersOuter WrapOption + emptyListMessage string +} + +type OxfordOptions func(config *OxfordConfigs) + +func WithConjunction(conjunction string) OxfordOptions { + return func(config *OxfordConfigs) { + config.conjunction = conjunction + } +} + +func WithSeparator(separator string) OxfordOptions { + return func(config *OxfordConfigs) { + config.separator = separator + } +} + +func WithInnerWrappers(wrappers WrapOption) OxfordOptions { + return func(config *OxfordConfigs) { + config.wrappersInner = wrappers + } +} + +func WithOuterWrappers(wrappers WrapOption) OxfordOptions { + return func(config *OxfordConfigs) { + config.wrappersOuter = wrappers + } +} + +func WithEmptyListMessage(message string) OxfordOptions { + return func(config *OxfordConfigs) { + config.emptyListMessage = message + } +} + +func OxfordizeList(elements []string, options ...OxfordOptions) string { + configs := OxfordConfigs{ + conjunction: ConjunctionDefault, + separator: SeparatorDefault, + wrappersInner: WrappersDefault, + wrappersOuter: WrappersDefault, + emptyListMessage: EmptyListMessageDefault, + } + for _, option := range options { + option(&configs) + } + + wrapped := make([]string, 0) + for _, element := range elements { + wrapped = append( + wrapped, + WrapString( + element, + configs.wrappersInner, + ), + ) + } + + last := len(elements) - 1 + var output string + switch len(elements) { + case 0: + output = configs.emptyListMessage + case 1: + output = wrapped[0] + case 2: + output = fmt.Sprintf( + "%s %s %s", + wrapped[0], + configs.conjunction, + wrapped[last], + ) + default: + wrapped[last] = fmt.Sprintf( + "%s %s", + configs.conjunction, + wrapped[last], + ) + output = strings.Join( + wrapped, + fmt.Sprintf( + "%s ", + configs.separator, + ), + ) + } + return WrapString(output, configs.wrappersOuter) +} diff --git a/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/wrap.go b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/wrap.go new file mode 100644 index 0000000..fce1bde --- /dev/null +++ b/vendor/github.com/conductorone/baton-sdk/pkg/ustrings/wrap.go @@ -0,0 +1,56 @@ +package ustrings + +import ( + "fmt" + "strings" +) + +type WrapOption int + +const ( + Empty WrapOption = iota + SingleQuotes + DoubleQuotes + TackQuotes + Parentheses + SquareBrackets + AngleBrackets +) + +const ( + quoteOptions = "'\"`" +) + +// TrimQuotes - given an input string, remove one layer of surrounding quotes if +// they exist. +func TrimQuotes(input string) string { + if len(input) <= 1 { + return input + } + for _, char := range strings.Split(quoteOptions, "") { + if strings.HasPrefix(input, char) && + strings.HasSuffix(input, char) { + return input[1 : len(input)-1] + } + } + return input +} + +func WrapString(input string, wrappers WrapOption) string { + switch wrappers { + case SingleQuotes: + return fmt.Sprintf("'%s'", input) + case DoubleQuotes: + return fmt.Sprintf(`"%s"`, input) + case TackQuotes: + return fmt.Sprintf("`%s`", input) + case Parentheses: + return fmt.Sprintf("(%s)", input) + case SquareBrackets: + return fmt.Sprintf("[%s]", input) + case AngleBrackets: + return fmt.Sprintf("<%s>", input) + default: + return input + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d6115a7..df71f14 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -144,7 +144,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.2.20 +# github.com/conductorone/baton-sdk v0.2.23 ## explicit; go 1.21 github.com/conductorone/baton-sdk/internal/connector github.com/conductorone/baton-sdk/pb/c1/c1z/v1 @@ -168,7 +168,6 @@ github.com/conductorone/baton-sdk/pkg/dotc1z/manager github.com/conductorone/baton-sdk/pkg/dotc1z/manager/local github.com/conductorone/baton-sdk/pkg/dotc1z/manager/s3 github.com/conductorone/baton-sdk/pkg/field -github.com/conductorone/baton-sdk/pkg/helpers github.com/conductorone/baton-sdk/pkg/logging github.com/conductorone/baton-sdk/pkg/metrics github.com/conductorone/baton-sdk/pkg/pagination @@ -189,6 +188,7 @@ github.com/conductorone/baton-sdk/pkg/types/ticket github.com/conductorone/baton-sdk/pkg/ugrpc github.com/conductorone/baton-sdk/pkg/uhttp github.com/conductorone/baton-sdk/pkg/us3 +github.com/conductorone/baton-sdk/pkg/ustrings github.com/conductorone/baton-sdk/pkg/utls # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit