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)
- }
-}