diff --git a/.github/workflows/security-pipeline.yml b/.github/workflows/security-pipeline.yml index 4b2ebff..5025d18 100644 --- a/.github/workflows/security-pipeline.yml +++ b/.github/workflows/security-pipeline.yml @@ -7,10 +7,9 @@ jobs: name: horusec-security runs-on: ubuntu-latest steps: - - name: Check out code into the Go module directory + - name: Check out code uses: actions/checkout@v2 - name: Running Horusec Security - shell: bash run: | - curl -fsSL https://horusec-cli.s3.amazonaws.com/install.sh | bash - horusec start -p="./" + curl -fsSL https://horusec.io/bin/install.sh | bash + horusec start -p="./" -e="true" diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..027705d --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,122 @@ +linters-settings: + govet: + check-shadowing: true + settings: + printf: + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + golint: + min-confidence: 0.8 + gocyclo: + min-complexity: 5 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 2 + depguard: + list-type: blacklist + packages: + # logging is allowed only by logutils.Log, logrus + # is allowed to use only in logutils package + - github.com/sirupsen/logrus + packages-with-error-messages: + github.com/sirupsen/logrus: "logging is allowed only by logutils.Log" + misspell: + locale: US + lll: + line-length: 120 + goimports: + local-prefixes: github.com/golangci/golangci-lint + gocritic: + enabled-tags: + - opinionated + - experimental + - diagnostic + - style + - performance + disabled-checks: + - evalOrder + - wrapperFunc + - unnamedResult + - octalLiteral + - dupImport + funlen: + lines: 15 + statements: 10 + +linters: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + disable-all: true + enable: + - dogsled + - deadcode + - depguard + - bodyclose + - funlen + - errcheck + - dupl + - gocritic + - gochecknoinits + - goconst + - gofmt + - gocyclo + - gosec + - golint + - ineffassign + - gosimple + - govet + - lll + - interfacer + - nakedret + - misspell + - staticcheck + - scopelint + - stylecheck + - structcheck + - unconvert + - typecheck + - unused + - unparam + - whitespace + - varcheck + +run: + skip-dirs: + - vendor/ + - tmp + - e2e/ + skip-files: + - .*_test.go + - .*_mock.go + +issues: + exclude-rules: + - path: platforms/finding.go + linters: + - gocritic + - path: platforms/rule.go + linters: + - gocritic + - path: text/file.go + linters: + - gocritic + - path: text/rule.go + linters: + - gocritic + - path: text/unit.go + linters: + - gocritic + +# golangci.com configuration +# https://github.com/golangci/golangci/wiki/Configuration +service: + golangci-lint-version: v1.21.0 # use the fixed version to not introduce new linters unexpectedly + prepare: + - echo "here I can run custom commands, but no preparation needed for this repo" diff --git a/.semver.yaml b/.semver.yaml index c40351d..accf0ac 100644 --- a/.semver.yaml +++ b/.semver.yaml @@ -1,4 +1,4 @@ alpha: 0 beta: 0 rc: 0 -release: v0.2.7 +release: v0.2.8 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7476b2d..d048d90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Please note we have a code of conduct, please follow it in all your interactions 2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. 3. Increase the version numbers in any examples files and the README.md to the new version that this - Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). You can usage [SEMVER-CLI](deployments/scripts/install-semver.sh) too. + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). You can usage [SEMVER-CLI](https://github.com/ZupIT/horusec/tree/master/deployments/semver) too. 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. diff --git a/Makefile b/Makefile index 15fd943..c9d16bb 100644 --- a/Makefile +++ b/Makefile @@ -9,17 +9,15 @@ fmt: # Run converage with threshold coverage: - deployments/scripts/coverage.sh 75 + curl -fsSL https://raw.githubusercontent.com/ZupIT/horusec/master/deployments/scripts/coverage.sh | bash -s 75 . # Check lint of project setup on file .golangci.yml lint: ifeq ($(wildcard $(GOCILINT)), $(GOCILINT)) -# $(GOCILINT) run -v --timeout=2m -c .golangci.yml ./... # not implemented lint equals of the horusec - $(GOCILINT) run -v --timeout=2m ./... + $(GOCILINT) run -v --timeout=2m -c .golangci.yml ./... else curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.25.0 -# $(GOCILINT) run -v --timeout=2m -c .golangci.yml ./... # not implemented lint equals of the horusec - $(GOCILINT) run -v --timeout=2m ./... # not implemented lint equals of the horusec + $(GOCILINT) run -v --timeout=2m -c .golangci.yml ./... endif # Run all tests of project but stop the execution on the first test fail diff --git a/deployments/scripts/coverage.sh b/deployments/scripts/coverage.sh deleted file mode 100755 index b376fee..0000000 --- a/deployments/scripts/coverage.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# 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. - - -THRESHOLD=$1 - -go clean -testcache -go test -timeout=2m -covermode=atomic -coverprofile coverage.out ./... -sed -i '/mock.go/d' coverage.out -COVERAGE=$(go tool cover -func=coverage.out | grep total: | awk '{print $3}') -COVERAGE=${COVERAGE%\%} - -if [ 1 -eq "$(echo $COVERAGE'>='$THRESHOLD | bc -l)" ] -then - echo "SUCCESS! Coverage above threshold" - echo "coverage: ${COVERAGE} - threshold: ${THRESHOLD}" - exit 0 -fi - -echo "FAILS! Coverage below threshold" -echo "coverage: ${COVERAGE} - threshold: ${THRESHOLD}" -exit 1 diff --git a/deployments/scripts/install-semver.sh b/deployments/scripts/install-semver.sh deleted file mode 100755 index 60c6588..0000000 --- a/deployments/scripts/install-semver.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -checkIfInstallationIsValid () { - semver &> /dev/null - RESPONSE=$? - if [ $RESPONSE != "0" ] - then - LOCATION_SEMVER=$(which semver) - echo "Semver is not installed please remove the binary in location [$LOCATION_SEMVER] and run again" - exit 1 - else - echo "Semver was installed with success!" - fi -} - -installSemver () { - semver &> /dev/null - RESPONSE=$? - if [ $RESPONSE != "0" ] - then - echo "Installing semver..." - curl https://horus-assets.s3.amazonaws.com/semver -o ./semver - chmod +x ./semver - sudo mv ./semver /usr/local/bin/semver - fi -} - -installSemver - -checkIfInstallationIsValid \ No newline at end of file diff --git a/deployments/scripts/up-version.sh b/deployments/scripts/up-version.sh deleted file mode 100755 index 4018546..0000000 --- a/deployments/scripts/up-version.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/bash - -# The purpose of this script is to simplify the way of generating a tag for github. -# Example: -# * A correction was made and updated the develop branch: -# * ./deployments/scripts/up-version.sh alpha -# * A new feature was made and updated the develop branch: -# * ./deployments/scripts/up-version.sh alpha -# * We are preparing the branch to develop and send it to production: -# * ./deployments/scripts/up-version.sh rc -# * After opening the PR and performing the merge of develop on the master, we must update the master and develop tag: -# * ./deployments/scripts/up-version.sh minor -# * We made a correction(hotfix) to the production environment and we have already merged the master branch and automatically need to update the develop branch: -# * ./deployments/scripts/up-version.sh release -# * We had to do a refactoring in the services and hear a "breaking changes" in the master branch: -# * ./deployments/scripts/up-version.sh major - -UPDATE_TYPE=$1 -BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) -TAG_VERSION="" - -validateUpdateType () { - case "$UPDATE_TYPE" in - "alpha") # Used to update an bugfix or an new feature in develop branch - echo "Update type selected is alpha" ;; - "rc") # Used when you finish development and start testing in the test environment and in develop branch - echo "Update type selected is rc(release-candidate)" ;; - "release") # Used when an correction was applied in master branch - echo "Update type selected is release" ;; - "minor") # Used when an new feature is enable in production environment and in master branch - echo "Update type selected is minor" ;; - "major") # Used when an big refactor is necessary to breaking changes in master branch - echo "Update type selected is major" ;; - *) - echo "Param Update type is invalid, please use the examples bellow allowed and try again!" - echo "Params Update type allowed: alpha, rc, release, minor, major" - exit 1;; - esac -} - -installSemver () { - chmod +x ./deployments/scripts/install-semver.sh - ./deployments/scripts/install-semver.sh -} - -validateCurrentBranch () { - # If branch not allowed return errors - if [[ "$UPDATE_TYPE" == "alpha" || "$UPDATE_TYPE" == "rc" ]] - then - if [ "$BRANCH_NAME" != "develop" ] - then - echo "Your current branch is \"$BRANCH_NAME\". For this update type only branch enable is \"develop\"" - echo "Please use the follow command to update your project" - echo "git checkout develop && git pull origin develop" - exit 1 - fi - git pull origin develop - else - if [ "$BRANCH_NAME" != "master" ] - then - echo "Your current branch is \"$BRANCH_NAME\". For this update type only branch enable is \"master\"" - echo "Please use the follow command to update your project" - echo "git checkout master && git pull origin master" - exit 1 - fi - git pull origin master - fi -} - -resetAlphaRcToMaster () { - alpha_version=$(semver get alpha) - rc_version=$(semver get rc) - if [[ "${alpha_version: -2}" != ".0" || "${rc_version: -2}" != ".0" ]] - then - echo "Alpha or Release-Candidate found, reseting version to:" - semver up release - fi -} - -upNewVersion () { - # Update version - if [ "$BRANCH_NAME" == "master" ] - then - resetAlphaRcToMaster - fi - echo "Update version to:" - semver up "$UPDATE_TYPE" - if [ "$BRANCH_NAME" == "master" ] - then - TAG_VERSION=$(semver get release) - else - TAG_VERSION=$(semver get "$UPDATE_TYPE") - fi - echo "Tag has been generated in version: $TAG_VERSION" - - # Commit new version - git tag "$TAG_VERSION" - git add ".semver.yaml" - git commit -m "[skip ci] update versioning file" -} - -pushChangesAndCheckResponse () { - # Update version - git push origin "$BRANCH_NAME" - RESULT_PUSH=$? - if [[ $RESULT_PUSH -eq 0 ]] - then - git push --tags - RESULT_PUSH=$? - if [[ $RESULT_PUSH -eq 0 ]] - then - echo "New version was updated!" - else - echo "Error on push tags: $RESULT_PUSH" - exit 1 - fi - else - echo "Error on push in branch: $RESULT_PUSH" - exit 1 - fi -} - -validateUpdateType - -installSemver - -validateCurrentBranch - -upNewVersion - -pushChangesAndCheckResponse - -exit 0 \ No newline at end of file diff --git a/engine.go b/engine.go index 49b5358..ce1775a 100644 --- a/engine.go +++ b/engine.go @@ -27,17 +27,17 @@ func RunOutputInJSON(document []Unit, rules []Rule, jsonFilePath string) error { if err != nil { return err } - if _, err := os.Create(jsonFilePath); err != nil { - return err - } - outputFile, err := os.OpenFile(jsonFilePath, os.O_CREATE|os.O_WRONLY, 0644) + outputFile, err := createOutputFile(jsonFilePath) + defer func() { + _ = outputFile.Close() + }() if err != nil { return err } - defer outputFile.Close() - if err = outputFile.Truncate(0); err != nil { - return err - } + return writeInOutputFile(outputFile, bytesToWrite) +} + +func writeInOutputFile(outputFile *os.File, bytesToWrite []byte) error { bytesWritten, err := outputFile.Write(bytesToWrite) if err != nil { return err @@ -51,27 +51,37 @@ func RunOutputInJSON(document []Unit, rules []Rule, jsonFilePath string) error { return nil } +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 + } + return outputFile, outputFile.Truncate(0) +} + func Run(document []Unit, rules []Rule) (documentFindings []Finding) { - if len(document) < 1 || len(rules) < 1 { + numberOfUnits := (len(document)) * (len(rules)) + if numberOfUnits == 0 { return []Finding{} } - numberOfUnits := (len(document)) * (len(rules)) + return executeRunByNumberOfUnits(numberOfUnits, document, rules) +} +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 } diff --git a/horusec-config.json b/horusec-config.json new file mode 100644 index 0000000..11869ac --- /dev/null +++ b/horusec-config.json @@ -0,0 +1,5 @@ +{ + "horusecCliFilesOrPathsToIgnore": "**/*_test.go, **/*_mock.go, **/*README.md, **/text/samples/**", + "horusecCliFalsePositiveHashes": "", + "horusecCliRiskAcceptHashes": "3089286353624d73b4aead98620dd433f571392350e7e3ccd3846a37f8ef5cb3, 30de4b818b007c1ce18499e62c0df018e5a7d1fcbad88e3660cbd0c1b91a996b" +} \ No newline at end of file diff --git a/platforms/android/manifest.go b/platforms/android/manifest.go index 4917ca5..17dab56 100644 --- a/platforms/android/manifest.go +++ b/platforms/android/manifest.go @@ -68,7 +68,7 @@ type ApplicationInfo struct { Services []Service `xml:"service"` } -// Manifest is a marshalled version of all the data in the AndroidManifest.xml file +// 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"` @@ -84,6 +84,7 @@ 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 { @@ -91,7 +92,7 @@ func (unit ManifestUnit) Eval(rule engine.Rule) (unitFindings []engine.Finding) for _, expression := range structuredDataRule.Expressions { exprResult := xmlquery.QuerySelectorAll(unit.Document, expression) - if len(exprResult) <= 0 { + if len(exprResult) < 1 { return } diff --git a/platforms/finding.go b/platforms/finding.go index aa37189..cbed621 100644 --- a/platforms/finding.go +++ b/platforms/finding.go @@ -6,16 +6,15 @@ import ( // PopulateFindingWithRuleMetadata converts the engine.Metadata field inside the StructuredDataRule to a engine.Finding // struct -func PopulateFindingWithRuleMetadata(ruleData StructuredDataRule, filename, codeSample string, line, column int) engine.Finding { +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, - + CodeSample: codeSample, SourceLocation: engine.Location{ Filename: filename, Line: line, diff --git a/text/file.go b/text/file.go index c7733a6..a7a58be 100644 --- a/text/file.go +++ b/text/file.go @@ -42,12 +42,13 @@ func binarySearch(searchIndex int, collection []int) (foundIndex int) { } // TextFile represents a file to be analyzed +// nolint 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/Documents/myProject/router/handler.js) + // 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 @@ -58,21 +59,16 @@ type TextFile struct { } func NewTextFile(relativeFilePath string, content []byte) (TextFile, error) { - var err error - var formattedPhysicalPath string - - if !filepath.IsAbs(relativeFilePath) { - formattedPhysicalPath, err = filepath.Abs(relativeFilePath) - - if err != nil { - return TextFile{}, err - } - } else { - formattedPhysicalPath = relativeFilePath + formattedPhysicalPath, err := validateRelativeFilePath(relativeFilePath) + if err != nil { + return TextFile{}, err } - _, formattedFilename := filepath.Split(formattedPhysicalPath) + 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), @@ -81,20 +77,27 @@ func NewTextFile(relativeFilePath string, content []byte) (TextFile, error) { Name: formattedFilename, DisplayName: relativeFilePath, } - textfile.newlineIndexes = newlineFinder.FindAllIndex(content, -1) for _, newlineIndex := range textfile.newlineIndexes { textfile.newlineEndingIndexes = append(textfile.newlineEndingIndexes, newlineIndex[0]) } + return textfile +} + +func validateRelativeFilePath(relativeFilePath string) (string, error) { + if !filepath.IsAbs(relativeFilePath) { + return filepath.Abs(relativeFilePath) + } - return textfile, nil + return relativeFilePath, nil } func (textfile TextFile) Content() string { return textfile.RawString } +// nolint TODO: Remove commentaries and refactor method to clean code func (textfile TextFile) FindLineAndColumn(findingIndex int) (line, column int) { // findingIndex is the index of the beginning of the text we want to // locate inside the file @@ -130,8 +133,7 @@ func (textfile TextFile) FindLineAndColumn(findingIndex int) (line, column int) column = (findingIndex - 1) - endOfCurrentLineInTheFile } } - - return + return line, column } func (textfile TextFile) ExtractSample(findingIndex int) string { @@ -154,13 +156,11 @@ func (textfile TextFile) ExtractSample(findingIndex int) string { func ReadAndCreateTextFile(filename string) (TextFile, error) { textFileContent, err := ReadTextFile(filename) - if err != nil { return TextFile{}, err } textFileMagicBytes := textFileContent[:4] - if bytes.Equal(textFileMagicBytes, ELFMagicNumber) { // Ignore Linux binaries return TextFile{}, nil @@ -196,10 +196,9 @@ func LoadDirIntoSingleUnit(path string, extensionsAccept []string) (TextUnit, er // Example: []string{".java"} // If an item of slice contains is equal the "**" it's will accept all extensions // Example: []string{"**"} +// nolint Complex method for pass refactor now TODO: Refactor this method in the future to clean code func LoadDirIntoMultiUnit(path string, maxFilesPerTextUnit int, extensionsAccept []string) ([]TextUnit, error) { - units := []TextUnit{ - TextUnit{}, - } + units := []TextUnit{{}} lastIndexToAdd := 0 err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() { diff --git a/text/reader.go b/text/reader.go index 41f010b..ce3c219 100644 --- a/text/reader.go +++ b/text/reader.go @@ -36,17 +36,15 @@ func newUnicodeReader(defaultReader io.Reader) io.Reader { // the encoding to UTF-8. func ReadTextFile(filename string) ([]byte, error) { fileDescriptor, err := os.Open(filename) - if err != nil { return []byte{}, err } - - defer fileDescriptor.Close() + defer func() { + _ = fileDescriptor.Close() + }() reader := newUnicodeReader(fileDescriptor) - utf8FormattedString, err := ioutil.ReadAll(reader) - if err != nil { return []byte{}, err } diff --git a/text/rule.go b/text/rule.go index 7ff69ef..0eafa6f 100644 --- a/text/rule.go +++ b/text/rule.go @@ -29,6 +29,7 @@ const ( AndMatch ) +// nolint name is necessary for now called TextRule for not occurs breaking changes type TextRule struct { engine.Metadata Type MatchType diff --git a/text/unit.go b/text/unit.go index cc1f247..d2ecdf3 100644 --- a/text/unit.go +++ b/text/unit.go @@ -16,6 +16,7 @@ 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 } @@ -43,20 +44,19 @@ func createFindingsFromIndexes(findingIndexes [][]int, file TextFile, rule TextR line, column := file.FindLineAndColumn(findingIndex[0]) codeSample := file.ExtractSample(findingIndex[0]) - finding := newFinding( + findings = append(findings, newFinding( rule, file.DisplayName, codeSample, line, column, - ) - - findings = append(findings, finding) + )) } 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 :/ @@ -87,18 +87,17 @@ func (unit TextUnit) evalNotMatchRule(textRule TextRule, findingsChan chan<- []e 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 :/ @@ -140,8 +139,9 @@ 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 { + if len(unit.Files) == 0 { return unitFindings } @@ -149,16 +149,7 @@ func (unit TextUnit) Eval(rule engine.Rule) (unitFindings []engine.Finding) { findingsChannel := make(chan []engine.Finding, chanSize) if textRule, ok := rule.(TextRule); ok { - 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) - } + unit.factoryExecuteEvalRuleAsyncByTextRuleType(textRule, findingsChannel) } else { // The rule isn't a TextRule, so we just bail out return []engine.Finding{} @@ -173,3 +164,17 @@ func (unit TextUnit) Eval(rule engine.Rule) (unitFindings []engine.Finding) { return unitFindings } + +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) + } +}