diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f8fad06..059dda3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # GitHub code owners # See https://github.com/blog/2392-introducing-code-owners -* @wiliansilvazup @nathannascimentozup @igorreiszup @lucasbrunozup @nathanmartinszup +* @wiliansilvazup @matheusalcantarazup @lucasbrunozup @nathanmartinszup @iancardosozup diff --git a/.golangci.yml b/.golangci.yml index 3a5001d..8e1ba57 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - linters-settings: depguard: list-type: blacklist @@ -46,8 +45,6 @@ linters-settings: min-complexity: 5 goimports: local-prefixes: github.com/ZupIT/horusec-engine - golint: - min-confidence: 0 gomnd: settings: mnd: @@ -71,7 +68,7 @@ linters-settings: nolintlint: allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) allow-unused: false # report any unused nolint directives - require-explanation: false # don't require an explanation for nolint directives + require-explanation: true # don't require an explanation for nolint directives require-specific: false # don't require nolint directives to be specific about which linter is being skipped linters: @@ -94,7 +91,6 @@ linters: - gocyclo - gofmt - goimports - - golint - gomnd - goprintffuncname - gosec @@ -116,22 +112,26 @@ linters: - unused - varcheck - whitespace + - gci + - gofumpt + - testpackage + - wsl + - nlreturn + - nestif + - gocognit + - errorlint + - revive # don't enable: # - asciicheck # - scopelint # - gochecknoglobals - # - gocognit # - godot # - godox - # - goerr113 # - interfacer # - maligned - # - nestif # - prealloc - # - testpackage - # - revive - # - wsl + # - goerr113 issues: exclude-rules: @@ -140,11 +140,13 @@ exclude-rules: source: "^// " run: + skip-dirs-use-default: true skip-dirs: - vendor/ - - text/examples/ - - tmp + - tmp/ - e2e/ + - examples/ skip-files: - .*_test.go - - .*_mock.go \ No newline at end of file + - .*_mock.go + - ".*tmp.*" diff --git a/Makefile b/Makefile index 28a5ebc..bd259cc 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,18 @@ GO ?= go GOFMT ?= gofmt -GO_FILES ?= $$(find . -name '*.go' | grep -v vendor) -GOLANG_CI_LINT ?= ./bin/golangci-lint +GO_FILES ?= $$(find . -name '*.go' | grep -v vendor | grep -v /examples/) +GOLANG_CI_LINT ?= golangci-lint GO_IMPORTS ?= goimports GO_IMPORTS_LOCAL ?= github.com/ZupIT/horusec-engine HORUSEC ?= horusec +GO_FUMPT ?= gofumpt +GO_GCI ?= gci ADDLICENSE ?= addlicense GO_LIST_TO_TEST ?= $$(go list ./... | grep -v /text/examples/) -fmt: - $(GOFMT) -w $(GO_FILES) - lint: - ifeq ($(wildcard $(GOLANG_CI_LINT)), $(GOLANG_CI_LINT)) - $(GOLANG_CI_LINT) run -v --timeout=5m -c .golangci.yml ./... - else - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s latest - $(GOLANG_CI_LINT) run -v --timeout=5m -c .golangci.yml ./... - endif + $(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + $(GOLANG_CI_LINT) run -v --timeout=5m -c .golangci.yml ./... coverage: curl -fsSL https://raw.githubusercontent.com/ZupIT/horusec-devkit/main/scripts/coverage.sh | bash -s 66.3 . @@ -26,13 +21,16 @@ test: $(GO) clean -testcache $(GO) test -v $(GO_LIST_TO_TEST) -race -timeout=5m -parallel=1 -failfast -short -fix-imports: - ifeq (, $(shell which $(GO_IMPORTS))) - $(GO) get -u golang.org/x/tools/cmd/goimports - $(GO_IMPORTS) -local $(GO_IMPORTS_LOCAL) -w $(GO_FILES) - else - $(GO_IMPORTS) -local $(GO_IMPORTS_LOCAL) -w $(GO_FILES) - endif +format: install-format-dependencies + $(GOFMT) -s -l -w $(GO_FILES) + $(GO_IMPORTS) -w -local $(GO_IMPORTS_LOCAL) $(GO_FILES) + $(GO_FUMPT) -l -w $(GO_FILES) + $(GO_GCI) -w -local $(GO_IMPORTS_LOCAL) $(GO_FILES) + +install-format-dependencies: + $(GO) install golang.org/x/tools/cmd/goimports@latest + $(GO) install mvdan.cc/gofumpt@latest + $(GO) install github.com/daixiang0/gci@latest security: ifeq (, $(shell which $(HORUSEC))) @@ -42,12 +40,12 @@ security: $(HORUSEC) start -p="./" -e="true" endif -pipeline: fmt fix-imports lint test coverage security - license: - $(GO) get -u github.com/google/addlicense + $(GO) install github.com/google/addlicense@latest @$(ADDLICENSE) -check -f ./copyright.txt $(shell find -regex '.*\.\(go\|js\|ts\|yml\|yaml\|sh\|dockerfile\)') license-fix: - $(GO) get -u github.com/google/addlicense + $(GO) install github.com/google/addlicense@latest @$(ADDLICENSE) -f ./copyright.txt $(shell find -regex '.*\.\(go\|js\|ts\|yml\|yaml\|sh\|dockerfile\)') + +pipeline: format license-fix lint test coverage security diff --git a/copyright.txt b/copyright.txt index 9d8cec3..68a398e 100644 --- a/copyright.txt +++ b/copyright.txt @@ -1,4 +1,4 @@ -Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +Copyright 2022 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/engine.go b/engine.go index 63b1168..ca8e7cb 100644 --- a/engine.go +++ b/engine.go @@ -15,20 +15,22 @@ package engine import ( - "encoding/json" - "fmt" - "math" - "os" + "context" + "io/fs" + "path/filepath" + "strings" + "sync" - "github.com/ZupIT/horusec-devkit/pkg/utils/logger" - loggerEnums "github.com/ZupIT/horusec-devkit/pkg/utils/logger/enums" + "golang.org/x/sync/errgroup" + + "github.com/ZupIT/horusec-engine/pool" ) -type Unit interface { - Type() UnitType - Eval(Rule) []Finding -} +// AcceptAnyExtension can be passed as extensions argument in NewEngine to accept any extension +const AcceptAnyExtension string = "*" +// Finding represents a possible vulnerability found by the engine, it contains all information necessary to detect and +// correct the vulnerability type Finding struct { ID string Name string @@ -39,125 +41,141 @@ type Finding struct { SourceLocation Location } -func Run(document []Unit, rules []Rule) (documentFindings []Finding) { - numberOfUnits := (len(document)) * (len(rules)) - if numberOfUnits == 0 { - return []Finding{} - } - - return executeRunByNumberOfUnits(numberOfUnits, document, rules) +// Location represents the location of the vulnerability in a file +type Location struct { + Filename string + Line int + Column int } -func RunOutputInJSON(document []Unit, rules []Rule, jsonFilePath string) error { - report := Run(document, rules) - bytesToWrite, err := json.MarshalIndent(report, "", " ") - if err != nil { - return err - } - outputFile, err := createOutputFile(jsonFilePath) - defer func() { - _ = outputFile.Close() - }() - if err != nil { - return err - } - return writeInOutputFile(outputFile, bytesToWrite) +// Engine contains all the engine necessary data +type Engine struct { + poolSize int + extensions []string } -func RunMaxUnitsByAnalysis(document []Unit, rules []Rule, maxUnitPerAnalysis int) (documentFindings []Finding) { - listDocuments := breakTextUnitsIntoLimitOfUnit(document, maxUnitPerAnalysis) - for key, units := range listDocuments { - logger.LogDebugWithLevel(fmt.Sprintf("Start run analysis %v/%v", key, len(listDocuments)), loggerEnums.DebugLevel) - documentFindings = append(documentFindings, Run(units, rules)...) +// NewEngine creates a new engine instance with all necessary data. +// extensions argument represents which extension the engine should apply the rules +// poolSize represents the number of go routines to open (Default is 10) +func NewEngine(poolSize int, extensions ...string) *Engine { + return &Engine{ + poolSize: poolSize, + extensions: extensions, } - return documentFindings } -func breakTextUnitsIntoLimitOfUnit(allUnits []Unit, maxUnitsPerAnalysis int) (units [][]Unit) { - units = [][]Unit{} - startIndex := 0 - endIndex := maxUnitsPerAnalysis - for i := 0; i < getTotalTextUnitsToRunByAnalysis(allUnits, maxUnitsPerAnalysis); i++ { - units = append(units, []Unit{}) - units = toBreakUnitsAddUnitAndUpdateStartEndIndex(allUnits, units, startIndex, endIndex, i) - startIndex = endIndex + 1 - endIndex += maxUnitsPerAnalysis - } - return units -} +// Run walks through projectPath and runs the method Rule.Run in a pool of goroutines +// if an error is found when executes Rule.Run method it cancels current running go routines and return +// valid findings and the error +// nolint:funlen,gocyclo // necessary complexity, breaking this function will lead to an even more complex code +func (e *Engine) Run(ctx context.Context, projectPath string, rules ...Rule) ([]Finding, error) { + var findings []Finding -func getTotalTextUnitsToRunByAnalysis(textUnits []Unit, maxUnitsPerAnalysis int) int { - totalTextUnits := len(textUnits) - if totalTextUnits <= maxUnitsPerAnalysis { - return 1 + paths, err := e.getValidFilePaths(projectPath) + if err != nil { + return nil, err } - totalUnitsToRun := float64(totalTextUnits / maxUnitsPerAnalysis) - // nolint:staticcheck // is necessary usage pointless in math.ceil - return int(math.Ceil(totalUnitsToRun)) -} -func toBreakUnitsAddUnitAndUpdateStartEndIndex( - allUnits []Unit, unitsToAppend [][]Unit, startIndex, endIndex, i int) [][]Unit { - if len(allUnits[startIndex:]) <= endIndex { - for k := range allUnits[startIndex:] { - unitsToAppend[i] = append(unitsToAppend[i], allUnits[k]) - } - } else { - for k := range allUnits[startIndex:endIndex] { - unitsToAppend[i] = append(unitsToAppend[i], allUnits[k]) - } - } - return unitsToAppend -} + mutex := new(sync.Mutex) + wg := sync.WaitGroup{} -func writeInOutputFile(outputFile *os.File, bytesToWrite []byte) error { - bytesWritten, err := outputFile.Write(bytesToWrite) + workerPool, err := pool.NewPool(e.poolSize) if err != nil { - return err + return nil, err } - if bytesWritten != len(bytesToWrite) { - return fmt.Errorf("bytes written and length of bytes to write is not equal: %v", map[string]interface{}{ - "bytesWritten": bytesWritten, - "bytesToWrite": string(bytesToWrite), + + defer workerPool.Release() + + group, _ := errgroup.WithContext(ctx) + + wg.Add(len(paths)) + + for _, path := range paths { + pathCopy := path + + errSubmit := workerPool.Submit(func() { + group.Go(func() error { + defer wg.Done() + + newFindings, errRunRule := e.runRule(rules, pathCopy) + if errRunRule != nil { + return errRunRule + } + + mutex.Lock() + findings = append(findings, newFindings...) + mutex.Unlock() + + return errRunRule + }) }) + if errSubmit != nil { + return nil, errSubmit + } } - return nil + + wg.Wait() + err = group.Wait() + + return findings, err } -//nolint:gomnd // improving in the feature -func createOutputFile(jsonFilePath string) (*os.File, error) { - if _, err := os.Create(jsonFilePath); err != nil { - return nil, err - } - outputFile, err := os.OpenFile(jsonFilePath, os.O_CREATE|os.O_WRONLY, 0600) - if err != nil { - return nil, err +func (e *Engine) runRule(rules []Rule, pathCopy string) ([]Finding, error) { + var findings []Finding + + for _, rule := range rules { + f, err := rule.Run(pathCopy) + if err != nil { + return nil, err + } + + findings = append(findings, f...) } - return outputFile, outputFile.Truncate(0) + + return findings, nil } -func executeRunByNumberOfUnits(numberOfUnits int, document []Unit, rules []Rule) (documentFindings []Finding) { - documentFindingsChannel := make(chan []Finding, numberOfUnits) - for _, documentUnit := range document { - localDocumentUnit := documentUnit - go execRulesInDocumentUnit(rules, localDocumentUnit, documentFindingsChannel) - } - for i := 1; i <= numberOfUnits; i++ { - unitFindings := <-documentFindingsChannel - documentFindings = append(documentFindings, unitFindings...) - } - close(documentFindingsChannel) - return documentFindings +// getValidFilePaths this function will walk the project directory and will look for files that match the extensions +// informed during the initialization of the engine and return a slice with it. +// Directories, sys links and files with extensions that are not in Engine.extensions struct wil be ignored +func (e *Engine) getValidFilePaths(projectPath string) ([]string, error) { + var validPaths []string + + err := filepath.WalkDir(projectPath, func(path string, entry fs.DirEntry, err error) error { + if err != nil || e.isInvalidFilePath(path, entry) { + return err + } + + validPaths = append(validPaths, path) + + return nil + }) + + return validPaths, err } -func execRulesInDocumentUnit(rules []Rule, documentUnit Unit, findings chan<- []Finding) { - for _, rule := range rules { - localRule := rule - if localRule.IsFor(documentUnit.Type()) { - go func() { - ruleFindings := documentUnit.Eval(localRule) - findings <- ruleFindings - }() +// isInvalidFilePath contains a list of validations to check if a path needs to be analyzed. It will ignore directories, +// sysLinks, extensions that don't match the necessary ones, and .git files +func (e *Engine) isInvalidFilePath(path string, entry fs.DirEntry) bool { + return entry.IsDir() || + entry.Type() == fs.ModeSymlink || + e.isInvalidExtension(path) || + e.isFileFromGitFolder(path) +} + +// isInvalidExtension verify if the filepath contains a valid file extension. +// The valid extensions are the ones that should be analyzed, and are passed during the initialization of the engine +func (e *Engine) isInvalidExtension(path string) bool { + for _, ext := range e.extensions { + if ext == filepath.Ext(path) || ext == AcceptAnyExtension { + return false } } + + return true +} + +// isFileFromGitFolder check if a file is in a .git folder +func (e *Engine) isFileFromGitFolder(path string) bool { + return strings.Contains(path, ".git") } diff --git a/engine_test.go b/engine_test.go index db65a4a..3cca464 100644 --- a/engine_test.go +++ b/engine_test.go @@ -15,53 +15,111 @@ package engine import ( + "context" + "errors" + "path/filepath" "testing" -) - -var TestUnitType UnitType = 999 - -type TestRule struct{} - -func (rule TestRule) IsFor(unitType UnitType) bool { - return TestUnitType == unitType -} -type TestUnit struct{} + "github.com/stretchr/testify/assert" +) -func (unit TestUnit) Type() UnitType { - return TestUnitType +type ruleMock struct { + findings []Finding + err error } -func (unit TestUnit) Eval(rule Rule) []Finding { - return []Finding{ - Finding{ - ID: "1", - }, +func newRuleMock(findings []Finding, err error) *ruleMock { + return &ruleMock{ + findings: findings, + err: err, } } -func TestRunWithTextUnits(t *testing.T) { - testProgram := []Unit{TestUnit{}} - rules := []Rule{TestRule{}} - - findings := Run(testProgram, rules) - - if len(findings) < 1 || len(findings) > 1 { - t.Fatal("Should find only 1 finding") - } +// Run will return a total of findings depending on total of file paths found in informed project path and total of +// findings passed to the mock (ruleMock.findings * file paths) +func (r *ruleMock) Run(_ string) ([]Finding, error) { + return r.findings, r.err } -func TestRunWith1000Units(t *testing.T) { - rules := []Rule{TestRule{}, TestRule{}, TestRule{}} - testProgram := []Unit{} - - for i := 0; i < 1000; i++ { - testProgram = append(testProgram, TestUnit{}) +func TestEngineRun(t *testing.T) { + testcases := []struct { + name string + projectPath string + extensions []string + rules Rule + err bool + expectedFindings int + }{ + { + name: "Should run without errors and return 225 findings", + projectPath: filepath.Join("text", "examples"), + extensions: []string{AcceptAnyExtension}, + rules: newRuleMock([]Finding{{}}, nil), + expectedFindings: 225, + err: false, + }, + { + name: "Should run without errors and return 24 findings", + projectPath: filepath.Join("text", "examples"), + extensions: []string{".ex"}, + rules: newRuleMock([]Finding{{}}, nil), + expectedFindings: 24, + err: false, + }, + { + name: "Should run without errors and return 3 findings", + projectPath: filepath.Join("text", "examples"), + extensions: []string{".py"}, + rules: newRuleMock([]Finding{{}}, nil), + expectedFindings: 3, + err: false, + }, + { + name: "Should run without errors and return 4 findings", + projectPath: filepath.Join("text", "examples"), + extensions: []string{".go"}, + rules: newRuleMock([]Finding{{}}, nil), + expectedFindings: 4, + err: false, + }, + { + name: "Should run without errors and return 0 findings", + projectPath: filepath.Join("text", "examples"), + extensions: []string{".invalidExt"}, + rules: newRuleMock([]Finding{{}}, nil), + expectedFindings: 0, + err: false, + }, + { + name: "Should return error when invalid project path", + projectPath: "invalidPath", + extensions: []string{AcceptAnyExtension}, + rules: newRuleMock(nil, nil), + expectedFindings: 0, + err: true, + }, + { + name: "Should return error when failed to run rule", + extensions: []string{AcceptAnyExtension}, + expectedFindings: 0, + rules: newRuleMock(nil, errors.New("test error")), + projectPath: filepath.Join("text", "examples"), + err: true, + }, } - findings := Run(testProgram, rules) + for _, testcase := range testcases { + t.Run(testcase.name, func(t *testing.T) { + engine := NewEngine(0, testcase.extensions...) + + findings, err := engine.Run(context.Background(), testcase.projectPath, testcase.rules) + if testcase.err { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } - if len(findings) != 3000 { - t.Fatal("Should find only 3000 finding") + assert.Len(t, findings, testcase.expectedFindings) + }) } } diff --git a/go.mod b/go.mod index 7ebefd9..f5d499a 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,7 @@ go 1.14 require ( github.com/ZupIT/horusec-devkit v1.0.21 - github.com/antchfx/xmlquery v1.3.9 - github.com/antchfx/xpath v1.2.0 + github.com/panjf2000/ants/v2 v2.4.7 github.com/stretchr/testify v1.7.0 - golang.org/x/text v0.3.7 + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c ) diff --git a/go.sum b/go.sum index aafed61..a9012b5 100644 --- a/go.sum +++ b/go.sum @@ -21,7 +21,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -35,54 +34,26 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/ZupIT/horusec-devkit v1.0.17 h1:j4KtyP3bV7eAWNZtk/2ZB9TIZYaD7QyUv0zRDPuKWiA= -github.com/ZupIT/horusec-devkit v1.0.17/go.mod h1:wTsXrXTD1YrChTQEng8EvVg+zL9nMUIQkhUG85sQwuQ= -github.com/ZupIT/horusec-devkit v1.0.19 h1:eQNzst0a91YkAzSWy+1A/brBR9Lon2dMmzs0vZ3dUzQ= -github.com/ZupIT/horusec-devkit v1.0.19/go.mod h1:8rEUFNoFOGeAIG1unUfaF5qP6agHPnf9WsMtGfQR/iU= github.com/ZupIT/horusec-devkit v1.0.21 h1:vAY0/DV+EMdfSae6cu8lF0UpGrJe1uuMW3H/TDznvdE= github.com/ZupIT/horusec-devkit v1.0.21/go.mod h1:ZNpTXWcN0tG7jHokH12Zi94Y2iiV1qxslElvfSD/kDE= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antchfx/xmlquery v1.3.7 h1:0hc7OU2rFIu8MMKT5kknruaTKsoCybkUaUFMnB1LOO4= -github.com/antchfx/xmlquery v1.3.7/go.mod h1:wojC/BxjEkjJt6dPiAqUzoXO5nIMWtxHS8PD8TmN4ks= -github.com/antchfx/xmlquery v1.3.9 h1:Y+zyMdiUZ4fasTQTkDb3DflOXP7+obcYEh80SISBmnQ= -github.com/antchfx/xmlquery v1.3.9/go.mod h1:wojC/BxjEkjJt6dPiAqUzoXO5nIMWtxHS8PD8TmN4ks= -github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8= -github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -90,7 +61,6 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 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/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -100,32 +70,14 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -133,15 +85,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -149,7 +95,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -170,21 +115,13 @@ github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5H github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -209,7 +146,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -238,70 +174,28 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20210420193930-a4630ec28c79/go.mod h1:Opf9rtYVq0eTyX+aRVmRO9hE8ERAozcdrBxWG9Q6mkQ= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= -github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -313,48 +207,30 @@ github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= -github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= -github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= -github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0= github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -362,7 +238,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -377,136 +252,61 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/migueleliasweb/go-github-mock v0.0.5/go.mod h1:gTpcHVcrBxK35OOQP3aGrgQypxvEoFTvtR0VGaEs2VM= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/panjf2000/ants/v2 v2.4.7 h1:MZnw2JRyTJxFwtaMtUJcwE618wKD04POWk2gwwP4E2M= +github.com/panjf2000/ants/v2 v2.4.7/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -516,24 +316,9 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -545,31 +330,18 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= -github.com/swaggo/http-swagger v1.1.1/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8= github.com/swaggo/http-swagger v1.1.2/go.mod h1:mX5nhypDmoSt4iw2mc5aKXxRFvp1CLLcCiog2B9M+Ro= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= github.com/swaggo/swag v1.7.3/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -588,23 +360,17 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -629,7 +395,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -638,16 +403,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -673,7 +432,6 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -683,11 +441,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -705,15 +459,11 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -726,12 +476,9 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -755,15 +502,12 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -774,14 +518,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -802,7 +542,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -832,14 +571,12 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -857,7 +594,6 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -869,7 +605,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -895,17 +630,11 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -917,7 +646,6 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -938,37 +666,23 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.1.0/go.mod h1:hXQIwafeRjJvUm+OMxcFWyswJ/vevcpPLlGocwAwuqw= -gorm.io/driver/postgres v1.1.2/go.mod h1:/AGV0zvqF3mt9ZtzLzQmXWQ/5vr+1V1TyHZGZVjzmwI= gorm.io/driver/postgres v1.2.3/go.mod h1:pJV6RgYQPG47aM1f0QeOzFH9HxQc8JcmAgjRCgS0wjs= -gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.11/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.16/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -979,5 +693,3 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/location.go b/location.go deleted file mode 100644 index 26ce330..0000000 --- a/location.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package engine - -import ( - "fmt" -) - -type Location struct { - Filename string - Line int - Column int -} - -func (location Location) String() string { - return fmt.Sprintf("Name: %s Location: %d:%d", location.Filename, location.Line, location.Column) -} diff --git a/logger.go b/logger.go index e97df4a..7ec3aa3 100644 --- a/logger.go +++ b/logger.go @@ -16,6 +16,7 @@ package engine import "github.com/ZupIT/horusec-devkit/pkg/utils/logger" +// SetLogLevel used to set the engine log level func SetLogLevel(level string) { logger.SetLogLevel(level) } diff --git a/platforms/android/AndroidManifest.2.xml b/platforms/android/AndroidManifest.2.xml deleted file mode 100644 index 78aa4b7..0000000 --- a/platforms/android/AndroidManifest.2.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/platforms/android/AndroidManifest.xml b/platforms/android/AndroidManifest.xml deleted file mode 100644 index 76c967b..0000000 --- a/platforms/android/AndroidManifest.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/platforms/android/manifest.go b/platforms/android/manifest.go deleted file mode 100644 index f60da38..0000000 --- a/platforms/android/manifest.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package android - -import ( - "bytes" - - "github.com/antchfx/xmlquery" - - engine "github.com/ZupIT/horusec-engine" - "github.com/ZupIT/horusec-engine/platforms" -) - -// Permission holds data about all the declared permissions in an AndroidManifest.xml file -type Permission struct { - Name string `xml:"name,attr"` - Required string `xml:"required,attr"` -} - -// SDKInfo holds information about the target and compilation SDK of the given App -type SDKInfo struct { - MinimumSDKVersion string `xml:"minSdkVersion,attr"` - TargetSDKVersion string `xml:"targetSdkVersion,attr"` - MaximumSDKVersion string `xml:"maxSdkVersion,attr"` -} - -// IntentAction holds data about the declared Actions that can be performed in given Activity. -type IntentAction struct { - Name string `xml:"name,attr"` -} - -// IntentCategory is the Activity's category. -type IntentCategory struct { - Name string `xml:"name,attr"` -} - -// IntentFilter holds imformational data about the `intention-filter` tag for the given Activity. -type IntentFilter struct { - Categories IntentCategory `xml:"category"` - Actions []IntentAction `xml:"action"` -} - -// Activity represents an Activity entry in the manifest file -type Activity struct { - Name string `xml:"name,attr"` - IntentFilter IntentFilter `xml:"intent-filter"` -} - -// BroadcastReceiver represents a broadcast receiver entry in the manifest file -type BroadcastReceiver struct { - Name string `xml:"name,attr"` - Enabled string `xml:"enabled,attr"` - IsExported string `xml:"exported,attr"` - Permission string `xml:"permission,attr"` -} - -// Service represents a Service entry in the manifest file -type Service struct { - Name string `xml:"name,attr"` - IsExported string `xml:"exported,attr"` - Permission string `xml:"permission,attr"` -} - -// ApplicationInfo holds all the data about the application components of the app -type ApplicationInfo struct { - Name string `xml:"name,attr"` - AllowADBBackup string `xml:"allowBackup,attr"` - Activities []Activity `xml:"activity"` - BroadcastReceivers []BroadcastReceiver `xml:"receiver"` - Services []Service `xml:"service"` -} - -// Manifest is a marshaled version of all the data in the AndroidManifest.xml file -type Manifest struct { - PackageName string `xml:"package,attr"` - SDKInfo SDKInfo `xml:"uses-sdk"` - Application ApplicationInfo `xml:"application"` - Permissions []Permission `xml:"uses-permission"` -} - -type ManifestUnit struct { - Document *xmlquery.Node -} - -func (unit ManifestUnit) Type() engine.UnitType { - return engine.StructuredDataUnit -} - -// nolint // Complex method for pass refactor now TODO: Refactor this method in the future to clean code -func (unit ManifestUnit) Eval(rule engine.Rule) (unitFindings []engine.Finding) { - if structuredDataRule, ok := rule.(platforms.StructuredDataRule); ok { - switch structuredDataRule.Type { - case platforms.RegularMatch: - for _, expression := range structuredDataRule.Expressions { - exprResult := xmlquery.QuerySelectorAll(unit.Document, expression) - - if len(exprResult) < 1 { - return - } - - for _, finding := range exprResult { - unitFindings = append( - unitFindings, - platforms.PopulateFindingWithRuleMetadata( - structuredDataRule, - "AndroidManifest.xml", finding.OutputXML(true), 0, 0), - ) - } - } - case platforms.NotMatch: - for _, expression := range structuredDataRule.Expressions { - exprResult := xmlquery.QuerySelectorAll(unit.Document, expression) - - if len(exprResult) > 0 { - return - } - - unitFindings = append( - unitFindings, - platforms.PopulateFindingWithRuleMetadata(structuredDataRule, - "AndroidManifest.xml", "", 0, 0), - ) - } - default: - return unitFindings - } - } - - return unitFindings -} - -func NewManifestUnit(content []byte) (unit *ManifestUnit, err error) { - manifestRawDataReader := bytes.NewReader(content) - - formattedDocument, err := xmlquery.Parse(manifestRawDataReader) - - if err != nil { - return unit, err - } - - unit = &ManifestUnit{ - Document: formattedDocument, - } - - return unit, nil -} diff --git a/platforms/android/manifest_test.go b/platforms/android/manifest_test.go deleted file mode 100644 index f2d0ca9..0000000 --- a/platforms/android/manifest_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package android - -import ( - "os" - "testing" - - engine "github.com/ZupIT/horusec-engine" - "github.com/ZupIT/horusec-engine/platforms" -) - -func TestLoadingAManifestUnitWithValidManifestShouldWork(t *testing.T) { - androidManifest, err := os.ReadFile("AndroidManifest.xml") - - if err != nil { - t.Fatal(err) - } - - _, err = NewManifestUnit(androidManifest) - - if err != nil { - t.Fatal(err) - } -} - -func TestMatchRegularRuleWithValidManifestShouldWork(t *testing.T) { - androidManifest, err := os.ReadFile("AndroidManifest.xml") - - if err != nil { - t.Fatal(err) - } - - manifestUnit, err := NewManifestUnit(androidManifest) - - if err != nil { - t.Fatal(err) - } - - exportedRule := platforms.NewStructuredDataRule(platforms.RegularMatch, []string{`//manifest//application//activity[@android:exported='true']`}) - - findings := engine.Run([]engine.Unit{manifestUnit}, []engine.Rule{exportedRule}) - - if len(findings) <= 0 { - t.Fatal("Should have found something") - } -} - -func TestMatchNotRuleWithValidManifestShouldWork(t *testing.T) { - androidManifest, err := os.ReadFile("AndroidManifest.xml") - - if err != nil { - t.Fatal(err) - } - - manifestUnit, err := NewManifestUnit(androidManifest) - - if err != nil { - t.Fatal(err) - } - - exportedRule := platforms.NewStructuredDataRule(platforms.NotMatch, []string{`//manifest//application[@usesCleartextTraffic='true']`}) - exportedRule.Description = "Congratulations! You're not using the usesCleattextTraffic property on your applications!" - - findings := engine.Run([]engine.Unit{manifestUnit}, []engine.Rule{exportedRule}) - - if len(findings) <= 0 { - t.Fatal("Should have found something") - } -} - -func TestMatchNotRuleWithValidManifestShouldWorkFindingAnIssue(t *testing.T) { - androidManifest, err := os.ReadFile("AndroidManifest.2.xml") - - if err != nil { - t.Fatal(err) - } - - manifestUnit, err := NewManifestUnit(androidManifest) - - if err != nil { - t.Fatal(err) - } - - exportedRule := platforms.NewStructuredDataRule(platforms.NotMatch, []string{`//manifest//application[@android:usesCleartextTraffic='true']`}) - exportedRule.Description = "Congratulations! You're not using the usesCleattextTraffic property on your applications!" - - findings := engine.Run([]engine.Unit{manifestUnit}, []engine.Rule{exportedRule}) - - if len(findings) > 0 { - t.Fatal("Should not have found something") - } -} - -func TestCustomXPathExpressionsHandlingWithValidManifestShouldWork(t *testing.T) { - androidManifest, err := os.ReadFile("AndroidManifest.xml") - - if err != nil { - t.Fatal(err) - } - - manifestUnit, err := NewManifestUnit(androidManifest) - - if err != nil { - t.Fatal(err) - } - - exportedRule := platforms.NewStructuredDataRule(platforms.RegularMatch, []string{`//manifest//application//activity[@android:name[ - contains( - translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'), - 'smali') - ]]`}) - - findings := engine.Run([]engine.Unit{manifestUnit}, []engine.Rule{exportedRule}) - - if len(findings) <= 0 { - t.Fatal("Should have found something") - } -} diff --git a/platforms/finding.go b/platforms/finding.go deleted file mode 100644 index f3bdc9d..0000000 --- a/platforms/finding.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package platforms - -import ( - engine "github.com/ZupIT/horusec-engine" -) - -// PopulateFindingWithRuleMetadata converts the engine.Metadata field inside the StructuredDataRule to a engine.Finding -// struct -//nolint // change to pointer -func PopulateFindingWithRuleMetadata( - ruleData StructuredDataRule, filename, codeSample string, line, column int) engine.Finding { - return engine.Finding{ - ID: ruleData.ID, - Name: ruleData.Name, - Severity: ruleData.Severity, - Confidence: ruleData.Confidence, - Description: ruleData.Description, - CodeSample: codeSample, - SourceLocation: engine.Location{ - Filename: filename, - Line: line, - Column: column, - }, - } -} diff --git a/platforms/rule.go b/platforms/rule.go deleted file mode 100644 index 078b4c0..0000000 --- a/platforms/rule.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package platforms - -import ( - "github.com/antchfx/xpath" - - engine "github.com/ZupIT/horusec-engine" -) - -type MatchType int - -const ( - RegularMatch MatchType = iota - NotMatch -) - -type StructuredDataRule struct { - engine.Metadata - Type MatchType - Expressions []*xpath.Expr -} - -//nolint // change to pointer -func (rule StructuredDataRule) IsFor(unitType engine.UnitType) bool { - return engine.StructuredDataUnit == unitType -} - -func NewStructuredDataRule(matchType MatchType, queryStrings []string) StructuredDataRule { - var exprs []*xpath.Expr - for _, query := range queryStrings { - exprs = append(exprs, xpath.MustCompile(query)) - } - - return StructuredDataRule{ - Type: matchType, - Expressions: exprs, - } -} diff --git a/pool/pool.go b/pool/pool.go new file mode 100644 index 0000000..64b47ec --- /dev/null +++ b/pool/pool.go @@ -0,0 +1,53 @@ +// Copyright 2022 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pool + +import ( + "time" + + "github.com/panjf2000/ants/v2" +) + +const ( + // DefaultAntsPoolSize sets up the capacity of worker pool, 256 * 1024. + DefaultAntsPoolSize = 10 + + // ExpiryDuration is the interval time to clean up those expired workers. + ExpiryDuration = 10 * time.Second +) + +// Pool is the alias of ants.Pool. +type Pool = ants.Pool + +// NewPool instantiates a new goroutine pool with poolSize argument or default pool size. +func NewPool(poolSize int) (*Pool, error) { + return ants.NewPool(getDefaultOrInformedPoolSize(poolSize), ants.WithOptions(getOptions())) +} + +// getDefaultOrInformedPoolSize returns informed pool size if greater than 0 or default pool size if 0 or lower +func getDefaultOrInformedPoolSize(poolSize int) int { + if poolSize > 0 { + return poolSize + } + + return DefaultAntsPoolSize +} + +// getOptions get ants goroutine pool options +func getOptions() ants.Options { + return ants.Options{ + ExpiryDuration: ExpiryDuration, + } +} diff --git a/rule.go b/rule.go index 489ad0f..d8c56fd 100644 --- a/rule.go +++ b/rule.go @@ -14,28 +14,16 @@ package engine -// UnitType defines which type of content, and therefore, which kind of rule -// is needed in order to extract information about the program we are analyzing -type UnitType int - -const ( - ProgramTextUnit UnitType = iota - StructuredDataUnit -) - // Rule defines a generic rule for any kind of analysis the engine have to execute type Rule interface { - IsFor(UnitType) bool // Indicates which kind of program unit this rules can be ran on + Run(path string) ([]Finding, error) } // Metadata holds information for the rule to match a useful advisory type Metadata struct { ID string Name string - CodeSample string Description string - - // Metadata levels - Severity string - Confidence string + Severity string + Confidence string } diff --git a/text/file.go b/text/file.go index 0485fc8..b6020a0 100644 --- a/text/file.go +++ b/text/file.go @@ -15,96 +15,68 @@ package text import ( - "bytes" - "fmt" - "os" "path/filepath" "regexp" "sort" "strings" - "time" - - "github.com/ZupIT/horusec-devkit/pkg/utils/logger" - loggerEnums "github.com/ZupIT/horusec-devkit/pkg/utils/logger/enums" ) -var ( - newlineFinder *regexp.Regexp = regexp.MustCompile("\x0a") +// regexNewLine regex representing the new line hexadecimal, equivalent of \n. +var regexNewLine = regexp.MustCompile("\x0a") + +// File represents a file to be analyzed +type File struct { + // AbsolutePath holds the complete path to the file (e.g. /home/user/myProject/router/handler.js) + AbsolutePath string + RelativePath string // RelativePath holds the raw path relative to the root folder of the project + Content []byte // Content holds all the file content + Name string // Name holds only the single name of the file (e.g. handler.js) + newlineIndexes [][]int // newlineIndexes holds information about where is the beginning and ending of each line + newlineEndingIndexes []int // newlineEndingIndexes represents the *start* index of each '\n' rune in the file +} + +// NewTextFile create a new text file with all necessary info filled +func NewTextFile(relativeFilePath string, content []byte) (*File, error) { + file := &File{ + RelativePath: relativeFilePath, + Content: content, + Name: filepath.Base(relativeFilePath), + newlineIndexes: regexNewLine.FindAllIndex(content, -1), + } - PEMagicBytes []byte = []byte{'\x4D', '\x5A'} // MZ - ELFMagicNumber []byte = []byte{'\x7F', '\x45', '\x4C', '\x46'} // .ELF -) + if err := file.setAbsFilePath(); err != nil { + return nil, err + } -const AcceptAllExtensions string = "**" + file.setNewlineEndingIndexes() -// binarySearch function uses this search algorithm to find the index of the matching element. -func binarySearch(searchIndex int, collection []int) (foundIndex int) { - foundIndex = sort.Search( - len(collection), - func(index int) bool { return collection[index] >= searchIndex }, - ) - return + return file, nil } -// TextFile represents a file to be analyzed -// nolint:golint // name is necessary for now called TextFile for not occurs breaking changes -type TextFile struct { - DisplayName string // Holds the raw path relative to the root folder of the project - Name string // Holds only the single name of the file (e.g. handler.js) - RawString string // Holds all the file content - - // Holds the complete path to the file, could be absolute or not (e.g. /home/user/myProject/router/handler.js) - PhysicalPath string - - // Indexes for internal file reference - // newlineIndexes holds information about where is the beginning and ending of each line in the file - newlineIndexes [][]int - // newlineEndingIndexes represents the *start* index of each '\n' rune in the file - newlineEndingIndexes []int -} +// setAbsFilePath verifies if the filepath is absolute and set, otherwise it will parse and then set +func (f *File) setAbsFilePath() error { + if filepath.IsAbs(f.RelativePath) { + f.AbsolutePath = f.RelativePath -func NewTextFile(relativeFilePath string, content []byte) (TextFile, error) { - formattedPhysicalPath, err := validateRelativeFilePath(relativeFilePath) - if err != nil { - return TextFile{}, err + return nil } - return createTextFileByPath(formattedPhysicalPath, relativeFilePath, content), nil -} - -func createTextFileByPath(formattedPhysicalPath, relativeFilePath string, content []byte) TextFile { - _, formattedFilename := filepath.Split(formattedPhysicalPath) - textfile := TextFile{ - PhysicalPath: formattedPhysicalPath, - RawString: string(content), + absolutePath, err := filepath.Abs(f.RelativePath) + f.AbsolutePath = absolutePath - // Display info - Name: formattedFilename, - DisplayName: relativeFilePath, - } - textfile.newlineIndexes = newlineFinder.FindAllIndex(content, -1) - - for _, newlineIndex := range textfile.newlineIndexes { - textfile.newlineEndingIndexes = append(textfile.newlineEndingIndexes, newlineIndex[0]) - } - return textfile + return err } -func validateRelativeFilePath(relativeFilePath string) (string, error) { - if !filepath.IsAbs(relativeFilePath) { - return filepath.Abs(relativeFilePath) +// setNewlineEndingIndexes for each new line index set the ending index +func (f *File) setNewlineEndingIndexes() { + for _, newlineIndex := range f.newlineIndexes { + f.newlineEndingIndexes = append(f.newlineEndingIndexes, newlineIndex[0]) } - - return relativeFilePath, nil -} - -//nolint // change to pointer -func (textfile TextFile) Content() string { - return textfile.RawString } -// nolint // refact to have a clean code -func (textfile TextFile) FindLineAndColumn(findingIndex int) (line, column int) { +// nolint:funlen,wsl // todo complex function need to be improved +// FindLineAndColumn get line and column using the beginning index of the example code +func (f *File) FindLineAndColumn(findingIndex int) (line, column int) { // findingIndex is the index of the beginning of the text we want to // locate inside the file @@ -114,15 +86,14 @@ func (textfile TextFile) FindLineAndColumn(findingIndex int) (line, column int) // so we search for where we would put the findingIndex in the array // using a binary search algorithm, because this will give us the exact // lines that the index is between. - lineIndex := binarySearch(findingIndex, textfile.newlineEndingIndexes) + lineIndex := f.binarySearch(findingIndex, f.newlineEndingIndexes) // Now with the right index found we have to get the previous \n // from the findingIndex, so it gets the right line - if lineIndex < len(textfile.newlineEndingIndexes) { + if lineIndex < len(f.newlineEndingIndexes) { // we add +1 here because we want the line to // reflect the "human" line count, not the indexed one in the slice line = lineIndex + 1 - endOfCurrentLine := lineIndex - 1 // If there is no previous line the finding is in the beginning @@ -132,137 +103,45 @@ func (textfile TextFile) FindLineAndColumn(findingIndex int) (line, column int) } // now we access the textual index in the slice to ge the column - endOfCurrentLineInTheFile := textfile.newlineEndingIndexes[endOfCurrentLine] + endOfCurrentLineInTheFile := f.newlineEndingIndexes[endOfCurrentLine] + if lineIndex == 0 { column = findingIndex } else { column = (findingIndex - 1) - endOfCurrentLineInTheFile } } - return line, column -} - -//nolint // change to pointer -func (textfile TextFile) ExtractSample(findingIndex int) string { - lineIndex := binarySearch(findingIndex, textfile.newlineEndingIndexes) - - if lineIndex < len(textfile.newlineEndingIndexes) { - endOfPreviousLine := 0 - if lineIndex > 0 { - endOfPreviousLine = textfile.newlineEndingIndexes[lineIndex-1] + 1 - } - endOfCurrentLine := textfile.newlineEndingIndexes[lineIndex] - lineContent := textfile.RawString[endOfPreviousLine:endOfCurrentLine] - - return strings.TrimSpace(lineContent) - } - - return "" + return line, column } -func ReadAndCreateTextFile(filename string) (TextFile, error) { - textFileContent, err := ReadTextFileUnix(filename) - if err != nil { - return TextFile{}, err - } - - textFileMagicBytes := textFileContent[:4] - if bytes.Equal(textFileMagicBytes, ELFMagicNumber) { - // Ignore Linux binaries - return TextFile{}, nil - } else if bytes.Equal(textFileContent[:2], PEMagicBytes) { - // Ignore Windows binaries - return TextFile{}, nil - } - - return NewTextFile(filename, textFileContent) -} +// binarySearch function uses this search algorithm to find the index of the matching element. +func (f *File) binarySearch(searchIndex int, collection []int) (foundIndex int) { + foundIndex = sort.Search( + len(collection), + func(index int) bool { return collection[index] >= searchIndex }, + ) -// The Param extensionAccept is an filter to check if you need get textUnit for file with this extesion -// Example: []string{".java"} -// If an item of slice contains is equal the "**" it's will accept all extensions -// Example: []string{"**"} -func LoadDirIntoSingleUnit(path string, extensionsAccept []string) (TextUnit, error) { - listTextUnit, err := loadDirIntoUnit(path, 0, extensionsAccept) - if err != nil { - return TextUnit{}, err - } - if len(listTextUnit) < 1 { - return TextUnit{}, nil - } - return listTextUnit[0], nil + return } -// The Param extensionAccept is an filter to check if you need get textUnit for file with this extesion -// Example: []string{".java"} -// If an item of slice contains is equal the "**" it's will accept all extensions -// Example: []string{"**"} -func LoadDirIntoMultiUnit(path string, maxFilesPerTextUnit int, extensionsAccept []string) ([]TextUnit, error) { - return loadDirIntoUnit(path, maxFilesPerTextUnit, extensionsAccept) -} +// nolint:funlen // todo complex function, needs to be improved +// ExtractSample search for the vulnerable code using the finding indexes +func (f *File) ExtractSample(findingIndex int) string { + lineIndex := f.binarySearch(findingIndex, f.newlineEndingIndexes) -func loadDirIntoUnit(path string, maxFilesPerTextUnit int, extensionsAccept []string) ([]TextUnit, error) { - filesToRun, err := getFilesPathIntoProjectPath(path, extensionsAccept) - if err != nil { - return []TextUnit{}, err - } - return getTextUnitsFromFilesPath(filesToRun, maxFilesPerTextUnit) -} + if lineIndex < len(f.newlineEndingIndexes) { + endOfPreviousLine := 0 -func getFilesPathIntoProjectPath(projectPath string, extensionsAccept []string) (filesToRun []string, err error) { - return filesToRun, filepath.Walk(projectPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - if checkIfEnableExtension(path, extensionsAccept) { - filesToRun = append(filesToRun, path) - } + if lineIndex > 0 { + endOfPreviousLine = f.newlineEndingIndexes[lineIndex-1] + 1 } - return nil - }) -} -//nolint // refactor to constant -func getTextUnitsFromFilesPath(filesToRun []string, maxFilesPerTextUnit int) (textUnits []TextUnit, err error) { - textUnits = []TextUnit{{}} - lastIndexToAdd := 0 - for k, currentFile := range filesToRun { - time.Sleep(15 * time.Millisecond) - currentTime := time.Now() - textUnits, lastIndexToAdd, err = readFileAndExtractTextUnit( - textUnits, lastIndexToAdd, maxFilesPerTextUnit, currentFile) - logger.LogTraceWithLevel(fmt.Sprintf( - "Read file in %v Microseconds. Total files read: %v/%v ", - time.Since(currentTime).Microseconds(), k, len(filesToRun)), loggerEnums.TraceLevel, currentFile) - if err != nil { - return []TextUnit{}, err - } - } - return textUnits, nil -} + endOfCurrentLine := f.newlineEndingIndexes[lineIndex] + lineContent := f.Content[endOfPreviousLine:endOfCurrentLine] -func readFileAndExtractTextUnit( - textUnits []TextUnit, lastIndexToAdd, maxFilesPerTextUnit int, currentFile string) ([]TextUnit, int, error) { - textFile, err := ReadAndCreateTextFile(currentFile) - if err != nil { - return []TextUnit{}, lastIndexToAdd, err - } - textUnits[lastIndexToAdd].Files = append(textUnits[lastIndexToAdd].Files, textFile) - if maxFilesPerTextUnit > 0 && len(textUnits[lastIndexToAdd].Files) >= maxFilesPerTextUnit { - textUnits = append(textUnits, TextUnit{}) - return textUnits, lastIndexToAdd + 1, nil + return strings.TrimSpace(string(lineContent)) } - return textUnits, lastIndexToAdd, nil -} -func checkIfEnableExtension(path string, extensionsAccept []string) bool { - ext := filepath.Ext(path) - for _, extAccept := range extensionsAccept { - if ext == extAccept || extAccept == AcceptAllExtensions { - return true - } - } - return false + return "" } diff --git a/text/file_test.go b/text/file_test.go index 89fc1f5..c721bfd 100644 --- a/text/file_test.go +++ b/text/file_test.go @@ -15,6 +15,7 @@ package text import ( + "errors" "path/filepath" "regexp" "testing" @@ -22,366 +23,185 @@ import ( "github.com/stretchr/testify/assert" ) -func TestFindLineAndColumnWithAKotlinController(t *testing.T) { - var exampleKotlinController = `package org.jetbrains.kotlin.demo - -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController -import java.util.concurrent.atomic.AtomicLong - -@RestController -class GreetingController { - - val counter = AtomicLong() - - @GetMapping("/greeting") - fun greeting(@RequestParam(value = "name", defaultValue = "World") name: String) = - Greeting(counter.incrementAndGet(), "Hello, $name") - -} -` - - nameVariableLine := 14 - nameVariableColumn := 71 - - // So we lookup for something in the file - // in this case the 'name: String' variable - // and the method should return the correct line and column - // for where it is, in a human readable form. - nameStringExtractor := regexp.MustCompile(`name\:`) - - findingIndex := nameStringExtractor.FindStringIndex(exampleKotlinController) - - controllerTextFile, err := NewTextFile("example/controller.kt", []byte(exampleKotlinController)) - - if err != nil { - t.Error(err) - } - - line, column := controllerTextFile.FindLineAndColumn(findingIndex[0]) - - if line != nameVariableLine || column != nameVariableColumn { - t.Errorf( - "Failed to find the right line and column. Wanted: %d:%d. Found: %d:%d", - nameVariableLine, nameVariableColumn, - line, column, - ) - } -} - -func TestFindLineAndColumnWithAGoFile(t *testing.T) { - var exampleGoFile = `package version - -import ( - "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" - "github.com/spf13/cobra" -) - -type IVersion interface { - CreateCobraCmd() *cobra.Command -} - -type Version struct { -} - -func NewVersionCommand() IVersion { - return &Version{} -} - -func (v *Version) CreateCobraCmd() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Actual version installed of the horusec", - Example: "horusec version", - RunE: func(cmd *cobra.Command, args []string) error { - logger.LogPrint(cmd.Short + " is: ") - return nil - }, - } -} -` - cmdShortVariableLine := 25 - cmdShortVariableColumn := 19 - - cmdShortExtractor := regexp.MustCompile(`cmd\.Short`) - - findingIndex := cmdShortExtractor.FindStringIndex(exampleGoFile) - - goTextFile, err := NewTextFile("example/cmd/version.go", []byte(exampleGoFile)) - - if err != nil { - t.Error(err) - } - - line, column := goTextFile.FindLineAndColumn(findingIndex[0]) - - if line != cmdShortVariableLine || column != cmdShortVariableColumn { - t.Errorf( - "Failed to find the right line and column. Wanted: %d:%d. Found: %d:%d", - cmdShortVariableLine, cmdShortVariableColumn, - line, column, - ) - } -} - -func TestExtractSampleWithAGoFile(t *testing.T) { - var exampleGoFile = `package version - -import ( - "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" - "github.com/spf13/cobra" -) - -type IVersion interface { - CreateCobraCmd() *cobra.Command -} - -type Version struct { -} - -func NewVersionCommand() IVersion { - return &Version{} -} - -func (v *Version) CreateCobraCmd() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Actual version installed of the horusec", - Example: "horusec version", - RunE: func(cmd *cobra.Command, args []string) error { - logger.LogPrint(cmd.Short + " is: ") - return nil - }, - } -} -` - cmdShortExtractor := regexp.MustCompile(`cmd\.Short`) - - findingIndex := cmdShortExtractor.FindStringIndex(exampleGoFile) - - goTextFile, err := NewTextFile("example/cmd/version.go", []byte(exampleGoFile)) - - if err != nil { - t.Error(err) - } - - lineContent := goTextFile.ExtractSample(findingIndex[0]) - - if lineContent != `logger.LogPrint(cmd.Short + " is: ")` { - t.Fatalf("Failed to find the correct line content. Found: %s", lineContent) - } -} - -func TestFindLineAndColumnWithAJavascriptFile(t *testing.T) { - var exampleJsFile = `function die(msg) { alert(msg); return false; } - -function checkValue($form, selector, name, expected_value) { - var input = $form.find(selector)[0]; - if (!input) { return die('You seem to be missing a required input.'); } - if ($(input).attr('value').toLowerCase() !== expected_value.toLowerCase()) { - return die('You seem to be using the wrong value for ' + name + '.'); - } - return true; -} - -var allowed_actions = ['http://localhost:8000/csrf/gift-card', 'http://127.0.0.1:8000/csrf/gift-card']; -$(document).on('submit', 'form', function(e) { - var $form = $(this); - if (!$form.attr('action') || allowed_actions.indexOf($form.attr('action')) === -1) { - return die("Check your form action. It appears to be incorrect. You want the full URL to the giftcard form!"); - } - if (!$form.attr('method') || $form.attr('method').toUpperCase() != 'POST') { - return die("Check your form method. You should be POSTing."); - } - - // inputs should be either hidden or submit - var inputs = $form.find('input').toArray(); - for (var i in inputs) { - var type = $(inputs[i]).attr('type') || ''; - switch (type.toLowerCase()) { - case 'hidden': - case 'submit': - break; // all good - default: - return die("You appear to have inputs that are not hidden."); +const ( + sampleKotlin = ` + package org.jetbrains.kotlin.demo + + import org.springframework.web.bind.annotation.GetMapping + import org.springframework.web.bind.annotation.RequestParam + import org.springframework.web.bind.annotation.RestController + import java.util.concurrent.atomic.AtomicLong + + @RestController + class GreetingController { + + val counter = AtomicLong() + + @GetMapping("/greeting") + fun greeting(@RequestParam(value = "name", defaultValue = "World") name: String) = + Greeting(counter.incrementAndGet(), "Hello, $name") + } - } - - if (!checkValue($form, 'input[type="submit"]', 'submit', 'View Photos')) { - return false; - } - if (!checkValue($form, 'input[name="email"]', 'email', 'evil@evil.com')) { - return false; - } - if (!checkValue($form, 'input[name="amount"]', 'amount', '100')) {function checkValue($form, selector, name, expected_value) { - var input = $form.find(selector)[0]; - if (!input) { return die('You seem to be missing a required input.'); } - if ($(input).attr('value').toLowerCase() !== expected_value.toLowerCase()) { - return die('You seem to be using the wrong value for ' + name + '.'); + ` + + sampleGo = ` + package version + + import ( + "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" + "github.com/spf13/cobra" + ) + + type IVersion interface { + CreateCobraCmd() *cobra.Command } - return true; - } - - var allowed_actions = ['http://localhost:8000/csrf/gift-card', 'http://127.0.0.1:8000/csrf/gift-card']; - $(document).on('submit', 'form', function(e) { - var $form = $(this); - if (!$form.attr('action') || allowed_actions.indexOf($form.attr('action')) === -1) { - return die("Check your form action. It appears to be incorrect. You want the full URL to the giftcard form!"); + + type Version struct { } - if (!$form.attr('method') || $form.attr('method').toUpperCase() != 'POST') { - return die("Check your form method. You should be POSTing."); + + func NewVersionCommand() IVersion { + return &Version{} } - - // inputs should be either hidden or submit - var inputs = $form.find('input').toArray(); - for (var i in inputs) { - var type = $(inputs[i]).attr('type') || ''; - switch (type.toLowerCase()) { - case 'hidden': - case 'submit': - break; // all good - default: - return die("You appear to have inputs that are not hidden."); + + func (v *Version) CreateCobraCmd() *cobra.Command { + return &cobra.Command{ + Use: "version", + Short: "Actual version installed of the horusec", + Example: "horusec version", + RunE: func(cmd *cobra.Command, args []string) error { + logger.LogPrint(cmd.Short + " is: ") + return nil + }, } } - - if (!checkValue($form, 'input[type="submit"]', 'submit', 'View Photos')) { - return false; - } - if (!checkValue($form, 'input[name="email"]', 'email', 'evil@evil.com')) { - return false; - } - if (!checkValue($form, 'input[name="amount"]', 'amount', '100')) { - return false; - } - - alert("Congrats! You did it!"); - return false; - }); - - /* TODO: solution panel? */ - return false; - } - - alert("Congrats! You did it!"); - return false; -}); - -/* TODO: solution panel? */ + ` + + sampleJs = ` + const http = require('http'); + + const hostname = '127.0.0.1'; + const port = 3000; + + const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello World'); + }); + + server.listen(port, hostname, () => { + console.log('Server running at https://${hostname}:${port}/''); + }); ` +) - regexCompiler := regexp.MustCompile(`(?m)(?i)(^| |;)(alert|confirm|prompt)\(.*`) - findingIndex := regexCompiler.FindStringIndex(exampleJsFile) - - jsTextFile, err := NewTextFile("example/cmd/version.js", []byte(exampleJsFile)) - - if err != nil { - t.Error(err) +func getFindingIndex(sample, expression string) (int, error) { + indexes := regexp.MustCompile(expression).FindIndex([]byte(sample)) + if len(indexes) > 0 { + return indexes[0], nil + } + + return 0, errors.New("failed to get finding indexes") +} + +func TestFindLineAndColumn(t *testing.T) { + testCases := []struct { + name string + regexExpression string + codeSample string + expectedLine int + expectedColumn int + }{ + { + name: "Should success find line and column for kotlin", + regexExpression: `name\:`, + codeSample: sampleKotlin, + expectedLine: 15, + expectedColumn: 70, + }, + { + name: "Should success find line and column for go", + regexExpression: `cmd\.Short`, + codeSample: sampleGo, + expectedLine: 26, + expectedColumn: 21, + }, + { + name: "Should success find line and column for js", + regexExpression: `server\.listen`, + codeSample: sampleJs, + expectedLine: 13, + expectedColumn: 2, + }, } - line, column := jsTextFile.FindLineAndColumn(findingIndex[0]) - if line != 1 || column != 19 { - t.Errorf( - "Failed to find the right line and column. Wanted: %d:%d. Found: %d:%d", - 1, 19, - line, column, - ) - } -} + for index, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + findingIndex, err := getFindingIndex(testCase.codeSample, testCase.regexExpression) + assert.NoError(t, err) -func TestNameFormattingAndDisplaying(t *testing.T) { - expectedName := "version.go" + file, err := NewTextFile("test", []byte(testCase.codeSample)) + assert.NoError(t, err) - goTextFile, err := NewTextFile("example/cmd/version.go", []byte{}) - - if err != nil { - t.Error(err) - } - - if goTextFile.Name != expectedName { - t.Errorf( - "Failed to format the Name of the TextFile for Golang. Wanted: %s, Got: %s", - expectedName, - goTextFile.Name, - ) + line, column := file.FindLineAndColumn(findingIndex) + assert.Equalf(t, testCase.expectedLine, line, "failed to find correct line, test case: %d", index) + assert.Equalf(t, testCase.expectedColumn, column, "failed to find correct column, test case: %d", index) + }) } } -func TestReadAndCreateTextFileWithELFFile(t *testing.T) { - textFile, err := ReadAndCreateTextFile(filepath.Join("examples", "elf", "example1", "test.elf")) - - if err != nil { - t.Fatal(err) - } - - t.Log(textFile.DisplayName) - - if textFile.DisplayName != "" || textFile.Name != "" || textFile.RawString != "" { - t.Fatal("Should not return anything") +func TestExtractSample(t *testing.T) { + testCases := []struct { + name string + regexExpression string + codeSample string + expectedCodeSample string + }{ + { + name: "Should success find code sample for kotlin", + regexExpression: `name\:`, + codeSample: sampleKotlin, + expectedCodeSample: "fun greeting(@RequestParam(value = \"name\", defaultValue = \"World\") name: String) =", + }, + { + name: "Should success find code sample for go", + regexExpression: `cmd\.Short`, + codeSample: sampleGo, + expectedCodeSample: "logger.LogPrint(cmd.Short + \" is: \")", + }, + { + name: "Should success find code sample for js", + regexExpression: `server\.listen`, + codeSample: sampleJs, + expectedCodeSample: "server.listen(port, hostname, () => {", + }, } -} -func TestReadAndCreateTextFileWithPEFile(t *testing.T) { - textFile, err := ReadAndCreateTextFile(filepath.Join("examples", "pe", "example1", "test.pe")) + for index, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + findingIndex, err := getFindingIndex(testCase.codeSample, testCase.regexExpression) + assert.NoError(t, err) - if err != nil { - t.Fatal(err) - } - - t.Log(textFile.DisplayName) + file, err := NewTextFile("test", []byte(testCase.codeSample)) + assert.NoError(t, err) - if textFile.DisplayName != "" || textFile.Name != "" || textFile.RawString != "" { - t.Fatal("Should not return anything") + sample := file.ExtractSample(findingIndex) + assert.Equalf(t, testCase.expectedCodeSample, sample, "failed to find code sample, test case: %d", index) + }) } } -func TestReadAndCreateTextFileWithMachOFile(t *testing.T) { - t.Log("TODO: Skip Mach-O files") - t.Skip() +func TestNewTextFile(t *testing.T) { + t.Run("Should success create a new text file", func(t *testing.T) { + relativeFilePath := filepath.Join("examples", "go", "example1", "api", "server.go") - textFile, err := ReadAndCreateTextFile(filepath.Join("examples", "pe", "example1", "test.macho")) - - if err != nil { - t.Fatal(err) - } - - t.Log(textFile.DisplayName) - - if textFile.DisplayName != "" || textFile.Name != "" || textFile.RawString != "" { - t.Fatal("Should not return anything") - } -} - -func TestTextFiles_GetAllFilesUnits(t *testing.T) { - t.Run("Should return unit with nine files when get any files", func(t *testing.T) { - path, err := filepath.Abs("examples") - assert.NoError(t, err) - textUnit, err := LoadDirIntoSingleUnit(path, []string{"**"}) - assert.NoError(t, err) - assert.Equal(t, 237, len(textUnit.Files)) - }) - t.Run("Should return multi unit with 4 textFiles and max of 3 files per textFile when get any files", func(t *testing.T) { - path, err := filepath.Abs("examples") + file, err := NewTextFile(relativeFilePath, []byte(sampleGo)) assert.NoError(t, err) - textUnit, err := LoadDirIntoMultiUnit(path, 3, []string{"**"}) - assert.NoError(t, err) - assert.Equal(t, 80, len(textUnit)) - for _, item := range textUnit { - assert.LessOrEqual(t, len(item.Files), 3) - } - }) - t.Run("Should return unit with tree files when get go files", func(t *testing.T) { - path, err := filepath.Abs("examples") - assert.NoError(t, err) - textUnit, err := LoadDirIntoSingleUnit(path, []string{".perf"}) - assert.NoError(t, err) - assert.Equal(t, 5, len(textUnit.Files)) - }) - t.Run("Should return error when path not exists", func(t *testing.T) { - path := "./not-exist-path.go" - units, err := LoadDirIntoSingleUnit(path, []string{".go"}) - assert.Error(t, err) - assert.Empty(t, units.Files) + + assert.Truef(t, filepath.IsAbs(file.AbsolutePath), "path it's not absolute") + assert.Equalf(t, relativeFilePath, file.RelativePath, "failed to match relative path") + assert.Equalf(t, sampleGo, string(file.Content), "failed to match content") + assert.Equalf(t, filepath.Base(relativeFilePath), file.Name, "failed to match file name") + assert.Lenf(t, file.newlineIndexes, 30, "sample go contains 30 new line indexes") + assert.Lenf(t, file.newlineEndingIndexes, 30, "sample go contains 30 ending indexes") }) } diff --git a/text/reader.go b/text/reader.go deleted file mode 100644 index 19f097b..0000000 --- a/text/reader.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package text - -import ( - "io" - "os" - - "golang.org/x/text/encoding/unicode" - "golang.org/x/text/transform" -) - -// newUnicodeReader creates a transformer to read UTF16 LE or BE MS-Windows files -// essentially transforming everything to UTF-8, if and only if the file have the BOM -func newUnicodeReaderUnix(defaultReader io.Reader) io.Reader { - decoder := unicode.UTF8.NewDecoder() - return transform.NewReader(defaultReader, unicode.BOMOverride(decoder)) -} - -// ReadTextFile reads the content of a file, converting when possible -// the encoding to UTF-8. -func ReadTextFileUnix(filename string) ([]byte, error) { - fileDescriptor, err := os.Open(filename) - if err != nil { - return []byte{}, err - } - defer func() { - _ = fileDescriptor.Close() - }() - - reader := newUnicodeReaderUnix(fileDescriptor) - utf8FormattedString, err := io.ReadAll(reader) - if err != nil { - return []byte{}, err - } - - return utf8FormattedString, nil -} diff --git a/text/reader_test.go b/text/reader_test.go deleted file mode 100644 index 201d615..0000000 --- a/text/reader_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !windows -// +build !windows - -package text - -import ( - "os" - "path/filepath" - "testing" -) - -func TestReadTextFileControlWithUTF8(t *testing.T) { - expectedBytes, err := os.ReadFile(filepath.Join("examples", "csharp", "example2", "PetsController.utf8.cs")) - if err != nil { - t.Fatal(err) - } - - bytesReadFromUTF8File, err := ReadTextFileUnix(filepath.Join("examples", "csharp", "example2", "PetsController.utf8.cs")) - if err != nil { - t.Fatal(err) - } - - if string(expectedBytes) != string(bytesReadFromUTF8File) { - t.Errorf("Failed to read UTF16 LE: expected: %#v got %#v\n", string(expectedBytes)[:4], bytesReadFromUTF8File[:4]) - } -} - -func TestReadTextFileControlWithUTF8WithBOM(t *testing.T) { - expectedBytes, err := os.ReadFile(filepath.Join("examples", "csharp", "example2", "PetsController.utf8.cs")) - if err != nil { - t.Fatal(err) - } - - bytesReadFromUTF8File, err := ReadTextFileUnix(filepath.Join("examples", "csharp", "example2", "PetsController.utf8bom.cs")) - if err != nil { - t.Fatal(err) - } - - if string(expectedBytes) != string(bytesReadFromUTF8File) { - t.Errorf("Failed to read UTF16 LE: expected: %#v got %#v\n", string(expectedBytes)[:4], bytesReadFromUTF8File[:4]) - } -} - -func TestReadTextFileWithUTF16LEWithBOM(t *testing.T) { - expectedBytes, err := os.ReadFile(filepath.Join("examples", "csharp", "example2", "PetsController.utf8.cs")) - if err != nil { - t.Fatal(err) - } - - bytesReadFromUTF16File, err := ReadTextFileUnix(filepath.Join("examples", "csharp", "example2", "PetsController.utf16lebom.cs")) - if err != nil { - t.Fatal(err) - } - - if string(expectedBytes) != string(bytesReadFromUTF16File) { - t.Errorf("Failed to read UTF16 LE: expected: %#v got %#v\n", string(expectedBytes)[:4], bytesReadFromUTF16File[:4]) - } -} - -func TestReadTextFileWithUTF16BEWithBOM(t *testing.T) { - expectedBytes, err := os.ReadFile(filepath.Join("examples", "csharp", "example2", "PetsController.utf8.cs")) - if err != nil { - t.Fatal(err) - } - - bytesReadFromUTF16File, err := ReadTextFileUnix(filepath.Join("examples", "csharp", "example2", "PetsController.utf16bebom.cs")) - if err != nil { - t.Fatal(err) - } - - if string(expectedBytes) != string(bytesReadFromUTF16File) { - t.Errorf("Failed to read UTF16 LE: expected: %#v got %#v\n", string(expectedBytes)[:4], bytesReadFromUTF16File[:4]) - } -} diff --git a/text/reader_win.go b/text/reader_win.go deleted file mode 100644 index 0a4b2e6..0000000 --- a/text/reader_win.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package text - -import ( - "bytes" - "errors" - "io" - "os" - - "golang.org/x/text/encoding/unicode" - "golang.org/x/text/transform" -) - -var ( - bigEndianUTF16BOM = []byte{'\xFE', '\xFF'} - littleEndianUTF16BOM = []byte{'\xFF', '\xFE'} - - ErrWinFileWithoutBOM error = errors.New( - "this file does not contains a BOM, please save it again with a BOM to avoid noise in test results") -) - -// newUnicodeReader creates a transformer to read UTF16 LE or BE MS-Windows files -// essentially transforming everything to UTF-8, if and only if the file have the BOM -func newUnicodeReaderWin(defaultReader io.Reader) io.Reader { - decoder := unicode.UTF8.NewDecoder() - return transform.NewReader(defaultReader, unicode.BOMOverride(decoder)) -} - -// ReadTextFile reads the content of a file, converting when possible -// the encoding to UTF-8. -// nolint // method is necessary more 10 lines -func ReadTextFileWin(filename string) ([]byte, error) { - fileDescriptor, err := os.Open(filename) - - if err != nil { - return []byte{}, err - } - - defer fileDescriptor.Close() - - bomCheckBuffer := make([]byte, 4) - - bytesRead, err := fileDescriptor.Read(bomCheckBuffer) - - if err != nil || bytesRead != 4 { - return []byte{}, err - } - - if !(bytes.Equal(bigEndianUTF16BOM, bomCheckBuffer)) && - !(bytes.Equal(littleEndianUTF16BOM, bomCheckBuffer)) { - return []byte{}, ErrWinFileWithoutBOM - } - - reader := newUnicodeReaderWin(fileDescriptor) - - utf8FormattedString, err := io.ReadAll(reader) - - if err != nil { - return []byte{}, err - } - - return utf8FormattedString, nil -} diff --git a/text/reader_win_test.go b/text/reader_win_test.go deleted file mode 100644 index bc6d344..0000000 --- a/text/reader_win_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build windows - -package text - -import ( - "path/filepath" - "testing" -) - -func TestWinReadTextFileShouldFailWithUTF16LEWithoutBOM(t *testing.T) { - _, err := ReadTextFileWin(filepath.Join("examples", "csharp", "example2", "PetsController.utf16le.cs")) - - if err == nil { - t.Fatalf("Should have returned error for files encoded with UTF16 LE without BOM") - } -} - -func TestWinReadTextFileShouldFailWithUTF16BEWithoutBOM(t *testing.T) { - _, err := ReadTextFileWin(filepath.Join("examples", "csharp", "example2", "PetsController.utf16be.cs")) - - if err == nil { - t.Fatalf("Should have returned error for files encoded with UTF16 BE without BOM") - } -} diff --git a/text/rule.go b/text/rule.go index 57576c0..8a69c6a 100644 --- a/text/rule.go +++ b/text/rule.go @@ -15,28 +15,223 @@ package text import ( + "bytes" + "fmt" + "io" + "os" "regexp" engine "github.com/ZupIT/horusec-engine" ) +// MatchType represents the possibles match types of the engine type MatchType int const ( - Regular MatchType = iota + // OrMatch for each regex that match will report a vulnerability + OrMatch MatchType = iota + + // Regular do the exact same thing as OrMatch, will be depreciated in the future to simplify engine use + Regular + + // NotMatch will report any file that don't match the regex expressions NotMatch - OrMatch + + // AndMatch need that all regex expressions match to report the vulnerability, it will get the first regex expression + // the use as base to the reported vulnerability AndMatch ) -// nolint // name is necessary for now called TextRule for not occurs breaking changes -type TextRule struct { +// peMagicBytes hexadecimal used to find windows binaries +// elfMagicNumber hexadecimal used to find linux binaries +var ( + peMagicBytes = []byte{'\x4D', '\x5A'} // MZ + elfMagicNumber = []byte{'\x7F', '\x45', '\x4C', '\x46'} // .ELF +) + +// Rule represents the vulnerability that should be searched in the file. It contains some predefined information about +// the vulnerability like the id, name, description, severity, confidence, match type that should be applied and the +// regular expressions used to match the vulnerable code +type Rule struct { engine.Metadata Type MatchType Expressions []*regexp.Regexp } -//nolint // change to pointer -func (rule TextRule) IsFor(unitType engine.UnitType) bool { - return engine.ProgramTextUnit == unitType +// Run start a static code analysis using regular expressions, it will read the file content as bytes and create a text +// file with it. The text file contains all information needed to find the vulnerable code when the regular expressions +// match. There's also a validation to ignore binary files +func (r *Rule) Run(path string) ([]engine.Finding, error) { + content, err := r.getFileContent(path) + if err != nil { + return nil, err + } + + if r.isBinary(content) { + return nil, nil + } + + textFile, err := NewTextFile(path, content) + if err != nil { + return nil, err + } + + return r.runByRuleType(textFile) +} + +// getFileContent opens the file using the file path, reads and returns its contents as bytes. After all done closes +// the file +func (r *Rule) getFileContent(path string) ([]byte, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + + defer file.Close() + + content, err := io.ReadAll(file) + if err != nil { + return nil, err + } + + return content, nil +} + +// runByRuleType determines which match type should be applied and ran according the rule +func (r *Rule) runByRuleType(file *File) ([]engine.Finding, error) { + switch r.Type { + // TODO: regular type do the exact same thing as OrMatch, will be depreciated in the future to simplify engine use + case OrMatch, Regular: + return r.runOrMatch(file) + case NotMatch: + return r.runNotMatch(file) + case AndMatch: + return r.runAndMatch(file) + } + + return nil, fmt.Errorf("invalid rule type") +} + +// runNotMatch for each regex expression will search for matches in the file and return they index and create the +// findings with them. Different of the other types, this type will report files that didn't have any match with each +// one of the regex expressions. +// TODO: since this match type search for files that didn't match the rules, we can't get a sample code, +// line and column, witch lead to a really vague report. Need to be revisited and improved in the future. +func (r *Rule) runNotMatch(file *File) ([]engine.Finding, error) { + var findings []engine.Finding + + for _, expression := range r.Expressions { + if expression.FindAllIndex(file.Content, -1) == nil { + findings = append(findings, r.newFinding(file.RelativePath, "", 0, 0)) + } + } + + return findings, nil +} + +// runAndMatch for each regex expression will search for matches in the file and return they index and create the +// findings with them. If any of the regex expressions don't match, it should return nil, all regex expressions should +// match to be a valid vulnerability. In case of all have matched the first finding will be returned to be used to +// generate the report +//nolint:funlen // necessary length, it's not a complex func, maybe can be improved in the future +func (r *Rule) runAndMatch(file *File) ([]engine.Finding, error) { + var findings []engine.Finding + + isFailedToMatchAll := false + + for _, expression := range r.Expressions { + findingIndexes := expression.FindAllIndex(file.Content, -1) + if findingIndexes != nil { + findings = append(findings, r.createFindingsFromIndexes(findingIndexes, file)...) + + continue + } + + isFailedToMatchAll = true + + break + } + + return r.getFirstFindingIfAllMatched(isFailedToMatchAll, findings), nil +} + +// getFirstFindingIfAllMatched checks if all regex expressions matched, if not will return nil. In case of all of them +// have match will get the first finding of the slice and return it to be used to generate the report +func (r *Rule) getFirstFindingIfAllMatched(isFailedToMatchAll bool, findings []engine.Finding) []engine.Finding { + if isFailedToMatchAll { + return nil + } + + if len(findings) >= 1 { + return []engine.Finding{findings[0]} + } + + return nil +} + +// runOrMatch for each regex expression will search for matches in the file and return they index and create the +// findings with them. Since the OrMatch type rules can match many times, they can return more than one finding for rule +func (r *Rule) runOrMatch(file *File) ([]engine.Finding, error) { + var findings []engine.Finding + + for _, expression := range r.Expressions { + findingIndexes := expression.FindAllIndex(file.Content, -1) + if findingIndexes != nil { + findings = append(findings, r.createFindingsFromIndexes(findingIndexes, file)...) + + continue + } + } + + return findings, nil +} + +// createFindingsFromIndexes for each index found of a possible vulnerability will get the line, column and code sample +// and create a new finding to append into the result +func (r *Rule) createFindingsFromIndexes(findingIndexes [][]int, file *File) (findings []engine.Finding) { + for _, findingIndex := range findingIndexes { + line, column := file.FindLineAndColumn(findingIndex[0]) + codeSample := file.ExtractSample(findingIndex[0]) + + findings = append(findings, r.newFinding( + file.RelativePath, + codeSample, + line, + column, + )) + } + + return findings +} + +// newFinding create a new finding with the information of the vulnerability obtained from the file +func (r *Rule) newFinding(filename, codeSample string, line, column int) engine.Finding { + return engine.Finding{ + ID: r.ID, + Name: r.Name, + Severity: r.Severity, + Confidence: r.Confidence, + Description: r.Description, + CodeSample: codeSample, + SourceLocation: engine.Location{ + Filename: filename, + Line: line, + Column: column, + }, + } +} + +// isBinary verify if the file being analyzed is a binary file +func (r *Rule) isBinary(content []byte) bool { + // Ignore Linux binaries + if bytes.Equal(content[:4], elfMagicNumber) { + return true + } + + // Ignore Windows binaries + if bytes.Equal(content[:2], peMagicBytes) { + return true + } + + return false } diff --git a/text/rule_test.go b/text/rule_test.go new file mode 100644 index 0000000..539396a --- /dev/null +++ b/text/rule_test.go @@ -0,0 +1,171 @@ +// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package text + +import ( + "path/filepath" + "regexp" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRun(t *testing.T) { + testCases := []struct { + name string + filepath string + matchType MatchType + expressions []*regexp.Regexp + expectedFindings int + }{ + { + name: "Should return 1 findings with match type AndMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: AndMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`Logger\.Fatal`), + regexp.MustCompile(`echoInstance.Start`), + }, + expectedFindings: 1, + }, + { + name: "Should return 3 findings with match type OrMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: OrMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`echoInstance\.Use\(middleware`), + }, + expectedFindings: 3, + }, + { + name: "Should return 1 findings with match type NotMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: NotMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`should-not-match`), + }, + expectedFindings: 1, + }, + { + name: "Should return 0 findings with match type AndMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: AndMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`should-not-match`), + regexp.MustCompile(`echoInstance.Start`), + }, + expectedFindings: 0, + }, + { + name: "Should return 0 findings with match type OrMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: OrMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`should-not-match`), + }, + expectedFindings: 0, + }, + { + name: "Should return 0 findings with match type NotMatch and go sample", + filepath: filepath.Join("examples", "go", "example1", "api", "server.go"), + matchType: NotMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`Logger\.Fatal`), + }, + expectedFindings: 0, + }, + { + name: "Should return 1 findings with match type AndMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: AndMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`secret =`), + regexp.MustCompile(`password =`), + regexp.MustCompile(`command =`), + }, + expectedFindings: 1, + }, + { + name: "Should return 3 findings with match type OrMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: OrMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`secret =`), + regexp.MustCompile(`password =`), + regexp.MustCompile(`command =`), + regexp.MustCompile(`print(secret)`), + }, + expectedFindings: 3, + }, + { + name: "Should return 1 findings with match type NotMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: NotMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`should-not-match`), + }, + expectedFindings: 1, + }, + { + name: "Should return 0 findings with match type AndMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: AndMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`secret =`), + regexp.MustCompile(`password =`), + regexp.MustCompile(`should-not-match`), + }, + expectedFindings: 0, + }, + { + name: "Should return 0 findings with match type OrMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: OrMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`should-not-match`), + regexp.MustCompile(`should-not-match`), + }, + expectedFindings: 0, + }, + { + name: "Should return 0 findings with match type NotMatch and python sample", + filepath: filepath.Join("examples", "python", "example1", "main.py"), + matchType: NotMatch, + expressions: []*regexp.Regexp{ + regexp.MustCompile(`secret =`), + }, + expectedFindings: 0, + }, + } + + for index, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + rule := &Rule{ + Type: testCase.matchType, + Expressions: testCase.expressions, + } + + findings, err := rule.Run(testCase.filepath) + assert.NoError(t, err) + assert.Lenf( + t, + findings, + testCase.expectedFindings, + "should contains %d findings, but has %d. Test case %d", + testCase.expectedFindings, len(findings), index, + ) + }) + } +} diff --git a/text/unit.go b/text/unit.go deleted file mode 100644 index 9b2c69b..0000000 --- a/text/unit.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package text - -import engine "github.com/ZupIT/horusec-engine" - -// nolint // name is necessary for now called TextUnit for not occurs breaking changes -type TextUnit struct { - Files []TextFile -} - -//nolint // change to pointer -func newFinding(ruleData TextRule, filename, codeSample string, line, column int) engine.Finding { - return engine.Finding{ - ID: ruleData.ID, - Name: ruleData.Name, - Severity: ruleData.Severity, - Confidence: ruleData.Confidence, - Description: ruleData.Description, - - CodeSample: codeSample, - - SourceLocation: engine.Location{ - Filename: filename, - Line: line, - Column: column, - }, - } -} - -//nolint // change to pointer -func createFindingsFromIndexes(findingIndexes [][]int, file TextFile, rule TextRule) (findings []engine.Finding) { - for _, findingIndex := range findingIndexes { - line, column := file.FindLineAndColumn(findingIndex[0]) - codeSample := file.ExtractSample(findingIndex[0]) - - findings = append(findings, newFinding( - rule, - file.DisplayName, - codeSample, - line, - column, - )) - } - - return findings -} - -// nolint // Complex method for pass refactor now TODO: Refactor this method in the future to clean code -func (unit TextUnit) evalRegularRule(textRule TextRule, findingsChan chan<- []engine.Finding) { - for _, file := range unit.Files { - localFile := file // Preventing Gorountines of accessing the shared memory bit :/ - go func() { - var findings []engine.Finding - - for _, expression := range textRule.Expressions { - findingIndexes := expression.FindAllStringIndex(localFile.Content(), -1) - - if findingIndexes != nil { - ruleFindings := createFindingsFromIndexes(findingIndexes, localFile, textRule) - findings = append(findings, ruleFindings...) - - continue - } - } - - findingsChan <- findings - }() - } -} - -//nolint // change to pointer -func (unit TextUnit) evalNotMatchRule(textRule TextRule, findingsChan chan<- []engine.Finding) { - for _, file := range unit.Files { - localFile := file // Preventing Gorountines of accessing the shared memory bit :/ - go func() { - var findings []engine.Finding - - for _, expression := range textRule.Expressions { - findingIndexes := expression.FindAllStringIndex(localFile.Content(), -1) - if findingIndexes == nil { - findings = append(findings, newFinding(textRule, localFile.DisplayName, "", 0, 0)) - } - } - - findingsChan <- findings - }() - } -} - -// nolint // Complex method for pass refactor now TODO: Refactor this method in the future to clean code -func (unit TextUnit) evalAndMatchRule(textRule TextRule, findingsChan chan<- []engine.Finding) { - for _, file := range unit.Files { - localFile := file // Preventing Gorountines of accessing the shared memory bit :/ - go func() { - var findings []engine.Finding - var ruleFindings []engine.Finding - haveFound := true - - for _, expression := range textRule.Expressions { - findingIndexes := expression.FindAllStringIndex(localFile.Content(), -1) - - if findingIndexes != nil { - ruleFindings = append(ruleFindings, createFindingsFromIndexes(findingIndexes, localFile, textRule)...) - continue - } - - haveFound = false - break - } - - if haveFound { - findings = append(findings, getFirstFinding(ruleFindings)) - } - - findingsChan <- findings - }() - } -} - -func getFirstFinding(ruleFindings []engine.Finding) engine.Finding { - if len(ruleFindings) >= 1 { - return ruleFindings[0] - } - - return engine.Finding{} -} - -func (unit TextUnit) Type() engine.UnitType { - return engine.ProgramTextUnit -} - -// nolint // Complex method for pass refactor now TODO: Refactor this method in the future to clean code -func (unit TextUnit) Eval(rule engine.Rule) (unitFindings []engine.Finding) { - if len(unit.Files) == 0 { - return unitFindings - } - - chanSize := len(unit.Files) - findingsChannel := make(chan []engine.Finding, chanSize) - - if textRule, ok := rule.(TextRule); ok { - unit.factoryExecuteEvalRuleAsyncByTextRuleType(textRule, findingsChannel) - } else { - // The rule isn't a TextRule, so we just bail out - return []engine.Finding{} - } - - for i := 1; i <= chanSize; i++ { - fileFindings := <-findingsChannel - unitFindings = append(unitFindings, fileFindings...) - } - - close(findingsChannel) - - return unitFindings -} - -//nolint // change to pointer -func (unit TextUnit) factoryExecuteEvalRuleAsyncByTextRuleType( - textRule TextRule, findingsChannel chan []engine.Finding) { - switch textRule.Type { - case Regular: - go unit.evalRegularRule(textRule, findingsChannel) - case OrMatch: - go unit.evalRegularRule(textRule, findingsChannel) - case NotMatch: - go unit.evalNotMatchRule(textRule, findingsChannel) - case AndMatch: - go unit.evalAndMatchRule(textRule, findingsChannel) - } -} diff --git a/text/unit_test.go b/text/unit_test.go deleted file mode 100644 index e38a217..0000000 --- a/text/unit_test.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package text - -import ( - "path/filepath" - "regexp" - "testing" - - engine "github.com/ZupIT/horusec-engine" -) - -func TestTextUnitEvalWithRegularMatch(t *testing.T) { - var exampleGoFile = `package version - -import ( - "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" - "github.com/spf13/cobra" -) - -type IVersion interface { - CreateCobraCmd() *cobra.Command -} - -type Version struct { -} - -func NewVersionCommand() IVersion { - return &Version{} -} - -func (v *Version) CreateCobraCmd() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Actual version installed of the horusec", - Example: "horusec version", - RunE: func(cmd *cobra.Command, args []string) error { - logger.LogPrint(cmd.Short + " is: ") - return nil - }, - } -} -` - - var textUnit TextUnit = TextUnit{} - goTextFile, err := NewTextFile("example/cmd/version.go", []byte(exampleGoFile)) - - if err != nil { - t.Error(err) - } - - textUnit.Files = append(textUnit.Files, goTextFile) - - var regularMatchRule TextRule = TextRule{} - regularMatchRule.Type = Regular - regularMatchRule.Expressions = append(regularMatchRule.Expressions, regexp.MustCompile(`cmd\.Short`)) - - rules := []engine.Rule{regularMatchRule} - program := []engine.Unit{textUnit} - - findings := engine.Run(program, rules) - - for _, finding := range findings { - t.Log(finding.SourceLocation) - } - - if len(findings) < 1 || len(findings) > 1 { - t.Fatal("Should find only 1 finding") - } - -} - -func TestTextUnitEvalWithRegularMatchWithNoPositiveMatches(t *testing.T) { - var exampleGoFile = `package version - -type Version struct { -} - -` - - var textUnit TextUnit = TextUnit{} - goTextFile, err := NewTextFile("example/cmd/version.go", []byte(exampleGoFile)) - - if err != nil { - t.Error(err) - } - - textUnit.Files = append(textUnit.Files, goTextFile) - - var regularMatchRule TextRule = TextRule{} - regularMatchRule.Type = Regular - regularMatchRule.Expressions = append(regularMatchRule.Expressions, regexp.MustCompile(`cmd\.Short`)) - - rules := []engine.Rule{regularMatchRule} - program := []engine.Unit{textUnit} - - findings := engine.Run(program, rules) - - for _, finding := range findings { - t.Log(finding.SourceLocation) - } - - if len(findings) > 0 { - t.Fatal("Should not find anything") - } -} - -func TestTextUnitEvalWithRegularMatchWithMultipleFiles(t *testing.T) { - var examplePositiveGoFile = `package version - -import ( - "github.com/ZupIT/horusec/development-kit/pkg/utils/logger" - "github.com/spf13/cobra" -) - -type IVersion interface { - CreateCobraCmd() *cobra.Command -} - -type Version struct { -} - -func NewVersionCommand() IVersion { - return &Version{} -} - -func (v *Version) CreateCobraCmd() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Actual version installed of the horusec", - Example: "horusec version", - RunE: func(cmd *cobra.Command, args []string) error { - logger.LogPrint(cmd.Short + " is: ") - return nil - }, - } -} -` - - var exampleNegativeGoFile = `package version - -type Version struct { -} - -` - - var textUnit TextUnit = TextUnit{} - goPositiveTextFile, err := NewTextFile("example/cmd/version.go", []byte(examplePositiveGoFile)) - - if err != nil { - t.Error(err) - } - - goNegativeTextFile, err := NewTextFile("example/cmd/struct.go", []byte(exampleNegativeGoFile)) - - if err != nil { - t.Error(err) - } - - textUnit.Files = append(textUnit.Files, goPositiveTextFile) - textUnit.Files = append(textUnit.Files, goNegativeTextFile) - - var regularMatchRule TextRule = TextRule{} - regularMatchRule.Type = Regular - regularMatchRule.Expressions = append(regularMatchRule.Expressions, regexp.MustCompile(`cmd\.Short`)) - - rules := []engine.Rule{regularMatchRule} - program := []engine.Unit{textUnit} - - findings := engine.Run(program, rules) - - for _, finding := range findings { - t.Log(finding.SourceLocation) - } - - if len(findings) < 1 || len(findings) > 1 { - t.Fatalf("Should find only 1 finding, but found %d", len(findings)) - } -} - -func TestTextunitEvalWithRegularMatchWithMultipleRules(t *testing.T) { - javaFileContent := `package com.mycompany.app; - -import java.util.Random; - -/** - * Hello world! - * - */ -public class App -{ - public static void main( String[] args ) - { - String password = "Ch@ng3m3" - Random rand = new Random(); - System.out.println(rand.nextInt(50)); - System.out.println( "Hello World!" ); - System.out.println( "Actual password" + password ); - } -}` - - var textUnit TextUnit = TextUnit{} - - javaFile, err := NewTextFile("example/src/main.java", []byte(javaFileContent)) - - if err != nil { - t.Fatal(err) - } - - textUnit.Files = append(textUnit.Files, javaFile) - - var regularMatchRule TextRule = TextRule{} - regularMatchRule.Type = Regular - regularMatchRule.Description = "Finds java.util.Random imports" - regularMatchRule.Expressions = append(regularMatchRule.Expressions, regexp.MustCompile(`java\.util\.Random`)) - - var anotherRegularMatchRule TextRule = TextRule{} - anotherRegularMatchRule.Type = Regular - anotherRegularMatchRule.Description = "Finds hardcoded passwords" - anotherRegularMatchRule.Expressions = append(anotherRegularMatchRule.Expressions, regexp.MustCompile(`(password\s*=\s*['|\"]\w+[[:print:]]*['|\"])|(pass\s*=\s*['|\"]\w+['|\"]\s)|(pwd\s*=\s*['|\"]\w+['|\"]\s)|(passwd\s*=\s*['|\"]\w+['|\"]\s)|(senha\s*=\s*['|\"]\w+['|\"])`)) - - rules := []engine.Rule{regularMatchRule, anotherRegularMatchRule} - program := []engine.Unit{textUnit} - - findings := engine.Run(program, rules) - - for _, finding := range findings { - t.Log(finding.Description) - t.Log(finding.SourceLocation) - } - - if len(findings) < 2 || len(findings) > 2 { - t.Fatalf("Should find only 2 finding, but found %d", len(findings)) - } - -} - -func TestTextunitEvalWithAndMatch(t *testing.T) { - javaFileContent := `package com.mycompany.app; - -import java.util.Random; - -/** - * Hello world! - * - */ -public class App -{ - public static void main( String[] args ) - { - String password = "Ch@ng3m3" - Random rand = new Random(); - System.out.println(rand.nextInt(50)); - System.out.println( "Hello World!" ); - System.out.println( "Actual password" + password ); - } -}` - - var textUnit TextUnit = TextUnit{} - - javaFile, err := NewTextFile("example/src/main.java", []byte(javaFileContent)) - - if err != nil { - t.Fatal(err) - } - - textUnit.Files = append(textUnit.Files, javaFile) - - var andMatchRule TextRule = TextRule{} - andMatchRule.Description = "Finds java.util.Random imports" - andMatchRule.Type = AndMatch - andMatchRule.Expressions = append(andMatchRule.Expressions, regexp.MustCompile(`java\.util\.Random`)) - andMatchRule.Expressions = append(andMatchRule.Expressions, regexp.MustCompile(`rand\.\w+\(`)) - - rules := []engine.Rule{andMatchRule} - program := []engine.Unit{textUnit} - - findings := engine.Run(program, rules) - - for _, finding := range findings { - t.Log(finding.Description) - t.Log(finding.SourceLocation) - } - - if len(findings) != 1 { - t.Fatalf("Should find only 1 finding, but found %d", len(findings)) - } - -} - -/* - * - * - * ******* Benchmarks ******** - * - */ - -func BenchmarkHeavyGolangWithSingleTextUnit(b *testing.B) { - benchFiles := []string{ - "benchmark.perf", - "benchmark1.perf", - "benchmark2.perf", - "benchmark3.perf", - "benchmark4.perf", - } - - var textUnit TextUnit = TextUnit{} - - var summaryIdentifier TextRule = TextRule{} - summaryIdentifier.Expressions = append(summaryIdentifier.Expressions, regexp.MustCompile(`Summary`)) - - var instanceIdentifier TextRule = TextRule{} - instanceIdentifier.Expressions = append(instanceIdentifier.Expressions, regexp.MustCompile(`Instance`)) - - var staticMethodsIdentifier TextRule = TextRule{} - staticMethodsIdentifier.Expressions = append(staticMethodsIdentifier.Expressions, regexp.MustCompile(`static`)) - - rules := []engine.Rule{summaryIdentifier, instanceIdentifier, staticMethodsIdentifier} - - for _, benchFileName := range benchFiles { - benchFile, err := ReadAndCreateTextFile(filepath.Join("examples", "perf", benchFileName)) - - if err != nil { - b.Fatal(err) - } - - textUnit.Files = append(textUnit.Files, benchFile) - } - - program := []engine.Unit{textUnit} - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - engine.Run(program, rules) - } -} - -func BenchmarkHeavyGolangWithMultipleUnits(b *testing.B) { - benchFiles := []string{ - "benchmark.perf", - "benchmark1.perf", - "benchmark2.perf", - "benchmark3.perf", - "benchmark4.perf", - } - - var summaryIdentifier TextRule = TextRule{} - summaryIdentifier.Expressions = append(summaryIdentifier.Expressions, regexp.MustCompile(`Summary`)) - - var instanceIdentifier TextRule = TextRule{} - instanceIdentifier.Expressions = append(instanceIdentifier.Expressions, regexp.MustCompile(`Instance`)) - - var staticMethodsIdentifier TextRule = TextRule{} - staticMethodsIdentifier.Expressions = append(staticMethodsIdentifier.Expressions, regexp.MustCompile(`static`)) - - rules := []engine.Rule{summaryIdentifier, instanceIdentifier, staticMethodsIdentifier} - - program := []engine.Unit{} - - for _, benchFileName := range benchFiles { - var textUnit TextUnit = TextUnit{} - benchFile, err := ReadAndCreateTextFile(filepath.Join("examples", "perf", benchFileName)) - - if err != nil { - b.Fatal(err) - } - - textUnit.Files = append(textUnit.Files, benchFile) - for i := 0; i <= 1024; i++ { - program = append(program, textUnit) - } - } - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - engine.Run(program, rules) - } -}