From a12a2edc459c1f22d806b0aed7fca4c17deac84d Mon Sep 17 00:00:00 2001 From: Wilian Gabriel Date: Tue, 23 Nov 2021 16:22:18 -0300 Subject: [PATCH] e2e:feature - update e2e/analysis tests for build locally (#761) * In older version i found some errors: * The analysis is not effective in check tools runned, because not apply assert in all tools runned by language, then i fixed this; * Occurs when horusec not found files required in project how requirements.txt and others, not exist validation if analysis was been executed with success, then i fixed this; * In older version when run analysis always download all tools from dockerhub, and this not validate if current version is OK for create new release, then was implemented this new test. Note the struct AnalysisTestCase is shared into both tests, then was moved to centralized file. * Another error found was that the error logs presented by the tool were scattered, so we centralized the SetAnalysisError function where, in addition to adding the error in the analysis, it also performs the unified log among all the tools. * An error was found in the language detect package, if the user is using a project with git submodule it was not possible to copy the git folder as it was only a reference so we fixed these problems. * In HCL language it was necessary to change your docker file seen at issue https://github.com/bridgecrewio/checkov/issues/1947 where we found a problem in checkov for alpine version * Was Updated all dockerfiles with image from python fix in version python:3.10.0-alpine3.14 * Was Update dockerfile of Ruby language for usage ruby:2.4.10-alpine base image, because brakeman tool is not suport for newest version of ruby * Was Updated DockerAPI for pass GITHUB_TOKEN env because nancy and others tools use the github api's and get error GitHub rate-limiting on unauthenticated requests Signed-off-by: wilian --- .github/workflows/e2e.yml | 18 +- Makefile | 11 +- deployments/scripts/build-all-tools.sh | 40 ++ e2e/analysis/analysis_suite_test.go | 3 + e2e/analysis/analysis_test.go | 221 +++--- e2e/analysis/test_case.go | 673 ++++++++++++++++++ examples | 2 +- .../language_detect/language_detect.go | 88 ++- .../language_detect/language_detect_test.go | 12 + .../controllers/printresults/print_results.go | 2 +- internal/helpers/messages/print.go | 19 + internal/services/docker/docker_api.go | 2 + .../formatters/c/deployments/Dockerfile | 2 +- .../formatters/c/flawfinder/formatter.go | 9 +- .../formatters/csharp/dotnet_cli/formatter.go | 9 +- .../formatters/csharp/scs/formatter.go | 18 +- .../formatters/default_engine_formatter.go | 2 +- .../formatters/elixir/mixaudit/formatter.go | 9 +- .../formatters/elixir/sobelow/formatter.go | 16 +- .../generic/dependency_check/formatter.go | 9 +- .../formatters/generic/deployments/Dockerfile | 2 +- .../formatters/generic/semgrep/formatter.go | 9 +- .../formatters/generic/trivy/config.go | 10 +- .../formatters/generic/trivy/formatter.go | 25 +- .../formatters/go/deployments/Dockerfile | 2 +- .../services/formatters/go/gosec/formatter.go | 9 +- .../services/formatters/go/nancy/formatter.go | 11 +- .../formatters/hcl/checkov/formatter.go | 9 +- .../formatters/hcl/deployments/Dockerfile | 12 +- .../formatters/hcl/tfsec/formatter.go | 9 +- internal/services/formatters/interface.go | 2 +- .../javascript/npmaudit/formatter.go | 15 +- .../javascript/yarnaudit/formatter.go | 15 +- .../formatters/leaks/deployments/Dockerfile | 1 + .../formatters/leaks/gitleaks/config.go | 7 +- .../formatters/leaks/gitleaks/formatter.go | 10 +- .../formatters/php/phpcs/formatter.go | 9 +- .../formatters/python/bandit/formatter.go | 18 +- .../formatters/python/deployments/Dockerfile | 2 +- .../formatters/python/safety/formatter.go | 23 +- .../formatters/ruby/brakeman/formatter.go | 10 +- .../formatters/ruby/bundler/formatter.go | 12 +- .../formatters/ruby/deployments/Dockerfile | 2 +- internal/services/formatters/service.go | 4 +- internal/services/formatters/service_test.go | 14 +- .../formatters/shell/shellcheck/formatter.go | 10 +- internal/utils/testutil/examples.go | 7 +- internal/utils/testutil/formatter_mock.go | 2 +- 48 files changed, 1146 insertions(+), 280 deletions(-) create mode 100755 deployments/scripts/build-all-tools.sh create mode 100644 e2e/analysis/test_case.go create mode 100644 internal/helpers/messages/print.go diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 74d1e7528..e479a05e8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -24,6 +24,9 @@ on: permissions: read-all jobs: test: + permissions: + contents: write + packages: write runs-on: ${{ matrix.os }} strategy: matrix: @@ -38,6 +41,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 with: + fetch-depth: 0 submodules: true - name: Setup Golang @@ -50,6 +54,14 @@ jobs: uses: docker-practice/actions-setup-docker@master with: docker_buildx: false - - - name: Run e2e test for ${{ matrix.os }} - run: go test -v ./e2e/... -timeout 60m -failfast -race \ No newline at end of file + - name: Build local images + if: ${{ matrix.os == 'ubuntu-latest' }} + run: sh ./deployments/scripts/build-all-tools.sh + - name: Run e2e analysis test for ${{ matrix.os }} + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: go test -v ./e2e/analysis/... -timeout 60m -failfast -race + - name: Run e2e commands test for ${{ matrix.os }} + env: + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + run: go test -v ./e2e/commands/... -timeout 60m -failfast -race diff --git a/Makefile b/Makefile index 3de083016..2772ddc7e 100644 --- a/Makefile +++ b/Makefile @@ -34,23 +34,26 @@ test: $(GO) test -v $(GO_LIST_TO_TEST) -race -timeout=5m -parallel=1 -failfast -short test-e2e: + sh ./deployments/scripts/build-all-tools.sh $(GO) clean -testcache - $(GO) test -v ./e2e/... -timeout=10m -parallel=1 -failfast + $(GO) test -v ./e2e/analysis/... -timeout=30m -parallel=1 -failfast + $(GO) clean -testcache + $(GO) test -v ./e2e/commands/... -timeout=30m -parallel=1 -failfast fix-imports: ifeq (, $(shell which $(GO_IMPORTS))) - $(GO) get -u golang.org/x/tools/cmd/goimports + $(GO) install 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 license: - $(GO) get -u github.com/google/addlicense + $(GO) install github.com/google/addlicense @$(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 @$(ADDLICENSE) -f ./copyright.txt $(shell find -regex '.*\.\(go\|js\|ts\|yml\|yaml\|sh\|dockerfile\)') security: diff --git a/deployments/scripts/build-all-tools.sh b/deployments/scripts/build-all-tools.sh new file mode 100755 index 000000000..480decd1d --- /dev/null +++ b/deployments/scripts/build-all-tools.sh @@ -0,0 +1,40 @@ +# Copyright 2021 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. + +IMAGE_BASE_NAME=$1 +IMAGE_TAG=$2 + +setDefaultImageBaseName() { + if [ -z "$IMAGE_BASE_NAME" ]; then + IMAGE_BASE_NAME="local" + fi + if [ -z "$IMAGE_TAG" ]; then + IMAGE_TAG="local" + fi +} + +getDirectoryAndImagesNameByLanguageName() { + # shellcheck disable=SC2044 + for DOCKERFILE in $(find internal -type f -iname "Dockerfile"); do + LANGUAGE=$(echo $DOCKERFILE | cut -d "/" -f4) + if ! docker build -t "$IMAGE_BASE_NAME-$LANGUAGE:$IMAGE_TAG" -f "$DOCKERFILE" .; then + echo "Error on build docker file in path: $DOCKERFILE" + exit 1 + fi + done +} + +setDefaultImageBaseName + +getDirectoryAndImagesNameByLanguageName \ No newline at end of file diff --git a/e2e/analysis/analysis_suite_test.go b/e2e/analysis/analysis_suite_test.go index 2c694a8af..ca52672db 100644 --- a/e2e/analysis/analysis_suite_test.go +++ b/e2e/analysis/analysis_suite_test.go @@ -17,11 +17,14 @@ package analysis_test import ( "testing" + ginkgoconfig "github.com/onsi/ginkgo/config" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) func TestAnalysis(t *testing.T) { + ginkgoconfig.GinkgoConfig.FailFast = true RegisterFailHandler(Fail) defer GinkgoRecover() RunSpecs(t, "Analysis Suite") diff --git a/e2e/analysis/analysis_test.go b/e2e/analysis/analysis_test.go index fb374e3ec..fad2b458c 100644 --- a/e2e/analysis/analysis_test.go +++ b/e2e/analysis/analysis_test.go @@ -15,123 +15,132 @@ package analysis_test import ( + "encoding/json" "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "time" + "github.com/ZupIT/horusec-devkit/pkg/enums/languages" + + "github.com/google/uuid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" - "github.com/ZupIT/horusec-devkit/pkg/enums/languages" - "github.com/ZupIT/horusec-devkit/pkg/enums/tools" + "github.com/ZupIT/horusec-devkit/pkg/utils/logger" + "github.com/ZupIT/horusec/config" + "github.com/ZupIT/horusec/e2e/analysis" + customimages "github.com/ZupIT/horusec/internal/entities/custom_images" "github.com/ZupIT/horusec/internal/utils/testutil" ) -type AnalysisTestCase struct { - Language languages.Language - AnalysisFolder string - ExpectedTools []tools.Tool -} +const isWindows = runtime.GOOS == "windows" +const isDarwin = runtime.GOOS == "darwin" +const horusecConfigName = "horusec-config.json" + +var _ = Describe("Run a complete horusec analysis when build tools locally", func() { + tmpDir := CreateHorusecConfigAndReturnTMPDirectory() + + Describe("Running e2e tests when build tools locally", func() { + allTestsCases := analysis.NewTestCase() + + for idx, testCase := range allTestsCases { + if !isDarwin { + horusecConfigFilePathBuildLocally := filepath.Join(tmpDir, horusecConfigName) + RunTestCase(testCase, horusecConfigFilePathBuildLocally, "(build locally)", idx, len(allTestsCases)) -func (A AnalysisTestCase) RunAnalysisTestCase() (*gexec.Session, error) { - flags := map[string]string{ - testutil.StartFlagProjectPath: A.AnalysisFolder, + time.Sleep(2 * time.Second) + } + + horusecConfigFilePathDownloadFromDockerHub := filepath.Join(allTestsCases[idx].Command.Flags[testutil.StartFlagProjectPath], horusecConfigName) + RunTestCase(testCase, horusecConfigFilePathDownloadFromDockerHub, "(download from dockerhub)", idx, len(allTestsCases)) + + time.Sleep(2 * time.Second) + } + }) + + AfterEach(func() { + if err := os.RemoveAll(tmpDir); err != nil { + Fail(fmt.Sprintf("Error on remove tmp folder: %v", err)) + } + }) +}) + +func RunTestCase(testCase *analysis.TestCase, horusecConfigFilePath, runType string, idx, lenTestCase int) { + testCase.Command.Flags[testutil.GlobalFlagConfigFilePath] = horusecConfigFilePath + if isWindows && testCase.RequiredDocker { + logger.LogInfo("Tool ignored because is required docker: ", runType, testCase.Tool, fmt.Sprintf("[%v/%v]", idx+1, lenTestCase)) + return } - cmd := testutil.GinkgoGetHorusecCmdWithFlags(testutil.CmdStart, flags) - return gexec.Start(cmd, GinkgoWriter, GinkgoWriter) -} + logger.LogInfo("Preparing test for run e2e: ", runType, testCase.Tool, fmt.Sprintf("[%v/%v]", idx+1, lenTestCase)) + session, err := testCase.RunAnalysisTestCase() + if err != nil { + Fail(fmt.Sprintf("Error on run analysis Test Case %s: %v", runType, err)) + } + session.Wait(testutil.AverageTimeoutAnalyzeForExamplesFolder) + testCase.Command.Output = string(session.Out.Contents()) + testCase.Command.ExitCode = session.ExitCode() -var testcases = []AnalysisTestCase{ - { - Language: languages.Python, - AnalysisFolder: testutil.PythonExample1, - ExpectedTools: []tools.Tool{tools.Bandit, tools.BundlerAudit, tools.Trivy}, - }, - { - Language: languages.Ruby, - AnalysisFolder: testutil.RubyExample1, - ExpectedTools: []tools.Tool{tools.Brakeman, tools.BundlerAudit, tools.Trivy}, - }, - { - Language: languages.Javascript, - AnalysisFolder: testutil.JavaScriptExample1, - ExpectedTools: []tools.Tool{tools.NpmAudit, tools.YarnAudit, tools.HorusecEngine, tools.Semgrep, tools.Trivy}, - }, - { - Language: languages.Go, - AnalysisFolder: testutil.GoExample1, - ExpectedTools: []tools.Tool{tools.GoSec, tools.Semgrep, tools.Nancy, tools.Trivy}, - }, - { - Language: languages.CSharp, - AnalysisFolder: testutil.CsharpExample1, - ExpectedTools: []tools.Tool{tools.SecurityCodeScan, tools.HorusecEngine, tools.DotnetCli, tools.Trivy}, - }, - { - Language: languages.Java, - AnalysisFolder: testutil.JavaExample1, - ExpectedTools: []tools.Tool{tools.HorusecEngine, tools.Semgrep, tools.Trivy}, - }, - { - Language: languages.Kotlin, - AnalysisFolder: testutil.KotlinExample1, - ExpectedTools: []tools.Tool{tools.HorusecEngine}, - }, - { - Language: languages.Leaks, - AnalysisFolder: testutil.LeaksExample1, - ExpectedTools: []tools.Tool{tools.GitLeaks, tools.HorusecEngine}, - }, - { - Language: languages.PHP, - AnalysisFolder: testutil.PHPExample1, - ExpectedTools: []tools.Tool{tools.Semgrep, tools.PhpCS, tools.Trivy}, - }, - { - Language: languages.Dart, - AnalysisFolder: testutil.DartExample1, - ExpectedTools: []tools.Tool{tools.HorusecEngine}, - }, - { - Language: languages.Elixir, - AnalysisFolder: testutil.ElixirExample1, - ExpectedTools: []tools.Tool{tools.MixAudit, tools.Sobelow}, - }, - { - Language: languages.Nginx, - AnalysisFolder: testutil.NginxExample1, - ExpectedTools: []tools.Tool{tools.HorusecEngine}, - }, - { - Language: languages.Swift, - AnalysisFolder: testutil.SwiftExample1, - ExpectedTools: []tools.Tool{tools.HorusecEngine}, - }, + It(fmt.Sprintf("Execute command without error for %s: %s", runType, testCase.Tool), func() { + Expect(testCase.Command.ExitCode).Should(Equal(0)) + }) + + It(fmt.Sprintf("Validate is outputs expected exists on tool %s: %s", runType, testCase.Tool), func() { + for _, outputExpected := range testCase.Expected.OutputsContains { + Expect(testCase.Command.Output).Should( + ContainSubstring(outputExpected), + fmt.Sprintf("The output [%s] not exist in output", outputExpected), + testCase.Command.Output, + ) + } + }) + + It(fmt.Sprintf("Validate is outputs not expected exists on tool %s: %s", runType, testCase.Tool), func() { + for _, outputNotExpected := range testCase.Expected.OutputsNotContains { + Expect(testCase.Command.Output).ShouldNot( + ContainSubstring(outputNotExpected), + fmt.Sprintf("The output [%s] exist in output", outputNotExpected), + testCase.Command.Output, + ) + } + }) } -var _ = Describe("Run a complete horusec analysis", func() { - var ( - session *gexec.Session - ) - - for _, tt := range testcases { - Describe(fmt.Sprintf("Running on %s codebase.", tt.Language.ToString()), func() { - session, _ = tt.RunAnalysisTestCase() - session.Wait(testutil.AverageTimeoutAnalyzeForExamplesFolder) - - It("execute command without error", func() { - Expect(session.ExitCode()).To(Equal(0)) - }) - - It("vulnerabilities were found", func() { - Expect(session.Out.Contents()).To(ContainSubstring("{HORUSEC_CLI} Vulnerability Hash expected to be FIXED")) - Expect(session.Out.Contents()).To(ContainSubstring("VULNERABILITIES WERE FOUND IN YOUR CODE")) - }) - - It("running all expected tools", func() { - for _, tool := range tt.ExpectedTools { - Expect(session.Out.Contents()).To(ContainSubstring(fmt.Sprintf("{HORUSEC_CLI} Running %s", tool.ToString()))) - } - }) - }) +func CreateHorusecConfigAndReturnTMPDirectory() string { + tmpDir := filepath.Join(os.TempDir(), "horusec-analysis-e2e-"+uuid.NewString()) + horusecConfigPath := filepath.Join(tmpDir, horusecConfigName) + + if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil { + Fail(fmt.Sprintf("Error on create tmp folder: %v", err)) } -}) + + horusecConfigFile, err := os.Create(horusecConfigPath) + if err != nil { + Fail(fmt.Sprintf("Error on create config file for scan on e2e test %v", err)) + } + + horusecConfig := config.New() + + newCustomImages := customimages.Default() + for k := range newCustomImages { + if k == languages.CSharp { + newCustomImages[k] = strings.ToLower("local-csharp:local") + } else { + newCustomImages[k] = strings.ToLower(fmt.Sprintf("local-%s:local", k)) + } + } + + horusecConfig.CustomImages = newCustomImages + horusecConfigBytes, err := json.MarshalIndent(horusecConfig.ToMapLowerCase(), "", " ") + if err != nil { + Fail(fmt.Sprintf("Error on marshall horusec-config.json %v", err)) + } + + _, err = horusecConfigFile.Write(horusecConfigBytes) + if err != nil { + Fail(fmt.Sprintf("Error on write config file for scan on e2e test %v", err)) + } + return tmpDir +} diff --git a/e2e/analysis/test_case.go b/e2e/analysis/test_case.go new file mode 100644 index 000000000..14025b4d7 --- /dev/null +++ b/e2e/analysis/test_case.go @@ -0,0 +1,673 @@ +// Copyright 2021 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 analysis + +import ( + "fmt" + "runtime" + + "github.com/ZupIT/horusec-devkit/pkg/enums/analysis" + "github.com/ZupIT/horusec/internal/helpers/messages" + + "github.com/onsi/gomega/gexec" + + "github.com/ZupIT/horusec-devkit/pkg/enums/languages" + "github.com/ZupIT/horusec-devkit/pkg/enums/tools" + "github.com/ZupIT/horusec/internal/utils/testutil" + + . "github.com/onsi/ginkgo" +) + +// Expected struct represents the validations that will be expected when comparing the final results of the analysis +type Expected struct { + Language languages.Language + OutputsContains []string + OutputsNotContains []string + ExitCode int +} + +// Command struct represents all content for run command and your result who: output and exit code +type Command struct { + Flags map[string]string + Output string + ExitCode int +} + +// TestCase struct represents group of content for validate the test e2e of the tool and if is necessary docker for run this tool or not +type TestCase struct { + Tool tools.Tool + RequiredDocker bool + Command Command + Expected Expected +} + +func (tc TestCase) RunAnalysisTestCase() (*gexec.Session, error) { + isWindows := runtime.GOOS == "windows" + if isWindows || !tc.RequiredDocker { + tc.Command.Flags[testutil.StartFlagDisableDocker] = "true" + } + cmd := testutil.GinkgoGetHorusecCmdWithFlags(testutil.CmdStart, tc.Command.Flags) + return gexec.Start(cmd, GinkgoWriter, GinkgoWriter) +} + +func NewTestCase() []*TestCase { + return []*TestCase{ + { + Tool: tools.HorusecEngine, + RequiredDocker: false, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.ExamplesPath, + }, + }, + Expected: Expected{ + Language: languages.Generic, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + "In this analysis, a total of 66 possible vulnerabilities were found and we classified them into:", + "Total of Vulnerability CRITICAL is: 17", + "Total of Vulnerability HIGH is: 22", + "Total of Vulnerability MEDIUM is: 24", + "Total of Vulnerability LOW is: 3", + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.CSharp), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Dart), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Java), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Javascript), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Kotlin), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Nginx), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Swift), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Yaml), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.GoSec), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.SecurityCodeScan), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Brakeman), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Safety), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Bandit), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.NpmAudit), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.YarnAudit), + // TODO: This log show only if pass --enable-git-history, we can see if this tool was runned or not without this flag + //fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.GitLeaks), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.TfSec), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Checkov), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Semgrep), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Flawfinder), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.PhpCS), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.MixAudit), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Sobelow), + // TODO: This log show only if pass --enable-shellcheck, we can see if this tool was runned or not without this flag + //fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.ShellCheck), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.BundlerAudit), + // TODO: This log show only if pass --enable-owasp-dependency-check, we can see if this tool was runned or not without this flag + //fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.OwaspDependencyCheck), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.DotnetCli), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Nancy), + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.Trivy), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} The tool was ignored for run in this analysis: %s", tools.HorusecEngine), + }, + }, + }, + { + Tool: tools.Bandit, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.PythonExample2, + }, + }, + Expected: Expected{ + Language: languages.Python, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Bandit, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Bandit, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Safety, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Safety, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Bandit), + }, + }, + }, + { + Tool: tools.Safety, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.PythonExample2, + }, + }, + Expected: Expected{ + Language: languages.Python, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Bandit, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Bandit, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Safety, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Safety, languages.Python), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Safety), + }, + }, + }, + { + Tool: tools.GoSec, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.GoExample1, + }, + }, + Expected: Expected{ + Language: languages.Go, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.GoSec, languages.Go), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.GoSec, languages.Go), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.GoSec), + }, + }, + }, + { + Tool: tools.SecurityCodeScan, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.CsharpExample1, + }, + }, + Expected: Expected{ + Language: languages.CSharp, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.SecurityCodeScan, languages.CSharp), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.SecurityCodeScan, languages.CSharp), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.SecurityCodeScan), + }, + }, + }, + { + Tool: tools.NpmAudit, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.JavaScriptExample1, + }, + }, + Expected: Expected{ + Language: languages.Javascript, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.NpmAudit, languages.Javascript), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.NpmAudit, languages.Javascript), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.NpmAudit), + }, + }, + }, + { + Tool: tools.YarnAudit, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.JavaScriptExample2, + }, + }, + Expected: Expected{ + Language: languages.Javascript, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.YarnAudit, languages.Javascript), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.YarnAudit, languages.Javascript), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.YarnAudit), + }, + }, + }, + { + Tool: tools.TfSec, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.Hclxample1, + }, + }, + Expected: Expected{ + Language: languages.HCL, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.TfSec, languages.HCL), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.TfSec, languages.HCL), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.TfSec), + }, + }, + }, + { + Tool: tools.Checkov, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.Hclxample1, + }, + }, + Expected: Expected{ + Language: languages.HCL, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Checkov, languages.HCL), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Checkov, languages.HCL), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Checkov), + }, + }, + }, + { + Tool: tools.Flawfinder, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.CExample1, + }, + }, + Expected: Expected{ + Language: languages.C, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Flawfinder, languages.C), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Flawfinder, languages.C), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Flawfinder), + }, + }, + }, + { + Tool: tools.PhpCS, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.PHPExample1, + }, + }, + Expected: Expected{ + Language: languages.PHP, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.PhpCS, languages.PHP), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.PhpCS, languages.PHP), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.PhpCS), + }, + }, + }, + { + Tool: tools.MixAudit, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.ElixirExample1, + }, + }, + Expected: Expected{ + Language: languages.Elixir, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.MixAudit, languages.Elixir), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.MixAudit, languages.Elixir), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.MixAudit), + }, + }, + }, + { + Tool: tools.Sobelow, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.ElixirExample1, + }, + }, + Expected: Expected{ + Language: languages.Elixir, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Sobelow, languages.Elixir), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Sobelow, languages.Elixir), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Sobelow), + }, + }, + }, + { + Tool: tools.Brakeman, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.RubyExample1, + testutil.StartFlagIgnore: "**/*.js, **/*.html, **/*.py, **/*.ts", + }, + }, + Expected: Expected{ + Language: languages.Ruby, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Brakeman, languages.Ruby), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Brakeman, languages.Ruby), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Brakeman), + }, + }, + }, + { + Tool: tools.BundlerAudit, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.RubyExample1, + testutil.StartFlagIgnore: "**/*.js, **/*.html, **/*.py, **/*.ts", + }, + }, + Expected: Expected{ + Language: languages.Ruby, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.BundlerAudit, languages.Ruby), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.BundlerAudit, languages.Ruby), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.BundlerAudit), + }, + }, + }, + { + Tool: tools.DotnetCli, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.CsharpExample1, + }, + }, + Expected: Expected{ + Language: languages.CSharp, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.DotnetCli, languages.CSharp), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.DotnetCli, languages.CSharp), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.DotnetCli), + }, + }, + }, + { + Tool: tools.Nancy, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.GoExample1, + }, + }, + Expected: Expected{ + Language: languages.Go, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Nancy, languages.Go), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Nancy, languages.Go), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Nancy), + }, + }, + }, + { + Tool: tools.ShellCheck, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.LeaksExample1, + testutil.StartFlagEnableShellcheck: "true", + }, + }, + Expected: Expected{ + Language: languages.Shell, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.ShellCheck, languages.Shell), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.ShellCheck, languages.Shell), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.ShellCheck), + }, + }, + }, + { + Tool: tools.Semgrep, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.GoExample1, + }, + }, + Expected: Expected{ + Language: languages.Generic, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Semgrep, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Semgrep), + }, + }, + }, + { + Tool: tools.Trivy, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.LeaksExample1, + }, + }, + Expected: Expected{ + Language: languages.Generic, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.Trivy, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.Trivy), + }, + }, + }, + { + Tool: tools.OwaspDependencyCheck, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.JavaScriptExample1, + testutil.StartFlagEnableOwaspDependencyCheck: "true", + testutil.StartFlagAnalysisTimeout: "10000", + }, + }, + Expected: Expected{ + Language: languages.Generic, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.OwaspDependencyCheck, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.OwaspDependencyCheck, languages.Generic), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.OwaspDependencyCheck), + }, + }, + }, + { + Tool: tools.GitLeaks, + RequiredDocker: true, + Command: Command{ + Flags: map[string]string{ + testutil.StartFlagProjectPath: testutil.ExamplesPath, + testutil.StartFlagEnableGitHistory: "true", + testutil.StartFlagEnableCommitAuthor: "true", + testutil.StartFlagAnalysisTimeout: "10000", + testutil.StartFlagIgnore: "**/ruby/**, **/javascript/**, **/python/**, **/go/**", + }, + }, + Expected: Expected{ + Language: languages.Generic, + ExitCode: 0, + OutputsContains: []string{ + fmt.Sprintf(messages.MsgPrintFinishAnalysisWithStatus, analysis.Success), + messages.MsgDebugVulnHashToFix, + messages.MsgWarnAnalysisFoundVulns[16:], + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.GitLeaks, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.GitLeaks, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks), + fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks), + }, + OutputsNotContains: []string{ + fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.GitLeaks), + }, + }, + }, + } +} diff --git a/examples b/examples index b41bc3111..4426ce365 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit b41bc3111b3040e75e796fd33c663caf6c409f6d +Subproject commit 4426ce36543789eea56e14207a84bd780e602f62 diff --git a/internal/controllers/language_detect/language_detect.go b/internal/controllers/language_detect/language_detect.go index 5e3584dad..1d12b84ca 100644 --- a/internal/controllers/language_detect/language_detect.go +++ b/internal/controllers/language_detect/language_detect.go @@ -15,6 +15,7 @@ package languagedetect import ( + "errors" "fmt" "os" "path/filepath" @@ -33,6 +34,8 @@ import ( "github.com/ZupIT/horusec/internal/utils/copy" ) +const prefixGitSubModule = "gitdir: " + type LanguageDetect struct { configs *config.Config analysisID uuid.UUID @@ -163,19 +166,20 @@ func (ld *LanguageDetect) checkFileExtensionInvalid(path string) bool { return false } +// nolint:funlen // method is not necessary broken func (ld *LanguageDetect) copyProjectToHorusecFolder(directory string) error { folderDstName := filepath.Join(directory, ".horusec", ld.analysisID.String()) err := copy.Copy(directory, folderDstName, ld.filesAndFoldersToIgnore) if err != nil { logger.LogErrorWithLevel(messages.MsgErrorCopyProjectToHorusecAnalysis, err) - } else { - fmt.Print("\n") - logger.LogWarnWithLevel(fmt.Sprintf(messages.MsgWarnMonitorTimeoutIn, ld.configs.TimeoutInSecondsAnalysis)) - fmt.Print("\n") - logger.LogWarnWithLevel(messages.MsgWarnDontRemoveHorusecFolder, folderDstName) - fmt.Print("\n") + return err } - return err + fmt.Print("\n") + logger.LogWarnWithLevel(fmt.Sprintf(messages.MsgWarnMonitorTimeoutIn, ld.configs.TimeoutInSecondsAnalysis)) + fmt.Print("\n") + logger.LogWarnWithLevel(messages.MsgWarnDontRemoveHorusecFolder, folderDstName) + fmt.Print("\n") + return ld.copyGitFolderWhenIsSubmodule(directory, folderDstName) } func (ld *LanguageDetect) filterSupportedLanguages(langs []string) (onlySupportedLangs []languages.Language) { @@ -235,3 +239,73 @@ func (ld *LanguageDetect) isBatFileOrShellFile(lang string) bool { return strings.EqualFold(lang, "Batchfile") || strings.EqualFold(lang, "Shell") } + +// copyGitFolderWhenIsSubmodule check if the analysis is running with GitHistory enabled, +// If so, we also check whether the .git is a submodule or not, +// so we can find where the original git folder is +// and replace it inside .horusec to run the gitleaks tool without any problems. +//nolint:funlen +func (ld *LanguageDetect) copyGitFolderWhenIsSubmodule(directory, folderDstName string) error { + if ld.configs.EnableGitHistoryAnalysis { + isGitSubmodule, originalFolderPath := ld.returnGitFolderOriginalIfIsSubmodule(filepath.Join(directory, ".git")) + if isGitSubmodule { + logger.LogErrorWithLevel( + messages.MsgErrorCopyProjectToHorusecAnalysis, + os.RemoveAll(filepath.Join(folderDstName, ".git")), + ) + + err := copy.Copy( + filepath.Join(directory, originalFolderPath), + filepath.Join(folderDstName, ".git"), + func(src string) bool { return false }, + ) + if err != nil { + logger.LogErrorWithLevel(messages.MsgErrorCopyProjectToHorusecAnalysis, err) + return err + } + } + } + return nil +} + +//nolint:funlen // lines is not necessary broken +func (ld *LanguageDetect) returnGitFolderOriginalIfIsSubmodule(directory string) (bool, string) { + fileInfo, err := os.Stat(directory) + if err != nil { + logger.LogError(messages.MsgErrorCopyProjectToHorusecAnalysis, err) + return false, "" + } + if fileInfo.IsDir() { + return false, "" + } + fileContentBytes, err := os.ReadFile(directory) + if err != nil { + logger.LogError(messages.MsgErrorCopyProjectToHorusecAnalysis, err) + return false, "" + } + return ld.validateSubModuleContent(fileContentBytes) +} + +func (ld *LanguageDetect) validateSubModuleContent(fileContentBytes []byte) (bool, string) { + var fileContent string + if fileContentBytes != nil { + fileContent = string(fileContentBytes) + } + if !strings.HasPrefix(fileContent, prefixGitSubModule) { + logger.LogErrorWithLevel(messages.MsgErrorCopyProjectToHorusecAnalysis, + errors.New("file content wrong: "+fileContent)) + return false, "" + } + + return true, ld.extractGitSubmoduleCorrectlyPath(fileContent) +} + +// extractGitSubmoduleCorrectlyPath contains the logic for get correctly path +// from content of the symbolic link in git submodules. +// Its value is expected to be something like this "gitdir: ../.git/modules/examples". +// Then is prefix is removed and path returned for join with project path +func (ld *LanguageDetect) extractGitSubmoduleCorrectlyPath(fileContent string) string { + prefix := len(prefixGitSubModule) + suffix := len(fileContent) - 1 + return fileContent[prefix:suffix] +} diff --git a/internal/controllers/language_detect/language_detect_test.go b/internal/controllers/language_detect/language_detect_test.go index 87522d0b7..c4ef1ae5b 100644 --- a/internal/controllers/language_detect/language_detect_test.go +++ b/internal/controllers/language_detect/language_detect_test.go @@ -286,4 +286,16 @@ func TestNewLanguageDetect(t *testing.T) { } }) }) + t.Run("Should read git submodule path and copy to .horusec folder git submodule correctly", func(t *testing.T) { + analysisID := uuid.New() + configs := config.New() + configs.EnableGitHistoryAnalysis = true + controller := NewLanguageDetect(configs, analysisID) + _, err := controller.Detect(testutil.ExamplesPath) + assert.NoError(t, err) + projectClonedPath := filepath.Join(testutil.ExamplesPath, ".horusec", analysisID.String()) + fileInfo, err := os.Stat(filepath.Join(projectClonedPath, ".git")) + assert.NoError(t, err) + assert.True(t, fileInfo.IsDir()) + }) } diff --git a/internal/controllers/printresults/print_results.go b/internal/controllers/printresults/print_results.go index 613644815..abd77b407 100644 --- a/internal/controllers/printresults/print_results.go +++ b/internal/controllers/printresults/print_results.go @@ -108,7 +108,7 @@ func (pr *PrintResults) printResultsText() error { fmt.Fprint(pr.writer, "\n") pr.logSeparator(true) - pr.printlnf(`HORUSEC ENDED THE ANALYSIS WITH STATUS OF %q AND WITH THE FOLLOWING RESULTS:`, pr.analysis.Status) + pr.printlnf(messages.MsgPrintFinishAnalysisWithStatus, pr.analysis.Status) pr.logSeparator(true) diff --git a/internal/helpers/messages/print.go b/internal/helpers/messages/print.go new file mode 100644 index 000000000..1fbc02b3f --- /dev/null +++ b/internal/helpers/messages/print.go @@ -0,0 +1,19 @@ +// Copyright 2021 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 messages + +const ( + MsgPrintFinishAnalysisWithStatus = `HORUSEC ENDED THE ANALYSIS WITH STATUS OF %q AND WITH THE FOLLOWING RESULTS:` +) diff --git a/internal/services/docker/docker_api.go b/internal/services/docker/docker_api.go index f463b86c1..6ce0bb06c 100644 --- a/internal/services/docker/docker_api.go +++ b/internal/services/docker/docker_api.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "os" "strconv" "strings" "sync" @@ -277,6 +278,7 @@ func (d *API) getContainerConfig(imageNameWithTag, cmd string) *container.Config Image: imageNameWithTag, Tty: true, Cmd: []string{"/bin/sh", "-c", fmt.Sprintf(`cd %s && %s`, d.pathDestinyInContainer, cmd)}, + Env: []string{fmt.Sprintf("GITHUB_TOKEN=%s", os.Getenv("GITHUB_TOKEN"))}, } } diff --git a/internal/services/formatters/c/deployments/Dockerfile b/internal/services/formatters/c/deployments/Dockerfile index a86517efc..041281d51 100644 --- a/internal/services/formatters/c/deployments/Dockerfile +++ b/internal/services/formatters/c/deployments/Dockerfile @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM python:3.10.0-alpine +FROM python:3.10.0-alpine3.14 RUN pip install flawfinder==2.0.19 diff --git a/internal/services/formatters/c/flawfinder/formatter.go b/internal/services/formatters/c/flawfinder/formatter.go index 4e51a0565..aa0b6e74d 100644 --- a/internal/services/formatters/c/flawfinder/formatter.go +++ b/internal/services/formatters/c/flawfinder/formatter.go @@ -45,19 +45,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startFlawfinder(projectSubPath), tools.Flawfinder, projectSubPath) + output, err := f.startFlawfinder(projectSubPath) + f.SetAnalysisError(err, tools.Flawfinder, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Flawfinder, languages.C) } -func (f *Formatter) startFlawfinder(projectSubPath string) error { +func (f *Formatter) startFlawfinder(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Flawfinder, languages.C) output, err := f.ExecuteContainer(f.getConfigData(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/csharp/dotnet_cli/formatter.go b/internal/services/formatters/csharp/dotnet_cli/formatter.go index 6286ca996..4988a9fed 100644 --- a/internal/services/formatters/csharp/dotnet_cli/formatter.go +++ b/internal/services/formatters/csharp/dotnet_cli/formatter.go @@ -50,20 +50,21 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startDotnetCli(projectSubPath), tools.DotnetCli, projectSubPath) + output, err := f.startDotnetCli(projectSubPath) + f.SetAnalysisError(err, tools.DotnetCli, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.DotnetCli, languages.CSharp) } -func (f *Formatter) startDotnetCli(projectSubPath string) error { +func (f *Formatter) startDotnetCli(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.DotnetCli, languages.CSharp) output, err := f.checkOutputErrors(f.ExecuteContainer(f.getConfigData(projectSubPath))) if err != nil { - return err + return output, err } f.parseOutput(output, projectSubPath) - return nil + return output, nil } func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/csharp/scs/formatter.go b/internal/services/formatters/csharp/scs/formatter.go index bb5c143c7..ecdcadc79 100644 --- a/internal/services/formatters/csharp/scs/formatter.go +++ b/internal/services/formatters/csharp/scs/formatter.go @@ -54,24 +54,30 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startSecurityCodeScan(projectSubPath), tools.SecurityCodeScan, projectSubPath) + output, err := f.startSecurityCodeScan(projectSubPath) + f.SetAnalysisError(err, tools.SecurityCodeScan, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.SecurityCodeScan, languages.CSharp) } -func (f *Formatter) startSecurityCodeScan(projectSubPath string) error { +//nolint:funlen +func (f *Formatter) startSecurityCodeScan(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.SecurityCodeScan, languages.CSharp) analysisData := f.getDockerConfig(projectSubPath) if err := f.verifyIsSolutionError(analysisData.CMD); err != nil { - return err + return analysisData.CMD, err } - output, err := f.CheckOutputErrors(f.ExecuteContainer(analysisData)) + outputContainer, err := f.ExecuteContainer(analysisData) if err != nil { - return err + return "", err + } + output, err := f.CheckOutputErrors(outputContainer, err) + if err != nil { + return outputContainer, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) parseOutput(output string) error { diff --git a/internal/services/formatters/default_engine_formatter.go b/internal/services/formatters/default_engine_formatter.go index 997e13aa9..86e348dd1 100644 --- a/internal/services/formatters/default_engine_formatter.go +++ b/internal/services/formatters/default_engine_formatter.go @@ -48,7 +48,7 @@ func (f *DefaultFormatter) StartAnalysis(src string) { logger.LogDebugWithLevel(messages.MsgDebugToolIgnored + tools.HorusecEngine.ToString()) return } - f.svc.SetAnalysisError(f.execEngineAndParseResults(src), tools.HorusecEngine, src) + f.svc.SetAnalysisError(f.execEngineAndParseResults(src), tools.HorusecEngine, "", src) f.svc.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.HorusecEngine, f.language) } diff --git a/internal/services/formatters/elixir/mixaudit/formatter.go b/internal/services/formatters/elixir/mixaudit/formatter.go index 3c19861ed..b8dfef042 100644 --- a/internal/services/formatters/elixir/mixaudit/formatter.go +++ b/internal/services/formatters/elixir/mixaudit/formatter.go @@ -48,19 +48,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startMixAudit(projectSubPath), tools.MixAudit, projectSubPath) + output, err := f.startMixAudit(projectSubPath) + f.SetAnalysisError(err, tools.MixAudit, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.MixAudit, languages.Elixir) } -func (f *Formatter) startMixAudit(projectSubPath string) error { +func (f *Formatter) startMixAudit(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.MixAudit, languages.Elixir) output, err := f.ExecuteContainer(f.getConfigData(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/elixir/sobelow/formatter.go b/internal/services/formatters/elixir/sobelow/formatter.go index 9f86e1b56..5963ed6a4 100644 --- a/internal/services/formatters/elixir/sobelow/formatter.go +++ b/internal/services/formatters/elixir/sobelow/formatter.go @@ -53,23 +53,25 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startSobelow(projectSubPath), tools.Sobelow, projectSubPath) + output, err := f.startSobelow(projectSubPath) + f.SetAnalysisError(err, tools.Sobelow, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Sobelow, languages.Elixir) } -func (f *Formatter) startSobelow(projectSubPath string) error { +func (f *Formatter) startSobelow(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Sobelow, languages.Elixir) output, err := f.ExecuteContainer(f.getConfigData(projectSubPath)) if err != nil { - return err + return output, err } if strings.Contains(output, NotAPhoenixApplication) { - return ErrorNotAPhoenixApplication + return output, ErrorNotAPhoenixApplication } - return f.parseOutput(output, projectSubPath) + f.parseOutput(output, projectSubPath) + return output, nil } func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData { @@ -81,7 +83,7 @@ func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.Analysi return analysisData.SetData(f.GetCustomImageByLanguage(languages.Elixir), images.Elixir) } -func (f *Formatter) parseOutput(output, projectSubPath string) error { +func (f *Formatter) parseOutput(output, projectSubPath string) { const replaceDefaultMessage = "Checking Sobelow version..." output = strings.ReplaceAll(strings.ReplaceAll(output, replaceDefaultMessage, ""), "\r", "") @@ -94,8 +96,6 @@ func (f *Formatter) parseOutput(output, projectSubPath string) error { f.AddNewVulnerabilityIntoAnalysis(f.setVulnerabilityData(data, projectSubPath)) } } - - return nil } func (f *Formatter) setOutputData(output string) *entities.Output { diff --git a/internal/services/formatters/generic/dependency_check/formatter.go b/internal/services/formatters/generic/dependency_check/formatter.go index 381db8ad3..b7886790a 100644 --- a/internal/services/formatters/generic/dependency_check/formatter.go +++ b/internal/services/formatters/generic/dependency_check/formatter.go @@ -47,19 +47,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startDependencyCheck(projectSubPath), tools.OwaspDependencyCheck, projectSubPath) + output, err := f.startDependencyCheck(projectSubPath) + f.SetAnalysisError(err, tools.OwaspDependencyCheck, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.OwaspDependencyCheck, languages.Generic) } -func (f *Formatter) startDependencyCheck(projectSubPath string) error { +func (f *Formatter) startDependencyCheck(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.OwaspDependencyCheck, languages.Generic) output, err := f.ExecuteContainer(f.getConfigData(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getConfigData(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/generic/deployments/Dockerfile b/internal/services/formatters/generic/deployments/Dockerfile index 861be911c..1f9c8fe37 100644 --- a/internal/services/formatters/generic/deployments/Dockerfile +++ b/internal/services/formatters/generic/deployments/Dockerfile @@ -19,7 +19,7 @@ RUN "$JAVA_HOME/bin/jlink" --compress=2 \ --add-modules java.base,java.compiler,java.datatransfer,jdk.crypto.ec,java.desktop,java.instrument,java.logging,java.management,java.naming,java.rmi,java.scripting,java.security.sasl,java.sql,java.transaction.xa,java.xml,jdk.unsupported \ --output /jlinked -FROM python:3.10.0-alpine +FROM python:3.10.0-alpine3.14 RUN pip install semgrep==v0.63.0 diff --git a/internal/services/formatters/generic/semgrep/formatter.go b/internal/services/formatters/generic/semgrep/formatter.go index 02273ba09..5dbbb518e 100644 --- a/internal/services/formatters/generic/semgrep/formatter.go +++ b/internal/services/formatters/generic/semgrep/formatter.go @@ -50,19 +50,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startSemgrep(projectSubPath), tools.SecurityCodeScan, projectSubPath) + output, err := f.startSemgrep(projectSubPath) + f.SetAnalysisError(err, tools.SecurityCodeScan, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Semgrep, languages.Generic) } -func (f *Formatter) startSemgrep(projectSubPath string) error { +func (f *Formatter) startSemgrep(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Semgrep, languages.Generic) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/generic/trivy/config.go b/internal/services/formatters/generic/trivy/config.go index a14b5eb90..7d71064a1 100644 --- a/internal/services/formatters/generic/trivy/config.go +++ b/internal/services/formatters/generic/trivy/config.go @@ -14,19 +14,13 @@ package trivy -type Cmd string - -func (c Cmd) ToString() string { - return string(c) -} - -const CmdFs Cmd = ` +const CmdFs = ` {{WORK_DIR}} TRIVY_NEW_JSON_SCHEMA=true trivy fs -f json -o resultFs.json ./ &> /dev/null cat resultFs.json ` -const CmdConfig Cmd = ` +const CmdConfig = ` {{WORK_DIR}} TRIVY_NEW_JSON_SCHEMA=true trivy config -f json -o resultConfig.json ./ &> /dev/null cat resultConfig.json diff --git a/internal/services/formatters/generic/trivy/formatter.go b/internal/services/formatters/generic/trivy/formatter.go index f2df5443a..899203d5a 100644 --- a/internal/services/formatters/generic/trivy/formatter.go +++ b/internal/services/formatters/generic/trivy/formatter.go @@ -61,16 +61,17 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startTrivy(projectSubPath), tools.Trivy, projectSubPath) - f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Trivy, images.Generic) + output, err := f.startTrivy(projectSubPath) + f.SetAnalysisError(err, tools.Trivy, output, projectSubPath) + f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Trivy, languages.Generic) } -func (f *Formatter) startTrivy(projectSubPath string) error { - f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Trivy, images.Generic) +func (f *Formatter) startTrivy(projectSubPath string) (string, error) { + f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Trivy, languages.Generic) configOutput, fileSystemOutput, err := f.executeContainers(projectSubPath) if err != nil { - return err + return "", err } return f.parse(projectSubPath, configOutput, fileSystemOutput) @@ -116,24 +117,24 @@ func (f *Formatter) executeContainers(projectSubPath string) (string, string, er return result.config, result.fs, result.err } -func (f *Formatter) parse(projectSubPath, configOutput, fileSystemOutput string) error { +func (f *Formatter) parse(projectSubPath, configOutput, fileSystemOutput string) (string, error) { if err := f.parseOutput(configOutput, CmdConfig, projectSubPath); err != nil { - return err + return configOutput, err } - return f.parseOutput(fileSystemOutput, CmdFs, projectSubPath) + return fileSystemOutput, f.parseOutput(fileSystemOutput, CmdFs, projectSubPath) } -func (f *Formatter) getDockerConfig(cmd Cmd, projectSubPath string) *dockerEntities.AnalysisData { +func (f *Formatter) getDockerConfig(cmd, projectSubPath string) *dockerEntities.AnalysisData { analysisData := &dockerEntities.AnalysisData{ - CMD: f.AddWorkDirInCmd(cmd.ToString(), projectSubPath, tools.Trivy), + CMD: f.AddWorkDirInCmd(cmd, projectSubPath, tools.Trivy), Language: languages.Generic, } return analysisData.SetData(f.GetCustomImageByLanguage(languages.Generic), images.Generic) } -func (f *Formatter) parseOutput(output string, cmd Cmd, projectSubPath string) error { +func (f *Formatter) parseOutput(output, cmd, projectSubPath string) error { report := &entities.Output{} if output == "" { @@ -151,7 +152,7 @@ func (f *Formatter) parseOutput(output string, cmd Cmd, projectSubPath string) e return nil } -func (f *Formatter) setVulnerabilities(cmd Cmd, result *entities.Result, path string) { +func (f *Formatter) setVulnerabilities(cmd string, result *entities.Result, path string) { switch cmd { case CmdFs: f.setVulnerabilitiesOutput(result.Vulnerabilities, path) diff --git a/internal/services/formatters/go/deployments/Dockerfile b/internal/services/formatters/go/deployments/Dockerfile index f0471a3a9..f2d9ba687 100644 --- a/internal/services/formatters/go/deployments/Dockerfile +++ b/internal/services/formatters/go/deployments/Dockerfile @@ -16,7 +16,7 @@ FROM golang:1.17.3-alpine RUN apk add curl -RUN curl -fsSL https://github.com/sonatype-nexus-community/nancy/releases/download/v1.0.22/nancy-v1.0.22-linux-amd64 -o /bin/nancy +RUN curl -fsSL https://github.com/sonatype-nexus-community/nancy/releases/download/v1.0.28/nancy-v1.0.28-linux-amd64 -o /bin/nancy RUN chmod +x /bin/nancy RUN wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s v2.8.1 diff --git a/internal/services/formatters/go/gosec/formatter.go b/internal/services/formatters/go/gosec/formatter.go index 8d76bd729..5e88da381 100644 --- a/internal/services/formatters/go/gosec/formatter.go +++ b/internal/services/formatters/go/gosec/formatter.go @@ -50,19 +50,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startGoSec(projectSubPath), tools.GoSec, projectSubPath) + output, err := f.startGoSec(projectSubPath) + f.SetAnalysisError(err, tools.GoSec, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.GoSec, languages.Go) } -func (f *Formatter) startGoSec(projectSubPath string) error { +func (f *Formatter) startGoSec(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.GoSec, languages.Go) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.processOutput(output) + return "", f.processOutput(output) } // nolint: funlen diff --git a/internal/services/formatters/go/nancy/formatter.go b/internal/services/formatters/go/nancy/formatter.go index f681b3ca7..1b6a52494 100644 --- a/internal/services/formatters/go/nancy/formatter.go +++ b/internal/services/formatters/go/nancy/formatter.go @@ -51,23 +51,24 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startNancy(projectSubPath), tools.Nancy, projectSubPath) + output, err := f.startNancy(projectSubPath) + f.SetAnalysisError(err, tools.Nancy, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Nancy, languages.Go) } -func (f *Formatter) startNancy(projectSubPath string) error { +func (f *Formatter) startNancy(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Nancy, languages.Go) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } if output == "" { - return nil + return output, nil } - return f.processOutput(output, projectSubPath) + return output, f.processOutput(output, projectSubPath) } func (f *Formatter) processOutput(output, projectSubPath string) error { diff --git a/internal/services/formatters/hcl/checkov/formatter.go b/internal/services/formatters/hcl/checkov/formatter.go index 7f16992d9..a57f9374d 100644 --- a/internal/services/formatters/hcl/checkov/formatter.go +++ b/internal/services/formatters/hcl/checkov/formatter.go @@ -50,19 +50,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startCheckov(projectSubPath), tools.Checkov, projectSubPath) + output, err := f.startCheckov(projectSubPath) + f.SetAnalysisError(err, tools.Checkov, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Checkov, languages.HCL) } -func (f *Formatter) startCheckov(projectSubPath string) error { +func (f *Formatter) startCheckov(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Checkov, languages.HCL) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/hcl/deployments/Dockerfile b/internal/services/formatters/hcl/deployments/Dockerfile index bd5702934..e181e0d4f 100644 --- a/internal/services/formatters/hcl/deployments/Dockerfile +++ b/internal/services/formatters/hcl/deployments/Dockerfile @@ -12,9 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM python:3.10.0-alpine +FROM python:3.10.0-alpine3.14 RUN apk add --quiet --no-cache wget RUN wget -O /usr/bin/tfsec https://github.com/aquasecurity/tfsec/releases/download/v0.55.1/tfsec-linux-amd64 && chmod +x /usr/bin/tfsec -RUN pip3 install --upgrade pip==21.2.4 && pip3 install --upgrade setuptools==57.4.0 && pip3 install checkov==2.0.474 + +# This installation is necessary if we can usage checkov tool +# See more details in: https://github.com/bridgecrewio/checkov/issues/1947 +RUN pip install --upgrade pip==21.3.1 && pip install --upgrade setuptools==59.1.1 +RUN apk add --no-cache --virtual .build_deps build-base libffi-dev \ + && pip install --no-cache-dir -U checkov \ + && apk del .build_deps + + diff --git a/internal/services/formatters/hcl/tfsec/formatter.go b/internal/services/formatters/hcl/tfsec/formatter.go index 656c02a84..e087f9704 100644 --- a/internal/services/formatters/hcl/tfsec/formatter.go +++ b/internal/services/formatters/hcl/tfsec/formatter.go @@ -49,19 +49,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startTfSec(projectSubPath), tools.TfSec, projectSubPath) + output, err := f.startTfSec(projectSubPath) + f.SetAnalysisError(err, tools.TfSec, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.TfSec, languages.HCL) } -func (f *Formatter) startTfSec(projectSubPath string) error { +func (f *Formatter) startTfSec(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.TfSec, languages.HCL) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/interface.go b/internal/services/formatters/interface.go index 92558cb37..e9e23d5bd 100644 --- a/internal/services/formatters/interface.go +++ b/internal/services/formatters/interface.go @@ -59,7 +59,7 @@ type IService interface { GetConfigProjectPath() string // SetAnalysisError add an error from a tool to current analysis. - SetAnalysisError(err error, tool tools.Tool, projectSubPath string) + SetAnalysisError(err error, tool tools.Tool, output, projectSubPath string) // RemoveSrcFolderFromPath remove src prefix from filepath. RemoveSrcFolderFromPath(filepath string) string diff --git a/internal/services/formatters/javascript/npmaudit/formatter.go b/internal/services/formatters/javascript/npmaudit/formatter.go index e4d83bfc8..89e4b4c47 100644 --- a/internal/services/formatters/javascript/npmaudit/formatter.go +++ b/internal/services/formatters/javascript/npmaudit/formatter.go @@ -52,19 +52,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startNpmAudit(projectSubPath), tools.NpmAudit, projectSubPath) + output, err := f.startNpmAudit(projectSubPath) + f.SetAnalysisError(err, tools.NpmAudit, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.NpmAudit, languages.Javascript) } -func (f *Formatter) startNpmAudit(projectSubPath string) error { +func (f *Formatter) startNpmAudit(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.NpmAudit, languages.Javascript) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output, projectSubPath) + return output, f.parseOutput(output, projectSubPath) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { @@ -104,11 +105,7 @@ func (f *Formatter) newContainerOutputFromString(containerOutput string) (output return &entities.Output{}, nil } - if err = json.Unmarshal([]byte(containerOutput), &output); err != nil { - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.NpmAudit, containerOutput), err) - } - - return output, err + return output, json.Unmarshal([]byte(containerOutput), &output) } func (f *Formatter) processOutput(output *entities.Output, projectSubPath string) { diff --git a/internal/services/formatters/javascript/yarnaudit/formatter.go b/internal/services/formatters/javascript/yarnaudit/formatter.go index 9c4232b3f..902f1571b 100644 --- a/internal/services/formatters/javascript/yarnaudit/formatter.go +++ b/internal/services/formatters/javascript/yarnaudit/formatter.go @@ -54,19 +54,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startYarnAudit(projectSubPath), tools.YarnAudit, projectSubPath) + output, err := f.startYarnAudit(projectSubPath) + f.SetAnalysisError(err, tools.YarnAudit, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.YarnAudit, languages.Javascript) } -func (f *Formatter) startYarnAudit(projectSubPath string) error { +func (f *Formatter) startYarnAudit(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.YarnAudit, languages.Javascript) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output, projectSubPath) + return output, f.parseOutput(output, projectSubPath) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { @@ -119,11 +120,7 @@ func (f *Formatter) newContainerOutputFromString(containerOutput string) (output return &entities.Output{}, nil } - if err = json.Unmarshal([]byte(containerOutput), &output); err != nil { - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.YarnAudit, containerOutput), err) - } - - return output, err + return output, json.Unmarshal([]byte(containerOutput), &output) } func (f *Formatter) processOutput(output *entities.Output, projectSubPath string) { diff --git a/internal/services/formatters/leaks/deployments/Dockerfile b/internal/services/formatters/leaks/deployments/Dockerfile index e8382fe9e..9db1027f7 100644 --- a/internal/services/formatters/leaks/deployments/Dockerfile +++ b/internal/services/formatters/leaks/deployments/Dockerfile @@ -17,4 +17,5 @@ FROM zricethezav/gitleaks:v7.6.1 COPY ./internal/services/formatters/leaks/deployments/rules.toml /rules/rules.toml ENTRYPOINT [] + CMD ["/bin/sh"] \ No newline at end of file diff --git a/internal/services/formatters/leaks/gitleaks/config.go b/internal/services/formatters/leaks/gitleaks/config.go index 7e99a7fa6..9b097f650 100644 --- a/internal/services/formatters/leaks/gitleaks/config.go +++ b/internal/services/formatters/leaks/gitleaks/config.go @@ -17,6 +17,9 @@ package gitleaks const CMD = ` {{WORK_DIR}} - gitleaks --config-path /rules/rules.toml --path . --leaks-exit-code 0 --format json --report /tmp/leaks-result.json &> /tmp/leaks-runner-output.txt - cat /tmp/leaks-result.json + if ! gitleaks --config-path /rules/rules.toml --path . --leaks-exit-code 0 --format json --report /tmp/leaks-result.json &> /tmp/leaks-runner-output.txt; then + echo /tmp/leaks-runner-output.txt + else + cat /tmp/leaks-result.json + fi ` diff --git a/internal/services/formatters/leaks/gitleaks/formatter.go b/internal/services/formatters/leaks/gitleaks/formatter.go index 90d579d41..eb36fe66e 100644 --- a/internal/services/formatters/leaks/gitleaks/formatter.go +++ b/internal/services/formatters/leaks/gitleaks/formatter.go @@ -51,19 +51,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startGitLeaks(projectSubPath), tools.GitLeaks, projectSubPath) + output, err := f.startGitLeaks(projectSubPath) + f.SetAnalysisError(err, tools.GitLeaks, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.GitLeaks, languages.Leaks) } -func (f *Formatter) startGitLeaks(projectSubPath string) error { +func (f *Formatter) startGitLeaks(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.GitLeaks, languages.Leaks) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.formatOutputGitLeaks(output) + return output, f.formatOutputGitLeaks(output) } func (f *Formatter) formatOutputGitLeaks(output string) error { @@ -89,7 +90,6 @@ func (f *Formatter) parseOutputToIssues(output string) ([]entities.Issue, error) if err != nil && strings.Contains(err.Error(), "invalid character") { err = errors.New(output) } - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.GitLeaks, output), err) return issues, err } diff --git a/internal/services/formatters/php/phpcs/formatter.go b/internal/services/formatters/php/phpcs/formatter.go index c2ead6151..4cca34a1e 100644 --- a/internal/services/formatters/php/phpcs/formatter.go +++ b/internal/services/formatters/php/phpcs/formatter.go @@ -49,19 +49,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startPhpCs(projectSubPath), tools.PhpCS, projectSubPath) + output, err := f.startPhpCs(projectSubPath) + f.SetAnalysisError(err, tools.PhpCS, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.PhpCS, languages.PHP) } -func (f *Formatter) startPhpCs(projectSubPath string) error { +func (f *Formatter) startPhpCs(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.PhpCS, languages.PHP) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/python/bandit/formatter.go b/internal/services/formatters/python/bandit/formatter.go index 72f77a87a..dfe1ccfa8 100644 --- a/internal/services/formatters/python/bandit/formatter.go +++ b/internal/services/formatters/python/bandit/formatter.go @@ -49,20 +49,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startBandit(projectSubPath), tools.Bandit, projectSubPath) + output, err := f.startBandit(projectSubPath) + f.SetAnalysisError(err, tools.Bandit, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Bandit, languages.Python) } -func (f *Formatter) startBandit(projectSubPath string) error { +func (f *Formatter) startBandit(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Bandit, languages.Python) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - f.parseOutput(output) - return nil + return output, f.parseOutput(output) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { @@ -74,24 +74,24 @@ func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.Analy return analysisData.SetData(f.GetCustomImageByLanguage(languages.Python), images.Python) } -func (f *Formatter) parseOutput(output string) { +func (f *Formatter) parseOutput(output string) error { if output == "" { logger.LogDebugWithLevel(messages.MsgDebugOutputEmpty, map[string]interface{}{"tool": tools.Bandit.ToString()}) - return + return nil } banditOutput, err := f.parseOutputToBanditOutput(output) if err != nil { - return + return err } f.setBanditOutPutInHorusecAnalysis(banditOutput.Results) + return nil } func (f *Formatter) parseOutputToBanditOutput(output string) (banditOutput entities.BanditOutput, err error) { err = json.Unmarshal([]byte(output), &banditOutput) - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.Bandit, output), err) return banditOutput, err } diff --git a/internal/services/formatters/python/deployments/Dockerfile b/internal/services/formatters/python/deployments/Dockerfile index 7f4402993..1fc518b5e 100644 --- a/internal/services/formatters/python/deployments/Dockerfile +++ b/internal/services/formatters/python/deployments/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM python:3.10.0-alpine +FROM python:3.10.0-alpine3.14 RUN apk add jq RUN pip install safety==1.10.3 diff --git a/internal/services/formatters/python/safety/formatter.go b/internal/services/formatters/python/safety/formatter.go index 72764b386..a4fa1fa4d 100644 --- a/internal/services/formatters/python/safety/formatter.go +++ b/internal/services/formatters/python/safety/formatter.go @@ -56,20 +56,18 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startSafety(projectSubPath), tools.Safety, projectSubPath) + output, err := f.startSafety(projectSubPath) + f.SetAnalysisError(err, tools.Safety, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Safety, languages.Python) } -func (f *Formatter) startSafety(projectSubPath string) error { +func (f *Formatter) startSafety(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Safety, languages.Python) - output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - - f.parseOutput(output, projectSubPath) - return nil + return "", f.parseOutput(output, projectSubPath) } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { @@ -82,26 +80,25 @@ func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.Analy return analysisData.SetData(f.GetCustomImageByLanguage(languages.Python), images.Python) } -func (f *Formatter) parseOutput(output, projectSubPath string) { +func (f *Formatter) parseOutput(output, projectSubPath string) error { if output == "" { logger.LogDebugWithLevel(messages.MsgDebugOutputEmpty, map[string]interface{}{"tool": tools.Safety.ToString()}) - return + return nil } if len(output) >= 19 && strings.EqualFold(output[:19], "ERROR_REQ_NOT_FOUND") { - f.SetAnalysisError(errors.New(messages.MsgErrorNotFoundRequirementsTxt), tools.Safety, projectSubPath) - return + return errors.New(messages.MsgErrorNotFoundRequirementsTxt) } safetyOutput, err := f.parseOutputToSafetyOutput(output) if err != nil { - return + return err } f.setSafetyOutPutInHorusecAnalysis(safetyOutput.Issues, projectSubPath) + return nil } func (f *Formatter) parseOutputToSafetyOutput(output string) (safetyOutput entities.SafetyOutput, err error) { err = json.Unmarshal([]byte(output), &safetyOutput) - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.Safety, output), err) return safetyOutput, err } diff --git a/internal/services/formatters/ruby/brakeman/formatter.go b/internal/services/formatters/ruby/brakeman/formatter.go index ccd4a1e01..c7fbc345b 100644 --- a/internal/services/formatters/ruby/brakeman/formatter.go +++ b/internal/services/formatters/ruby/brakeman/formatter.go @@ -49,19 +49,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startBrakeman(projectSubPath), tools.Brakeman, projectSubPath) + output, err := f.startBrakeman(projectSubPath) + f.SetAnalysisError(err, tools.Brakeman, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.Brakeman, languages.Ruby) } -func (f *Formatter) startBrakeman(projectSubPath string) error { +func (f *Formatter) startBrakeman(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.Brakeman, languages.Ruby) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output, projectSubPath) + return output, f.parseOutput(output, projectSubPath) } func (f *Formatter) parseOutput(containerOutput, projectSubPath string) error { @@ -88,7 +89,6 @@ func (f *Formatter) newContainerOutputFromString(containerOutput string) (output } err = json.Unmarshal([]byte(containerOutput), &output) - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.Brakeman, containerOutput), err) return output, err } diff --git a/internal/services/formatters/ruby/bundler/formatter.go b/internal/services/formatters/ruby/bundler/formatter.go index 3765e7e06..d48c8eb46 100644 --- a/internal/services/formatters/ruby/bundler/formatter.go +++ b/internal/services/formatters/ruby/bundler/formatter.go @@ -54,24 +54,24 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startBundlerAudit(projectSubPath), tools.BundlerAudit, projectSubPath) + output, err := f.startBundlerAudit(projectSubPath) + f.SetAnalysisError(err, tools.BundlerAudit, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.BundlerAudit, languages.Ruby) } -func (f *Formatter) startBundlerAudit(projectSubPath string) error { +func (f *Formatter) startBundlerAudit(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.BundlerAudit, languages.Ruby) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } if errGemLock := f.verifyGemLockError(output); errGemLock != nil { - return errGemLock + return output, errGemLock } - f.parseOutput(f.removeOutputEsc(output), projectSubPath) - return nil + return "", nil } func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData { diff --git a/internal/services/formatters/ruby/deployments/Dockerfile b/internal/services/formatters/ruby/deployments/Dockerfile index eddf52cf0..32a9c115f 100644 --- a/internal/services/formatters/ruby/deployments/Dockerfile +++ b/internal/services/formatters/ruby/deployments/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM ruby:3.0.2-alpine +FROM ruby:2.4.10-alpine RUN gem install brakeman -v 5.1.1 RUN gem install bundler-audit -v 0.9.0 diff --git a/internal/services/formatters/service.go b/internal/services/formatters/service.go index 39b0ea5cd..a6f4af1e3 100644 --- a/internal/services/formatters/service.go +++ b/internal/services/formatters/service.go @@ -113,12 +113,12 @@ func (s *Service) GetAnalysisID() string { return s.analysis.GetIDString() } -func (s *Service) SetAnalysisError(err error, tool tools.Tool, projectSubPath string) { +func (s *Service) SetAnalysisError(err error, tool tools.Tool, output, projectSubPath string) { if err != nil { s.mutex.Lock() defer s.mutex.Unlock() s.addAnalysisError(err) - msg := s.GetAnalysisIDErrorMessage(tool, "") + msg := s.GetAnalysisIDErrorMessage(tool, output) if projectSubPath != "" { msg += " | ProjectSubPath -> " + projectSubPath } diff --git a/internal/services/formatters/service_test.go b/internal/services/formatters/service_test.go index 6ba1c8168..28e448fe1 100644 --- a/internal/services/formatters/service_test.go +++ b/internal/services/formatters/service_test.go @@ -128,7 +128,7 @@ func TestMock_AddWorkDirInCmd(t *testing.T) { _ = mock.GetCommitAuthor("", "") _ = mock.AddWorkDirInCmd("", "", "") _ = mock.GetConfigProjectPath() - mock.SetAnalysisError(errors.New(""), "", "") + mock.SetAnalysisError(errors.New(""), "", "", "") _ = mock.RemoveSrcFolderFromPath("") _ = mock.GetCodeWithMaxCharacters("", 0) }) @@ -279,10 +279,10 @@ func TestLogAnalysisError(t *testing.T) { logger.LogSetOutput(stdOutMock) logger.SetLogLevel("debug") assert.NotPanics(t, func() { - monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "") - monitorController.SetAnalysisError(errors.New("test2"), tools.GitLeaks, "") + monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "container err", "") + monitorController.SetAnalysisError(errors.New("test2"), tools.GitLeaks, "container err", "") }) - assert.Contains(t, stdOutMock.String(), `{HORUSEC_CLI} Something error went wrong in GoSec tool | analysisID -> 00000000-0000-0000-0000-000000000000 | output -> `) + assert.Contains(t, stdOutMock.String(), `{HORUSEC_CLI} Something error went wrong in GoSec tool | analysisID -> 00000000-0000-0000-0000-000000000000 | output -> container err`) }) t.Run("should not panic when logging error and exists projectSubPath", func(t *testing.T) { monitorController := NewFormatterService(&analysis.Analysis{}, testutil.NewDockerMock(), &config.Config{}) @@ -290,10 +290,10 @@ func TestLogAnalysisError(t *testing.T) { logger.LogSetOutput(stdOutMock) logger.SetLogLevel("debug") assert.NotPanics(t, func() { - monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "/tmp") - monitorController.SetAnalysisError(errors.New("test2"), tools.GitLeaks, "/tmp") + monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "container err", "/tmp") + monitorController.SetAnalysisError(errors.New("test2"), tools.GitLeaks, "container err", "/tmp") }) - assert.Contains(t, stdOutMock.String(), `{HORUSEC_CLI} Something error went wrong in GoSec tool | analysisID -> 00000000-0000-0000-0000-000000000000 | output -> | ProjectSubPath -> /tmp - test"`) + assert.Contains(t, stdOutMock.String(), `{HORUSEC_CLI} Something error went wrong in GoSec tool | analysisID -> 00000000-0000-0000-0000-000000000000 | output -> container err | ProjectSubPath -> /tmp - test"`) }) } diff --git a/internal/services/formatters/shell/shellcheck/formatter.go b/internal/services/formatters/shell/shellcheck/formatter.go index a8e70f105..aa980ba34 100644 --- a/internal/services/formatters/shell/shellcheck/formatter.go +++ b/internal/services/formatters/shell/shellcheck/formatter.go @@ -51,19 +51,20 @@ func (f *Formatter) StartAnalysis(projectSubPath string) { return } - f.SetAnalysisError(f.startShellCheck(projectSubPath), tools.ShellCheck, projectSubPath) + output, err := f.startShellCheck(projectSubPath) + f.SetAnalysisError(err, tools.ShellCheck, output, projectSubPath) f.LogDebugWithReplace(messages.MsgDebugToolFinishAnalysis, tools.ShellCheck, languages.Shell) } -func (f *Formatter) startShellCheck(projectSubPath string) error { +func (f *Formatter) startShellCheck(projectSubPath string) (string, error) { f.LogDebugWithReplace(messages.MsgDebugToolStartAnalysis, tools.ShellCheck, languages.Shell) output, err := f.ExecuteContainer(f.getDockerConfig(projectSubPath)) if err != nil { - return err + return output, err } - return f.parseOutput(output) + return output, f.parseOutput(output) } func (f *Formatter) parseOutput(containerOutput string) error { @@ -90,7 +91,6 @@ func (f *Formatter) newContainerOutputFromString(containerOutput string) (output containerOutput = strings.ReplaceAll(containerOutput, NotFoundFiles, "") err = json.Unmarshal([]byte(containerOutput), &output) - logger.LogErrorWithLevel(f.GetAnalysisIDErrorMessage(tools.ShellCheck, containerOutput), err) return output, err } diff --git a/internal/utils/testutil/examples.go b/internal/utils/testutil/examples.go index fba8cb54d..bdec6644a 100644 --- a/internal/utils/testutil/examples.go +++ b/internal/utils/testutil/examples.go @@ -24,7 +24,7 @@ import ( const ( // AverageTimeoutAnalyzeForExamplesFolder Average timeout for analysis in the example directory - AverageTimeoutAnalyzeForExamplesFolder = time.Minute * 15 + AverageTimeoutAnalyzeForExamplesFolder = time.Minute * 30 ) var ( @@ -34,6 +34,11 @@ var ( // ExamplesPath represents the entire examples directory. ExamplesPath = filepath.Join(RootPath, "examples") + // nolint:golint + // C-Lang Example represents the entire c-lang examples directory. + CExample = filepath.Join(ExamplesPath, "c") + CExample1 = filepath.Join(CExample, "example1") + // CsharpExample represents the entire C# examples directory. CsharpExample = filepath.Join(ExamplesPath, "csharp") CsharpExample1 = filepath.Join(CsharpExample, "example1") diff --git a/internal/utils/testutil/formatter_mock.go b/internal/utils/testutil/formatter_mock.go index c34d8a1d4..3bf20d927 100644 --- a/internal/utils/testutil/formatter_mock.go +++ b/internal/utils/testutil/formatter_mock.go @@ -68,7 +68,7 @@ func (m *FormatterMock) GetConfigProjectPath() string { return args.Get(0).(string) } -func (m *FormatterMock) SetAnalysisError(_ error, _ tools.Tool, _ string) { +func (m *FormatterMock) SetAnalysisError(_ error, _ tools.Tool, _, _ string) { _ = m.MethodCalled("SetAnalysisError") }