diff --git a/sdk/component/conf.go b/sdk/component/conf.go index 98799adbd..676761ea0 100644 --- a/sdk/component/conf.go +++ b/sdk/component/conf.go @@ -3,6 +3,8 @@ package component import ( "fmt" + "github.com/go-errors/errors" + "github.com/smithy-security/smithy/sdk" "github.com/smithy-security/smithy/sdk/component/internal/uuid" ) @@ -199,41 +201,41 @@ func newRunnerConfig() (*RunnerConfig, error) { // --- BEGIN - BASIC ENV - BEGIN --- panicHandler, err := NewDefaultPanicHandler() if err != nil { - return nil, fmt.Errorf("could not construct panic handler: %w", err) + return nil, errors.Errorf("could not construct panic handler: %w", err) } componentName, err := fromEnvOrDefault(envVarKeyComponentName, "", withFallbackToDefaultOnError(true)) if err != nil { - return nil, fmt.Errorf("could not lookup environment for '%s': %w", envVarKeyComponentName, err) + return nil, errors.Errorf("could not lookup environment for '%s': %w", envVarKeyComponentName, err) } instanceIDStr, err := fromEnvOrDefault(envVarKeyInstanceID, "", withFallbackToDefaultOnError(true)) if err != nil { - return nil, fmt.Errorf("could not lookup environment for '%s': %w", envVarKeyInstanceID, err) + return nil, errors.Errorf("could not lookup environment for '%s': %w", envVarKeyInstanceID, err) } instanceID, err := uuid.Parse(instanceIDStr) if err != nil { - return nil, fmt.Errorf("could not parse instance ID '%s': %w", instanceIDStr, err) + return nil, errors.Errorf("could not parse instance ID '%s': %w", instanceIDStr, err) } // --- END - BASIC ENV - END --- // --- BEGIN - LOGGING ENV - BEGIN --- logLevel, err := fromEnvOrDefault(envVarKeyLoggingLogLevel, logLevelDebug.String(), withFallbackToDefaultOnError(true)) if err != nil { - return nil, fmt.Errorf("could not lookup environment for '%s': %w", envVarKeyLoggingLogLevel, err) + return nil, errors.Errorf("could not lookup environment for '%s': %w", envVarKeyLoggingLogLevel, err) } logger, err := newDefaultLogger(RunnerConfigLoggingLevel(logLevel)) if err != nil { - return nil, fmt.Errorf("could not initialised default logger for '%s': %w", envVarKeyLoggingLogLevel, err) + return nil, errors.Errorf("could not initialised default logger for '%s': %w", envVarKeyLoggingLogLevel, err) } // --- END - LOGGING ENV - END --- // --- BEGIN - STORER ENV - BEGIN --- st, err := fromEnvOrDefault(envVarKeyBackendStoreType, "", withFallbackToDefaultOnError(true)) if err != nil { - return nil, fmt.Errorf("could not lookup environment for '%s': %w", envVarKeyBackendStoreType, err) + return nil, errors.Errorf("could not lookup environment for '%s': %w", envVarKeyBackendStoreType, err) } conf := &RunnerConfig{ @@ -250,7 +252,7 @@ func newRunnerConfig() (*RunnerConfig, error) { if st != "" { var storageType = storeType(st) if !isAllowedStoreType(storageType) { - return nil, fmt.Errorf("invalid store type for '%s': %w", envVarKeyBackendStoreType, err) + return nil, errors.Errorf("invalid store type for '%s': %w", envVarKeyBackendStoreType, err) } conf.storerConfig.storeType = storageType @@ -261,13 +263,13 @@ func newRunnerConfig() (*RunnerConfig, error) { withFallbackToDefaultOnError(true), ) if err != nil { - return nil, fmt.Errorf("could not lookup environment for '%s': %w", envVarKeyBackendStoreDSN, err) + return nil, errors.Errorf("could not lookup environment for '%s': %w", envVarKeyBackendStoreDSN, err) } conf.storerConfig.dbDSN = dbDSN conf.storerConfig.store, err = newStorer(conf.storerConfig) if err != nil { - return nil, fmt.Errorf("could not initialise store for '%s': %w", envVarKeyBackendStoreType, err) + return nil, errors.Errorf("could not initialise store for '%s': %w", envVarKeyBackendStoreType, err) } } // --- END - STORER ENV - END --- diff --git a/sdk/component/enricher.go b/sdk/component/enricher.go index ca1b6b6e2..356e2ac91 100644 --- a/sdk/component/enricher.go +++ b/sdk/component/enricher.go @@ -2,7 +2,8 @@ package component import ( "context" - "fmt" + + "github.com/go-errors/errors" ) // RunEnricher runs an enricher after initialising the run context. @@ -28,7 +29,7 @@ func RunEnricher(ctx context.Context, enricher Enricher, opts ...RunnerOption) e findings, err := store.Read(ctx, instanceID) if err != nil { logger.With(logKeyError, err.Error()).Error("reading step failed") - return fmt.Errorf("could not read: %w", err) + return errors.Errorf("could not read: %w", err) } logger = logger.With(logKeyNumParsedFindings, len(findings)) @@ -38,7 +39,7 @@ func RunEnricher(ctx context.Context, enricher Enricher, opts ...RunnerOption) e enrichedFindings, err := enricher.Annotate(ctx, findings) if err != nil { logger.With(logKeyError, err.Error()).Error("enricher step failed") - return fmt.Errorf("could not enricher: %w", err) + return errors.Errorf("could not enricher: %w", err) } logger = logger.With(logKeyNumEnrichedFindings, len(enrichedFindings)) @@ -47,7 +48,7 @@ func RunEnricher(ctx context.Context, enricher Enricher, opts ...RunnerOption) e if err := store.Update(ctx, instanceID, enrichedFindings); err != nil { logger.With(logKeyError, err.Error()).Error("updating step failed") - return fmt.Errorf("could not update: %w", err) + return errors.Errorf("could not update: %w", err) } logger.Debug("updated step completed!") diff --git a/sdk/component/env.go b/sdk/component/env.go index d839582de..c8fad30d2 100644 --- a/sdk/component/env.go +++ b/sdk/component/env.go @@ -1,13 +1,13 @@ package component import ( - "errors" - "fmt" "net/url" "os" "strconv" "time" + "github.com/go-errors/errors" + "github.com/smithy-security/smithy/sdk/component/internal/uuid" ) @@ -70,14 +70,14 @@ func fromEnvOrDefault[T parseableEnvTypes](envVar string, defaultVal T, opts ... parseOpts := &defaultEnvParseOptions for _, opt := range opts { if err := opt(parseOpts); err != nil { - return dest, fmt.Errorf("option error: %w", err) + return dest, errors.Errorf("option error: %w", err) } } envStr := parseOpts.envLoader(envVar) if envStr == "" { if !parseOpts.defaultOnError { - return dest, fmt.Errorf("required env variable '%s' not found", envVar) + return dest, errors.Errorf("required env variable '%s' not found", envVar) } return defaultVal, nil } @@ -115,12 +115,12 @@ func fromEnvOrDefault[T parseableEnvTypes](envVar string, defaultVal T, opts ... return defaultVal, nil } - return dest, fmt.Errorf("failed to parse env %s to %T: %v", envVar, dest, err) + return dest, errors.Errorf("failed to parse env %s to %T: %v", envVar, dest, err) } dest, ok := v.(T) if !ok { - return dest, fmt.Errorf("failed to cast env %s to %T", envVar, dest) + return dest, errors.Errorf("failed to cast env %s to %T", envVar, dest) } return dest, nil diff --git a/sdk/component/filter.go b/sdk/component/filter.go index c99590960..6c2c71bea 100644 --- a/sdk/component/filter.go +++ b/sdk/component/filter.go @@ -2,7 +2,8 @@ package component import ( "context" - "fmt" + + "github.com/go-errors/errors" ) // RunFilter runs a filter after initialising the run context. @@ -28,7 +29,7 @@ func RunFilter(ctx context.Context, filter Filter, opts ...RunnerOption) error { findings, err := store.Read(ctx, instanceID) if err != nil { logger.With(logKeyError, err.Error()).Error("reading step failed") - return fmt.Errorf("could not read: %w", err) + return errors.Errorf("could not read: %w", err) } logger = logger.With(logKeyNumParsedFindings, len(findings)) @@ -39,7 +40,7 @@ func RunFilter(ctx context.Context, filter Filter, opts ...RunnerOption) error { switch { case err != nil: logger.With(logKeyError, err.Error()).Error("filter step failed") - return fmt.Errorf("could not filter: %w", err) + return errors.Errorf("could not filter: %w", err) case !ok: logger.Debug("no findings were filtered, returning") return nil @@ -51,7 +52,7 @@ func RunFilter(ctx context.Context, filter Filter, opts ...RunnerOption) error { if err := store.Update(ctx, instanceID, filteredFindings); err != nil { logger.With(logKeyError, err.Error()).Error("updating step failed") - return fmt.Errorf("could not update: %w", err) + return errors.Errorf("could not update: %w", err) } logger.Debug("updated step completed!") diff --git a/sdk/component/internal/storer/local/sqlite/export_test.go b/sdk/component/internal/storer/local/sqlite/export_test.go index a83aff129..02fcc135d 100644 --- a/sdk/component/internal/storer/local/sqlite/export_test.go +++ b/sdk/component/internal/storer/local/sqlite/export_test.go @@ -1,8 +1,6 @@ package sqlite -import ( - "fmt" -) +import "github.com/go-errors/errors" // CreateTable is used to create a table in testing settings. func (m *manager) CreateTable() error { @@ -16,11 +14,11 @@ func (m *manager) CreateTable() error { ); `) if err != nil { - return fmt.Errorf("could not prepare statement for creating table: %w", err) + return errors.Errorf("could not prepare statement for creating table: %w", err) } if _, err := stmt.Exec(); err != nil { - return fmt.Errorf("could not create table: %w", err) + return errors.Errorf("could not create table: %w", err) } return stmt.Close() diff --git a/sdk/component/internal/storer/local/sqlite/sqlite.go b/sdk/component/internal/storer/local/sqlite/sqlite.go index dc742c720..8af26a0d3 100644 --- a/sdk/component/internal/storer/local/sqlite/sqlite.go +++ b/sdk/component/internal/storer/local/sqlite/sqlite.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "encoding/json" - "errors" "fmt" "time" + "github.com/go-errors/errors" "github.com/jonboulle/clockwork" _ "github.com/mattn/go-sqlite3" "google.golang.org/protobuf/encoding/protojson" @@ -72,7 +72,7 @@ func NewManager(dsn string, opts ...managerOption) (*manager, error) { db, err := sql.Open("sqlite3", dsn) if err != nil { - return nil, fmt.Errorf("could not open sqlite db: %w", err) + return nil, errors.Errorf("could not open sqlite db: %w", err) } mgr := &manager{ @@ -82,7 +82,7 @@ func NewManager(dsn string, opts ...managerOption) (*manager, error) { for _, opt := range opts { if err := opt(mgr); err != nil { - return nil, fmt.Errorf("could not apply option: %w", err) + return nil, errors.Errorf("could not apply option: %w", err) } } @@ -104,7 +104,7 @@ func (m *manager) Read(ctx context.Context, instanceID uuid.UUID) ([]*ocsf.Vulne ; `) if err != nil { - return nil, fmt.Errorf("could not prepare select statement: %w", err) + return nil, errors.Errorf("could not prepare select statement: %w", err) } defer stmt.Close() @@ -118,21 +118,21 @@ func (m *manager) Read(ctx context.Context, instanceID uuid.UUID) ([]*ocsf.Vulne Scan(&jsonFindingsStr) if err != nil { if errors.Is(err, sql.ErrNoRows) { - return nil, fmt.Errorf("%s: %w", instanceID.String(), storer.ErrNoFindingsFound) + return nil, errors.Errorf("%s: %w", instanceID.String(), storer.ErrNoFindingsFound) } - return nil, fmt.Errorf("could not select findings: %w", err) + return nil, errors.Errorf("could not select findings: %w", err) } var jsonFindings []json.RawMessage if err := json.Unmarshal([]byte(jsonFindingsStr), &jsonFindings); err != nil { - return nil, fmt.Errorf("could not unmarshal json findings to []json.RawMessage: %w", err) + return nil, errors.Errorf("could not unmarshal json findings to []json.RawMessage: %w", err) } var findings []*ocsf.VulnerabilityFinding for _, jsonFinding := range jsonFindings { var finding ocsf.VulnerabilityFinding if err := protojson.Unmarshal(jsonFinding, &finding); err != nil { - return nil, fmt.Errorf("failed to unmarshal JSON findings to *ocsf.VulnerabilityFinding: %w", err) + return nil, errors.Errorf("failed to unmarshal JSON findings to *ocsf.VulnerabilityFinding: %w", err) } findings = append(findings, &finding) } @@ -153,7 +153,7 @@ func (m *manager) Write(ctx context.Context, instanceID uuid.UUID, findings []*o ; `) if err != nil { - return fmt.Errorf("could not prepare write statement: %w", err) + return errors.Errorf("could not prepare write statement: %w", err) } defer stmt.Close() @@ -162,7 +162,7 @@ func (m *manager) Write(ctx context.Context, instanceID uuid.UUID, findings []*o sql.Named(columnNameinstanceID.String(), instanceID.String()), sql.Named(columnNameFindings.String(), jsonFindings), ); err != nil { - return fmt.Errorf("could not insert findings: %w", err) + return errors.Errorf("could not insert findings: %w", err) } return nil @@ -186,7 +186,7 @@ func (m *manager) Update(ctx context.Context, instanceID uuid.UUID, findings []* ; `) if err != nil { - return fmt.Errorf("could not prepare update statement: %w", err) + return errors.Errorf("could not prepare update statement: %w", err) } defer stmt.Close() @@ -197,15 +197,15 @@ func (m *manager) Update(ctx context.Context, instanceID uuid.UUID, findings []* sql.Named(columnNameFindings.String(), jsonFindings), ) if err != nil { - return fmt.Errorf("could not update findings: %w", err) + return errors.Errorf("could not update findings: %w", err) } r, err := res.RowsAffected() switch { case err != nil: - return fmt.Errorf("could not get rows affected: %w", err) + return errors.Errorf("could not get rows affected: %w", err) case r <= 0: - return fmt.Errorf( + return errors.Errorf( "could not update findings for instance '%s': %w", instanceID.String(), storer.ErrNoFindingsFound, @@ -218,7 +218,7 @@ func (m *manager) Update(ctx context.Context, instanceID uuid.UUID, findings []* // Close closes the connection to the underlying database. func (m *manager) Close(ctx context.Context) error { if err := m.db.Close(); err != nil { - return fmt.Errorf("could not close sqlite db: %w", err) + return errors.Errorf("could not close sqlite db: %w", err) } return nil } @@ -228,14 +228,14 @@ func (m *manager) marshalFindings(findings []*ocsf.VulnerabilityFinding) (string for _, finding := range findings { b, err := protojson.Marshal(finding) if err != nil { - return "", fmt.Errorf("could not json marshal finding: %w", err) + return "", errors.Errorf("could not json marshal finding: %w", err) } rawFindings = append(rawFindings, b) } jsonFindings, err := json.Marshal(rawFindings) if err != nil { - return "", fmt.Errorf("could not json marshal findings: %w", err) + return "", errors.Errorf("could not json marshal findings: %w", err) } return string(jsonFindings), nil diff --git a/sdk/component/internal/storer/storer.go b/sdk/component/internal/storer/storer.go index 82bb810a3..3eedf7a3f 100644 --- a/sdk/component/internal/storer/storer.go +++ b/sdk/component/internal/storer/storer.go @@ -1,5 +1,5 @@ package storer -import "errors" +import "github.com/go-errors/errors" var ErrNoFindingsFound = errors.New("no findings found") diff --git a/sdk/component/internal/uuid/uuid.go b/sdk/component/internal/uuid/uuid.go index 10c52bcac..74eed0bca 100644 --- a/sdk/component/internal/uuid/uuid.go +++ b/sdk/component/internal/uuid/uuid.go @@ -1,8 +1,7 @@ package uuid import ( - "fmt" - + "github.com/go-errors/errors" "github.com/google/uuid" ) @@ -23,7 +22,7 @@ func Parse(s string) (UUID, error) { } u, err := uuid.Parse(s) if err != nil { - return Nil, fmt.Errorf("invalid UUID string: %s", s) + return Nil, errors.Errorf("invalid UUID string: %s", s) } return UUID(u), nil } diff --git a/sdk/component/logger.go b/sdk/component/logger.go index 008cf913b..1cde5516f 100644 --- a/sdk/component/logger.go +++ b/sdk/component/logger.go @@ -2,9 +2,10 @@ package component import ( "context" - "fmt" "log/slog" "os" + + "github.com/go-errors/errors" ) const ( @@ -104,7 +105,7 @@ func newDefaultLogger(level RunnerConfigLoggingLevel) (*defaultLogger, error) { case logLevelWarn: logLevel = slog.LevelWarn default: - return nil, fmt.Errorf("unknown logger level: %s", level) + return nil, errors.Errorf("unknown logger level: %s", level) } return &defaultLogger{ diff --git a/sdk/component/reporter.go b/sdk/component/reporter.go index 58f001eb5..1bd40f759 100644 --- a/sdk/component/reporter.go +++ b/sdk/component/reporter.go @@ -2,7 +2,8 @@ package component import ( "context" - "fmt" + + "github.com/go-errors/errors" ) // RunReporter runs a reporter after initialising the run context. @@ -30,7 +31,7 @@ func RunReporter(ctx context.Context, reporter Reporter, opts ...RunnerOption) e logger. With(logKeyError, err.Error()). Debug("could not execute read step") - return fmt.Errorf("could not read findings: %w", err) + return errors.Errorf("could not read findings: %w", err) } logger.Debug("read step completed!") @@ -40,7 +41,7 @@ func RunReporter(ctx context.Context, reporter Reporter, opts ...RunnerOption) e logger. With(logKeyError, err.Error()). Debug("could not execute report step") - return fmt.Errorf("could not report findings: %w", err) + return errors.Errorf("could not report findings: %w", err) } logger.Debug("reporter step completed!") diff --git a/sdk/component/runner.go b/sdk/component/runner.go index 39d50d9b4..538c66dfa 100644 --- a/sdk/component/runner.go +++ b/sdk/component/runner.go @@ -2,11 +2,10 @@ package component import ( "context" - "errors" - "fmt" "os/signal" "syscall" + "github.com/go-errors/errors" "golang.org/x/sync/errgroup" ) @@ -26,7 +25,7 @@ type ( func newRunner(opts ...RunnerOption) (*runner, error) { cfg, err := newRunnerConfig() if err != nil { - return nil, fmt.Errorf("could not create default runner configuration: %w", err) + return nil, errors.Errorf("could not create default runner configuration: %w", err) } r := &runner{config: cfg} @@ -38,7 +37,7 @@ func newRunner(opts ...RunnerOption) (*runner, error) { } if err := r.config.isValid(); err != nil { - return nil, fmt.Errorf("invalid configuration: %w", err) + return nil, errors.Errorf("invalid configuration: %w", err) } return r, nil @@ -61,7 +60,7 @@ func run( ) error { r, err := newRunner(opts...) if err != nil { - return fmt.Errorf("could not create runner: %w", err) + return errors.Errorf("could not create runner: %w", err) } var ( @@ -112,7 +111,7 @@ func run( logger.Error("received an unexpected panic in the component runner, handling...") if panicErr, ok := r.config.PanicHandler.HandlePanic(ctx, pe); ok { logger.Error("shutting application down...") - syncErrs <- fmt.Errorf("unexpected panic error in the component runner: %w", panicErr) + syncErrs <- errors.Errorf("unexpected panic error in the component runner: %w", panicErr) } logger.Error("panic handled in the component runner!") } @@ -122,7 +121,7 @@ func run( // TODO: potentially decompose run steps to handle cancellations separately. // Actually run the component. if err := componentRunner(ctx, conf); err != nil { - return fmt.Errorf("could not run component: %w", err) + return errors.Errorf("could not run component: %w", err) } logger.Debug("component done! Preparing to exit...") @@ -133,7 +132,7 @@ func run( // Wait for all the runner bits to be done and report an error if fatal and unexpected. if err := g.Wait(); err != nil && !isContextErr(err) { - return fmt.Errorf("unexpected run error: %w", err) + return errors.Errorf("unexpected run error: %w", err) } return nil diff --git a/sdk/component/scanner.go b/sdk/component/scanner.go index f85d34998..d6a15a0bb 100644 --- a/sdk/component/scanner.go +++ b/sdk/component/scanner.go @@ -2,7 +2,8 @@ package component import ( "context" - "fmt" + + "github.com/go-errors/errors" ) // RunScanner runs a scanner after initialising the run context. @@ -30,7 +31,7 @@ func RunScanner(ctx context.Context, scanner Scanner, opts ...RunnerOption) erro logger. With(logKeyError, err.Error()). Debug("could not execute transform step") - return fmt.Errorf("could not transform raw findings: %w", err) + return errors.Errorf("could not transform raw findings: %w", err) } logger = logger. @@ -44,7 +45,7 @@ func RunScanner(ctx context.Context, scanner Scanner, opts ...RunnerOption) erro With(logKeyError, err.Error()). With(logKeyRawFinding, rv). Error("invalid raw finding") - return fmt.Errorf("invalid raw finding: %w", err) + return errors.Errorf("invalid raw finding: %w", err) } } @@ -55,7 +56,7 @@ func RunScanner(ctx context.Context, scanner Scanner, opts ...RunnerOption) erro logger. With(logKeyError, err.Error()). Debug("could not execute store step") - return fmt.Errorf("could not store vulnerabilities: %w", err) + return errors.Errorf("could not store vulnerabilities: %w", err) } logger.Debug("store step completed!") diff --git a/sdk/component/storer.go b/sdk/component/storer.go index 8a4924c08..126920a65 100644 --- a/sdk/component/storer.go +++ b/sdk/component/storer.go @@ -1,7 +1,7 @@ package component import ( - "fmt" + "github.com/go-errors/errors" "github.com/smithy-security/smithy/sdk/component/internal/storer/local/sqlite" ) @@ -18,9 +18,9 @@ func newStorer(conf runnerConfigStorer) (Storer, error) { if conf.storeType == storeTypeLocal { localMgr, err := sqlite.NewManager(conf.dbDSN) if err != nil { - return nil, fmt.Errorf("unable to initialize local sqlite manager: %w", err) + return nil, errors.Errorf("unable to initialize local sqlite manager: %w", err) } return localMgr, nil } - return nil, fmt.Errorf("curently unsupported store type: %s", conf.storeType) + return nil, errors.Errorf("curently unsupported store type: %s", conf.storeType) } diff --git a/sdk/component/target.go b/sdk/component/target.go index f8834078d..9e3247bf0 100644 --- a/sdk/component/target.go +++ b/sdk/component/target.go @@ -2,7 +2,8 @@ package component import ( "context" - "fmt" + + "github.com/go-errors/errors" ) // RunTarget runs a target after initialising the run context. @@ -16,7 +17,7 @@ func RunTarget(ctx context.Context, target Target, opts ...RunnerOption) error { if err := target.Prepare(ctx); err != nil { logger.With(logKeyError, err.Error()).Error("preparing target failed") - return fmt.Errorf("could not prepare target: %w", err) + return errors.Errorf("could not prepare target: %w", err) } logger.Debug("component has completed successfully!") diff --git a/sdk/go.mod b/sdk/go.mod index 80e617399..e0b1b4c35 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -3,6 +3,7 @@ module github.com/smithy-security/smithy/sdk go 1.23.0 require ( + github.com/go-errors/errors v1.5.1 github.com/google/uuid v1.6.0 github.com/jonboulle/clockwork v0.4.0 github.com/mattn/go-sqlite3 v1.14.24 diff --git a/sdk/go.sum b/sdk/go.sum index 39692e0c2..3ab6cd2e9 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/sdk/vendor/github.com/go-errors/errors/.travis.yml b/sdk/vendor/github.com/go-errors/errors/.travis.yml new file mode 100644 index 000000000..1dc296026 --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - "1.8.x" + - "1.11.x" + - "1.16.x" + - "1.21.x" diff --git a/sdk/vendor/github.com/go-errors/errors/LICENSE.MIT b/sdk/vendor/github.com/go-errors/errors/LICENSE.MIT new file mode 100644 index 000000000..c9a5b2eeb --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/LICENSE.MIT @@ -0,0 +1,7 @@ +Copyright (c) 2015 Conrad Irwin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/sdk/vendor/github.com/go-errors/errors/README.md b/sdk/vendor/github.com/go-errors/errors/README.md new file mode 100644 index 000000000..558bc883e --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/README.md @@ -0,0 +1,84 @@ +go-errors/errors +================ + +[![Build Status](https://travis-ci.org/go-errors/errors.svg?branch=master)](https://travis-ci.org/go-errors/errors) + +Package errors adds stacktrace support to errors in go. + +This is particularly useful when you want to understand the state of execution +when an error was returned unexpectedly. + +It provides the type \*Error which implements the standard golang error +interface, so you can use this library interchangeably with code that is +expecting a normal error return. + +Usage +----- + +Full documentation is available on +[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple +example: + +```go +package crashy + +import "github.com/go-errors/errors" + +var Crashed = errors.Errorf("oh dear") + +func Crash() error { + return errors.New(Crashed) +} +``` + +This can be called as follows: + +```go +package main + +import ( + "crashy" + "fmt" + "github.com/go-errors/errors" +) + +func main() { + err := crashy.Crash() + if err != nil { + if errors.Is(err, crashy.Crashed) { + fmt.Println(err.(*errors.Error).ErrorStack()) + } else { + panic(err) + } + } +} +``` + +Meta-fu +------- + +This package was original written to allow reporting to +[Bugsnag](https://bugsnag.com/) from +[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar +packages by Facebook and Dropbox, it was moved to one canonical location so +everyone can benefit. + +This package is licensed under the MIT license, see LICENSE.MIT for details. + + +## Changelog +* v1.1.0 updated to use go1.13's standard-library errors.Is method instead of == in errors.Is +* v1.2.0 added `errors.As` from the standard library. +* v1.3.0 *BREAKING* updated error methods to return `error` instead of `*Error`. +> Code that needs access to the underlying `*Error` can use the new errors.AsError(e) +> ``` +> // before +> errors.New(err).ErrorStack() +> // after +>. errors.AsError(errors.Wrap(err)).ErrorStack() +> ``` +* v1.4.0 *BREAKING* v1.4.0 reverted all changes from v1.3.0 and is identical to v1.2.0 +* v1.4.1 no code change, but now without an unnecessary cover.out file. +* v1.4.2 performance improvement to ErrorStack() to avoid unnecessary work https://github.com/go-errors/errors/pull/40 +* v1.5.0 add errors.Join() and errors.Unwrap() copying the stdlib https://github.com/go-errors/errors/pull/40 +* v1.5.1 fix build on go1.13..go1.19 (broken by adding Join and Unwrap with wrong build constraints) diff --git a/sdk/vendor/github.com/go-errors/errors/error.go b/sdk/vendor/github.com/go-errors/errors/error.go new file mode 100644 index 000000000..533f1bb26 --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/error.go @@ -0,0 +1,209 @@ +// Package errors provides errors that have stack-traces. +// +// This is particularly useful when you want to understand the +// state of execution when an error was returned unexpectedly. +// +// It provides the type *Error which implements the standard +// golang error interface, so you can use this library interchangably +// with code that is expecting a normal error return. +// +// For example: +// +// package crashy +// +// import "github.com/go-errors/errors" +// +// var Crashed = errors.Errorf("oh dear") +// +// func Crash() error { +// return errors.New(Crashed) +// } +// +// This can be called as follows: +// +// package main +// +// import ( +// "crashy" +// "fmt" +// "github.com/go-errors/errors" +// ) +// +// func main() { +// err := crashy.Crash() +// if err != nil { +// if errors.Is(err, crashy.Crashed) { +// fmt.Println(err.(*errors.Error).ErrorStack()) +// } else { +// panic(err) +// } +// } +// } +// +// This package was original written to allow reporting to Bugsnag, +// but after I found similar packages by Facebook and Dropbox, it +// was moved to one canonical location so everyone can benefit. +package errors + +import ( + "bytes" + "fmt" + "reflect" + "runtime" +) + +// The maximum number of stackframes on any error. +var MaxStackDepth = 50 + +// Error is an error with an attached stacktrace. It can be used +// wherever the builtin error interface is expected. +type Error struct { + Err error + stack []uintptr + frames []StackFrame + prefix string +} + +// New makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The stacktrace will point to the line of code that +// called New. +func New(e interface{}) *Error { + var err error + + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// Wrap makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The skip parameter indicates how far up the stack +// to start the stacktrace. 0 is from the current call, 1 from its caller, etc. +func Wrap(e interface{}, skip int) *Error { + if e == nil { + return nil + } + + var err error + + switch e := e.(type) { + case *Error: + return e + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2+skip, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// WrapPrefix makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the +// error message when calling Error(). The skip parameter indicates how far +// up the stack to start the stacktrace. 0 is from the current call, +// 1 from its caller, etc. +func WrapPrefix(e interface{}, prefix string, skip int) *Error { + if e == nil { + return nil + } + + err := Wrap(e, 1+skip) + + if err.prefix != "" { + prefix = fmt.Sprintf("%s: %s", prefix, err.prefix) + } + + return &Error{ + Err: err.Err, + stack: err.stack, + prefix: prefix, + } + +} + +// Errorf creates a new error with the given message. You can use it +// as a drop-in replacement for fmt.Errorf() to provide descriptive +// errors in return values. +func Errorf(format string, a ...interface{}) *Error { + return Wrap(fmt.Errorf(format, a...), 1) +} + +// Error returns the underlying error's message. +func (err *Error) Error() string { + + msg := err.Err.Error() + if err.prefix != "" { + msg = fmt.Sprintf("%s: %s", err.prefix, msg) + } + + return msg +} + +// Stack returns the callstack formatted the same way that go does +// in runtime/debug.Stack() +func (err *Error) Stack() []byte { + buf := bytes.Buffer{} + + for _, frame := range err.StackFrames() { + buf.WriteString(frame.String()) + } + + return buf.Bytes() +} + +// Callers satisfies the bugsnag ErrorWithCallerS() interface +// so that the stack can be read out. +func (err *Error) Callers() []uintptr { + return err.stack +} + +// ErrorStack returns a string that contains both the +// error message and the callstack. +func (err *Error) ErrorStack() string { + return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack()) +} + +// StackFrames returns an array of frames containing information about the +// stack. +func (err *Error) StackFrames() []StackFrame { + if err.frames == nil { + err.frames = make([]StackFrame, len(err.stack)) + + for i, pc := range err.stack { + err.frames[i] = NewStackFrame(pc) + } + } + + return err.frames +} + +// TypeName returns the type this error. e.g. *errors.stringError. +func (err *Error) TypeName() string { + if _, ok := err.Err.(uncaughtPanic); ok { + return "panic" + } + return reflect.TypeOf(err.Err).String() +} + +// Return the wrapped error (implements api for As function). +func (err *Error) Unwrap() error { + return err.Err +} diff --git a/sdk/vendor/github.com/go-errors/errors/error_1_13.go b/sdk/vendor/github.com/go-errors/errors/error_1_13.go new file mode 100644 index 000000000..34ab3e00e --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/error_1_13.go @@ -0,0 +1,35 @@ +//go:build go1.13 +// +build go1.13 + +package errors + +import ( + baseErrors "errors" +) + +// As finds the first error in err's tree that matches target, and if one is found, sets +// target to that error value and returns true. Otherwise, it returns false. +// +// For more information see stdlib errors.As. +func As(err error, target interface{}) bool { + return baseErrors.As(err, target) +} + +// Is detects whether the error is equal to a given error. Errors +// are considered equal by this function if they are matched by errors.Is +// or if their contained errors are matched through errors.Is. +func Is(e error, original error) bool { + if baseErrors.Is(e, original) { + return true + } + + if e, ok := e.(*Error); ok { + return Is(e.Err, original) + } + + if original, ok := original.(*Error); ok { + return Is(e, original.Err) + } + + return false +} diff --git a/sdk/vendor/github.com/go-errors/errors/error_backward.go b/sdk/vendor/github.com/go-errors/errors/error_backward.go new file mode 100644 index 000000000..ff14c4bfa --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/error_backward.go @@ -0,0 +1,125 @@ +//go:build !go1.13 +// +build !go1.13 + +package errors + +import ( + "reflect" +) + +type unwrapper interface { + Unwrap() error +} + +// As assigns error or any wrapped error to the value target points +// to. If there is no value of the target type of target As returns +// false. +func As(err error, target interface{}) bool { + targetType := reflect.TypeOf(target) + + for { + errType := reflect.TypeOf(err) + + if errType == nil { + return false + } + + if reflect.PtrTo(errType) == targetType { + reflect.ValueOf(target).Elem().Set(reflect.ValueOf(err)) + return true + } + + wrapped, ok := err.(unwrapper) + if ok { + err = wrapped.Unwrap() + } else { + return false + } + } +} + +// Is detects whether the error is equal to a given error. Errors +// are considered equal by this function if they are the same object, +// or if they both contain the same error inside an errors.Error. +func Is(e error, original error) bool { + if e == original { + return true + } + + if e, ok := e.(*Error); ok { + return Is(e.Err, original) + } + + if original, ok := original.(*Error); ok { + return Is(e, original.Err) + } + + return false +} + +// Disclaimer: functions Join and Unwrap are copied from the stdlib errors +// package v1.21.0. + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +func Join(errs ...error) error { + n := 0 + for _, err := range errs { + if err != nil { + n++ + } + } + if n == 0 { + return nil + } + e := &joinError{ + errs: make([]error, 0, n), + } + for _, err := range errs { + if err != nil { + e.errs = append(e.errs, err) + } + } + return e +} + +type joinError struct { + errs []error +} + +func (e *joinError) Error() string { + var b []byte + for i, err := range e.errs { + if i > 0 { + b = append(b, '\n') + } + b = append(b, err.Error()...) + } + return string(b) +} + +func (e *joinError) Unwrap() []error { + return e.errs +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/sdk/vendor/github.com/go-errors/errors/join_unwrap_1_20.go b/sdk/vendor/github.com/go-errors/errors/join_unwrap_1_20.go new file mode 100644 index 000000000..44df35ece --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/join_unwrap_1_20.go @@ -0,0 +1,32 @@ +//go:build go1.20 +// +build go1.20 + +package errors + +import baseErrors "errors" + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +// +// For more information see stdlib errors.Join. +func Join(errs ...error) error { + return baseErrors.Join(errs...) +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +// +// For more information see stdlib errors.Unwrap. +func Unwrap(err error) error { + return baseErrors.Unwrap(err) +} diff --git a/sdk/vendor/github.com/go-errors/errors/join_unwrap_backward.go b/sdk/vendor/github.com/go-errors/errors/join_unwrap_backward.go new file mode 100644 index 000000000..50c766976 --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/join_unwrap_backward.go @@ -0,0 +1,71 @@ +//go:build !go1.20 +// +build !go1.20 + +package errors + +// Disclaimer: functions Join and Unwrap are copied from the stdlib errors +// package v1.21.0. + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +func Join(errs ...error) error { + n := 0 + for _, err := range errs { + if err != nil { + n++ + } + } + if n == 0 { + return nil + } + e := &joinError{ + errs: make([]error, 0, n), + } + for _, err := range errs { + if err != nil { + e.errs = append(e.errs, err) + } + } + return e +} + +type joinError struct { + errs []error +} + +func (e *joinError) Error() string { + var b []byte + for i, err := range e.errs { + if i > 0 { + b = append(b, '\n') + } + b = append(b, err.Error()...) + } + return string(b) +} + +func (e *joinError) Unwrap() []error { + return e.errs +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/sdk/vendor/github.com/go-errors/errors/parse_panic.go b/sdk/vendor/github.com/go-errors/errors/parse_panic.go new file mode 100644 index 000000000..d295563df --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/parse_panic.go @@ -0,0 +1,127 @@ +package errors + +import ( + "strconv" + "strings" +) + +type uncaughtPanic struct{ message string } + +func (p uncaughtPanic) Error() string { + return p.message +} + +// ParsePanic allows you to get an error object from the output of a go program +// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap. +func ParsePanic(text string) (*Error, error) { + lines := strings.Split(text, "\n") + + state := "start" + + var message string + var stack []StackFrame + + for i := 0; i < len(lines); i++ { + line := lines[i] + + if state == "start" { + if strings.HasPrefix(line, "panic: ") { + message = strings.TrimPrefix(line, "panic: ") + state = "seek" + } else { + return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line) + } + + } else if state == "seek" { + if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") { + state = "parsing" + } + + } else if state == "parsing" { + if line == "" { + state = "done" + break + } + createdBy := false + if strings.HasPrefix(line, "created by ") { + line = strings.TrimPrefix(line, "created by ") + createdBy = true + } + + i++ + + if i >= len(lines) { + return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line) + } + + frame, err := parsePanicFrame(line, lines[i], createdBy) + if err != nil { + return nil, err + } + + stack = append(stack, *frame) + if createdBy { + state = "done" + break + } + } + } + + if state == "done" || state == "parsing" { + return &Error{Err: uncaughtPanic{message}, frames: stack}, nil + } + return nil, Errorf("could not parse panic: %v", text) +} + +// The lines we're passing look like this: +// +// main.(*foo).destruct(0xc208067e98) +// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151 +func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) { + idx := strings.LastIndex(name, "(") + if idx == -1 && !createdBy { + return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name) + } + if idx != -1 { + name = name[:idx] + } + pkg := "" + + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + + if !strings.HasPrefix(line, "\t") { + return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line) + } + + idx = strings.LastIndex(line, ":") + if idx == -1 { + return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line) + } + file := line[1:idx] + + number := line[idx+1:] + if idx = strings.Index(number, " +"); idx > -1 { + number = number[:idx] + } + + lno, err := strconv.ParseInt(number, 10, 32) + if err != nil { + return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line) + } + + return &StackFrame{ + File: file, + LineNumber: int(lno), + Package: pkg, + Name: name, + }, nil +} diff --git a/sdk/vendor/github.com/go-errors/errors/stackframe.go b/sdk/vendor/github.com/go-errors/errors/stackframe.go new file mode 100644 index 000000000..ef4a8b3f3 --- /dev/null +++ b/sdk/vendor/github.com/go-errors/errors/stackframe.go @@ -0,0 +1,122 @@ +package errors + +import ( + "bufio" + "bytes" + "fmt" + "os" + "runtime" + "strings" +) + +// A StackFrame contains all necessary information about to generate a line +// in a callstack. +type StackFrame struct { + // The path to the file containing this ProgramCounter + File string + // The LineNumber in that file + LineNumber int + // The Name of the function that contains this ProgramCounter + Name string + // The Package that contains this function + Package string + // The underlying ProgramCounter + ProgramCounter uintptr +} + +// NewStackFrame popoulates a stack frame object from the program counter. +func NewStackFrame(pc uintptr) (frame StackFrame) { + + frame = StackFrame{ProgramCounter: pc} + if frame.Func() == nil { + return + } + frame.Package, frame.Name = packageAndName(frame.Func()) + + // pc -1 because the program counters we use are usually return addresses, + // and we want to show the line that corresponds to the function call + frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1) + return + +} + +// Func returns the function that contained this frame. +func (frame *StackFrame) Func() *runtime.Func { + if frame.ProgramCounter == 0 { + return nil + } + return runtime.FuncForPC(frame.ProgramCounter) +} + +// String returns the stackframe formatted in the same way as go does +// in runtime/debug.Stack() +func (frame *StackFrame) String() string { + str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter) + + source, err := frame.sourceLine() + if err != nil { + return str + } + + return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source) +} + +// SourceLine gets the line of code (from File and Line) of the original source if possible. +func (frame *StackFrame) SourceLine() (string, error) { + source, err := frame.sourceLine() + if err != nil { + return source, New(err) + } + return source, err +} + +func (frame *StackFrame) sourceLine() (string, error) { + if frame.LineNumber <= 0 { + return "???", nil + } + + file, err := os.Open(frame.File) + if err != nil { + return "", err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + currentLine := 1 + for scanner.Scan() { + if currentLine == frame.LineNumber { + return string(bytes.Trim(scanner.Bytes(), " \t")), nil + } + currentLine++ + } + if err := scanner.Err(); err != nil { + return "", err + } + + return "???", nil +} + +func packageAndName(fn *runtime.Func) (string, string) { + name := fn.Name() + pkg := "" + + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Since the package path might contains dots (e.g. code.google.com/...), + // we first remove the path prefix if there is one. + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + return pkg, name +} diff --git a/sdk/vendor/modules.txt b/sdk/vendor/modules.txt index 7a724a430..cffa2d98a 100644 --- a/sdk/vendor/modules.txt +++ b/sdk/vendor/modules.txt @@ -1,6 +1,9 @@ # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew +# github.com/go-errors/errors v1.5.1 +## explicit; go 1.14 +github.com/go-errors/errors # github.com/google/uuid v1.6.0 ## explicit github.com/google/uuid