From 7ae4e77b7a27441468f6947d5ce09b8ca7c4db07 Mon Sep 17 00:00:00 2001 From: Matheus Alcantara Date: Thu, 14 Oct 2021 14:01:42 -0300 Subject: [PATCH] cli: fix breaking change on vulnerability hashes On pr #636 we add the rule id on description of vulnerability, but the Details of vulnerability is used to generate the vulnerability hash, so adding the rule id on details generate a different hash which cause a breaking change. So this commit remove the rule id prefix from Details field of Vulnerability and also add a workaround to users that is already using the new hash as a false positive and risk accept. To support the two ways of hashing the vulnerability a new field was added on Vulnerability struct that represents the breaking way, so we generate the two hashes of vulnerability and when we set the vulnerability to false positive/risk accept according to config file we use the two hashes to match. Fixes #680 Signed-off-by: Matheus Alcantara --- go.mod | 2 +- go.sum | 4 +- internal/controllers/analyzer/analyzer.go | 39 ++++-- .../controllers/analyzer/analyzer_test.go | 83 +++++++++++++ .../controllers/printresults/print_results.go | 3 + internal/services/formatters/service.go | 3 +- internal/services/formatters/service_test.go | 116 +++++++++++++----- internal/utils/vuln_hash/vuln_hash.go | 14 +++ 8 files changed, 219 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index 21ea9f24e..1eb4228c5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ZupIT/horusec go 1.17 require ( - github.com/ZupIT/horusec-devkit v1.0.18 + github.com/ZupIT/horusec-devkit v1.0.19 github.com/ZupIT/horusec-engine v0.3.6 github.com/bmatcuk/doublestar/v4 v4.0.2 github.com/briandowns/spinner v1.16.0 diff --git a/go.sum b/go.sum index 9a87feb5b..690dd5197 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/ZupIT/horusec-devkit v1.0.17/go.mod h1:wTsXrXTD1YrChTQEng8EvVg+zL9nMUIQkhUG85sQwuQ= -github.com/ZupIT/horusec-devkit v1.0.18 h1:Nbl7YQTBnwPFRmIEn0LKINN5u2SwvCu6Jt8wmlhHTO8= -github.com/ZupIT/horusec-devkit v1.0.18/go.mod h1:8rEUFNoFOGeAIG1unUfaF5qP6agHPnf9WsMtGfQR/iU= +github.com/ZupIT/horusec-devkit v1.0.19 h1:eQNzst0a91YkAzSWy+1A/brBR9Lon2dMmzs0vZ3dUzQ= +github.com/ZupIT/horusec-devkit v1.0.19/go.mod h1:8rEUFNoFOGeAIG1unUfaF5qP6agHPnf9WsMtGfQR/iU= github.com/ZupIT/horusec-engine v0.3.6 h1:m/kL9K8+OVAaYjagoDmNFFDEA3BnyJbcx0DfNYGyaDM= github.com/ZupIT/horusec-engine v0.3.6/go.mod h1:s3SZQ9gXXlEcIagEuopZJga+Dw6RBFWMD7Rh5A+tIys= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= diff --git a/internal/controllers/analyzer/analyzer.go b/internal/controllers/analyzer/analyzer.go index 14bc1d883..13c3f2eb7 100644 --- a/internal/controllers/analyzer/analyzer.go +++ b/internal/controllers/analyzer/analyzer.go @@ -28,6 +28,7 @@ import ( "github.com/google/uuid" "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" + "github.com/ZupIT/horusec-devkit/pkg/entities/vulnerability" enumsAnalysis "github.com/ZupIT/horusec-devkit/pkg/enums/analysis" "github.com/ZupIT/horusec-devkit/pkg/enums/confidence" "github.com/ZupIT/horusec-devkit/pkg/enums/languages" @@ -443,11 +444,14 @@ func (a *Analyzer) logProjectSubPath(language languages.Language, subPath string } } +// nolint:gocyclo func (a *Analyzer) checkIfNoExistHashAndLog(list []string) { for _, hash := range list { existing := false - for keyAv := range a.analysis.AnalysisVulnerabilities { - if hash == a.analysis.AnalysisVulnerabilities[keyAv].Vulnerability.VulnHash { + for idx := range a.analysis.AnalysisVulnerabilities { + vulnHash := a.analysis.AnalysisVulnerabilities[idx].Vulnerability.VulnHash + vulnHashInvalid := a.analysis.AnalysisVulnerabilities[idx].Vulnerability.VulnHashInvalid + if hash == vulnHash || hash == vulnHashInvalid { existing = true break } @@ -484,21 +488,30 @@ func (a *Analyzer) getCustomOrDefaultImage(language languages.Language) string { return fmt.Sprintf("%s/%s", images.DefaultRegistry, images.MapValues()[language]) } -func (a *Analyzer) SetFalsePositivesAndRiskAcceptInVulnerabilities( - listFalsePositive, listRiskAccept []string) *analysis.Analysis { - for key := range a.analysis.AnalysisVulnerabilities { - a.setVulnerabilityType(key, listFalsePositive, enumsVulnerability.FalsePositive) - a.setVulnerabilityType(key, listRiskAccept, enumsVulnerability.RiskAccepted) +// SetFalsePositivesAndRiskAcceptInVulnerabilities set analysis vulnerabiltieis to false +// positive or risk accept if the hash exists on falsePositive and riskAccept params. +// +// nolint:lll +func (a *Analyzer) SetFalsePositivesAndRiskAcceptInVulnerabilities(falsePositive, riskAccept []string) *analysis.Analysis { + for idx := range a.analysis.AnalysisVulnerabilities { + a.setVulnerabilityType( + &a.analysis.AnalysisVulnerabilities[idx].Vulnerability, falsePositive, enumsVulnerability.FalsePositive, + ) + a.setVulnerabilityType( + &a.analysis.AnalysisVulnerabilities[idx].Vulnerability, riskAccept, enumsVulnerability.RiskAccepted, + ) } return a.analysis } -func (a *Analyzer) setVulnerabilityType(keyAnalysisVulnerabilities int, - listToCheck []string, vulnerabilityType enumsVulnerability.Type) { - currentHash := a.analysis.AnalysisVulnerabilities[keyAnalysisVulnerabilities].Vulnerability.VulnHash - for _, flagVulnerabilityHash := range listToCheck { - if flagVulnerabilityHash != "" && strings.TrimSpace(currentHash) == strings.TrimSpace(flagVulnerabilityHash) { - a.analysis.AnalysisVulnerabilities[keyAnalysisVulnerabilities].Vulnerability.Type = vulnerabilityType +func (a *Analyzer) setVulnerabilityType( + vuln *vulnerability.Vulnerability, hashes []string, vulnType enumsVulnerability.Type, +) { + for _, hash := range hashes { + hash = strings.TrimSpace(hash) + // See vulnerability.Vulnerability.VulnHashInvalid docs for more info. + if hash != "" && (strings.TrimSpace(vuln.VulnHash) == hash || strings.TrimSpace(vuln.VulnHashInvalid) == hash) { + vuln.Type = vulnType } } } diff --git a/internal/controllers/analyzer/analyzer_test.go b/internal/controllers/analyzer/analyzer_test.go index 0655c4416..32d8d5f5d 100644 --- a/internal/controllers/analyzer/analyzer_test.go +++ b/internal/controllers/analyzer/analyzer_test.go @@ -17,15 +17,20 @@ package analyzer import ( "bytes" "errors" + "fmt" "io" "os" "path/filepath" "testing" + "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" entitiesAnalysis "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" + "github.com/ZupIT/horusec-devkit/pkg/entities/vulnerability" + vulnerabilityenum "github.com/ZupIT/horusec-devkit/pkg/enums/vulnerability" "github.com/ZupIT/horusec-devkit/pkg/utils/logger" horusecAPI "github.com/ZupIT/horusec/internal/services/horusec_api" "github.com/ZupIT/horusec/internal/utils/mock" + vulnhash "github.com/ZupIT/horusec/internal/utils/vuln_hash" "github.com/ZupIT/horusec/internal/entities/workdir" @@ -65,6 +70,84 @@ func BenchmarkAnalyzerAnalyze(b *testing.B) { } } +func TestAnalyzerSetFalsePositivesAndRiskAcceptInVulnerabilities(t *testing.T) { + vuln := vulnerability.Vulnerability{ + RuleID: "HS-TEST-1", + Line: "10", + Column: "20", + File: "testing", + Code: "testing", + Details: fmt.Sprintf("Test\nDescription testing"), + } + vulnhash.Bind(&vuln) + + testcases := []struct { + name string + vulnerability vulnerability.Vulnerability + hashes []string + expectedType vulnerabilityenum.Type + }{ + { + name: "ChangeCorrectHashToFalsePositive", + vulnerability: vuln, + hashes: []string{vuln.VulnHash}, + expectedType: vulnerabilityenum.FalsePositive, + }, + { + name: "ChangeBreakingHashToFalsePositive", + vulnerability: vuln, + hashes: []string{vuln.VulnHashInvalid}, + expectedType: vulnerabilityenum.FalsePositive, + }, + { + name: "ChangeCorrectHashToRiskAccept", + vulnerability: vuln, + hashes: []string{vuln.VulnHash}, + expectedType: vulnerabilityenum.RiskAccepted, + }, + { + name: "ChangeBreakingHashToRiskAccept", + vulnerability: vuln, + hashes: []string{vuln.VulnHashInvalid}, + expectedType: vulnerabilityenum.RiskAccepted, + }, + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + analyzer := NewAnalyzer(config.New()) + + analyzer.analysis.AnalysisVulnerabilities = append( + analyzer.analysis.AnalysisVulnerabilities, analysis.AnalysisVulnerabilities{ + AnalysisID: uuid.New(), + Vulnerability: tt.vulnerability, + }, + ) + var ( + falsePositiveHashes []string + riskAcceptHashes []string + ) + + switch tt.expectedType { + case vulnerabilityenum.FalsePositive: + falsePositiveHashes = tt.hashes + case vulnerabilityenum.RiskAccepted: + riskAcceptHashes = tt.hashes + default: + t.Fatalf("invalid type %s", tt.expectedType) + } + + analyzer.SetFalsePositivesAndRiskAcceptInVulnerabilities(falsePositiveHashes, riskAcceptHashes) + + require.Len(t, analyzer.analysis.AnalysisVulnerabilities, len(tt.hashes)) + for _, vuln := range analyzer.analysis.AnalysisVulnerabilities { + assert.Equal(t, tt.expectedType, vuln.Vulnerability.Type) + } + + }) + } +} + func TestNewAnalyzer(t *testing.T) { t.Run("Should return type os struct correctly", func(t *testing.T) { assert.IsType(t, &Analyzer{}, NewAnalyzer(&config.Config{})) diff --git a/internal/controllers/printresults/print_results.go b/internal/controllers/printresults/print_results.go index 8cce07e35..174998a3c 100644 --- a/internal/controllers/printresults/print_results.go +++ b/internal/controllers/printresults/print_results.go @@ -277,6 +277,9 @@ func (pr *PrintResults) printTextOutputVulnerabilityData(vulnerability *vulnerab pr.printLNF("Confidence: %s", vulnerability.Confidence) pr.printLNF("File: %s", pr.getProjectPath(vulnerability.File)) pr.printLNF("Code: %s", vulnerability.Code) + if vulnerability.RuleID != "" { + pr.printLNF("RuleID: %s", vulnerability.RuleID) + } pr.printLNF("Details: %s", vulnerability.Details) pr.printLNF("Type: %s", vulnerability.Type) diff --git a/internal/services/formatters/service.go b/internal/services/formatters/service.go index 0477fc600..191d607a0 100644 --- a/internal/services/formatters/service.go +++ b/internal/services/formatters/service.go @@ -237,12 +237,13 @@ func (s *Service) AddNewVulnerabilityIntoAnalysis(vuln *vulnerability.Vulnerabil func (s *Service) newVulnerabilityFromFinding(finding *engine.Finding, tool tools.Tool, language languages.Language) *vulnerability.Vulnerability { return &vulnerability.Vulnerability{ + RuleID: finding.ID, Line: strconv.Itoa(finding.SourceLocation.Line), Column: strconv.Itoa(finding.SourceLocation.Column), Confidence: confidence.Confidence(finding.Confidence), File: s.removeHorusecFolder(finding.SourceLocation.Filename), Code: s.GetCodeWithMaxCharacters(finding.CodeSample, finding.SourceLocation.Column), - Details: fmt.Sprintf("%s: %s\n%s", finding.ID, finding.Name, finding.Description), + Details: fmt.Sprintf("%s\n%s", finding.Name, finding.Description), SecurityTool: tool, Language: language, Severity: severities.GetSeverityByString(finding.Severity), diff --git a/internal/services/formatters/service_test.go b/internal/services/formatters/service_test.go index 9826141fe..0360bf6b2 100644 --- a/internal/services/formatters/service_test.go +++ b/internal/services/formatters/service_test.go @@ -16,26 +16,86 @@ package formatters import ( "errors" + "fmt" "strconv" "testing" + "github.com/ZupIT/horusec-devkit/pkg/enums/confidence" "github.com/ZupIT/horusec-devkit/pkg/enums/languages" + "github.com/ZupIT/horusec-devkit/pkg/enums/severities" + engine "github.com/ZupIT/horusec-engine" + commitauthor "github.com/ZupIT/horusec/internal/entities/commit_author" "github.com/ZupIT/horusec/internal/entities/toolsconfig" - entitiesAnalysis "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" - commitAuthor "github.com/ZupIT/horusec/internal/entities/commit_author" + "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" + "github.com/ZupIT/horusec-devkit/pkg/entities/vulnerability" "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/ZupIT/horusec-devkit/pkg/enums/tools" "github.com/ZupIT/horusec/config" - dockerEntities "github.com/ZupIT/horusec/internal/entities/docker" + dockerentities "github.com/ZupIT/horusec/internal/entities/docker" "github.com/ZupIT/horusec/internal/entities/workdir" "github.com/ZupIT/horusec/internal/services/docker" + "github.com/ZupIT/horusec/internal/services/engines/java" ) +func TestParseFindingsToVulnerabilities(t *testing.T) { + analysis := new(analysis.Analysis) + svc := NewFormatterService(analysis, &docker.Mock{}, config.New()) + + rule := java.NewAWSQueryInjection() + findings := []engine.Finding{ + { + ID: rule.ID, + Name: rule.Name, + Severity: rule.Severity, + CodeSample: "testing", + Confidence: rule.Confidence, + Description: rule.Description, + SourceLocation: engine.Location{ + Filename: "Test.java", + Line: 10, + Column: 20, + }, + }, + } + err := svc.ParseFindingsToVulnerabilities(findings, tools.HorusecEngine, languages.Java) + require.Nil(t, err, "Expected nil error to parse finding to vulnerabilities") + + expectedVulnerabilities := []vulnerability.Vulnerability{ + { + RuleID: rule.ID, + Line: "10", + Column: "20", + Confidence: confidence.Confidence(rule.Confidence), + File: "Test.java", + Code: "testing", + Details: fmt.Sprintf("%s\n%s", rule.Name, rule.Description), + SecurityTool: tools.HorusecEngine, + Language: languages.Java, + Severity: severities.GetSeverityByString(rule.Severity), + CommitAuthor: "-", + CommitDate: "-", + CommitEmail: "-", + CommitHash: "-", + CommitMessage: "-", + // NOTE: We hard coded vulnerability hash here to assert that we are not breaking existing hashes + VulnHash: "b9ffd6959275a840254c9ddc9ab0cc5edd6f7950f1b71103d772ac5a17ca988d", + VulnHashInvalid: "7ebe9a1e2b39735edcae2f576f31ea4779b5eb9300064e3ebb351069fdd01ed3", + }, + } + + require.Len(t, analysis.AnalysisVulnerabilities, len(expectedVulnerabilities)) + for idx := range expectedVulnerabilities { + assert.Equal(t, expectedVulnerabilities[idx], analysis.AnalysisVulnerabilities[idx].Vulnerability) + + } +} + func TestMock_AddWorkDirInCmd(t *testing.T) { mock := &Mock{} t.Run("Should mock with success", func(t *testing.T) { @@ -44,10 +104,10 @@ func TestMock_AddWorkDirInCmd(t *testing.T) { mock.On("SetAnalysisError").Return() mock.On("ExecuteContainer").Return("", nil) mock.On("GetAnalysisIDErrorMessage").Return("") - mock.On("GetCommitAuthor").Return(commitAuthor.CommitAuthor{}) + mock.On("GetCommitAuthor").Return(commitauthor.CommitAuthor{}) mock.On("AddWorkDirInCmd").Return("") mock.On("GetConfigProjectPath").Return("") - mock.On("GetAnalysis").Return(&entitiesAnalysis.Analysis{}) + mock.On("GetAnalysis").Return(&analysis.Analysis{}) mock.On("SetToolFinishedAnalysis").Return() mock.On("LogAnalysisError").Return() mock.On("SetMonitor").Return() @@ -55,7 +115,7 @@ func TestMock_AddWorkDirInCmd(t *testing.T) { mock.On("GetCodeWithMaxCharacters").Return("") mock.LogDebugWithReplace("", "", "") _ = mock.GetAnalysisID() - _, _ = mock.ExecuteContainer(&dockerEntities.AnalysisData{}) + _, _ = mock.ExecuteContainer(&dockerentities.AnalysisData{}) _ = mock.GetAnalysisIDErrorMessage("", "") _ = mock.GetCommitAuthor("", "") _ = mock.AddWorkDirInCmd("", "", "") @@ -68,14 +128,14 @@ func TestMock_AddWorkDirInCmd(t *testing.T) { func TestExecuteContainer(t *testing.T) { t.Run("should return no error when success set is finished", func(t *testing.T) { - analysis := &entitiesAnalysis.Analysis{} + analysis := &analysis.Analysis{} dockerAPIControllerMock := &docker.Mock{} dockerAPIControllerMock.On("SetAnalysisID") dockerAPIControllerMock.On("CreateLanguageAnalysisContainer").Return("test", nil) monitorController := NewFormatterService(analysis, dockerAPIControllerMock, &config.Config{}) - result, err := monitorController.ExecuteContainer(&dockerEntities.AnalysisData{}) + result, err := monitorController.ExecuteContainer(&dockerentities.AnalysisData{}) assert.NoError(t, err) assert.Equal(t, "test", result) @@ -84,7 +144,7 @@ func TestExecuteContainer(t *testing.T) { func TestGetAnalysisIDErrorMessage(t *testing.T) { t.Run("should success get error message with replaces", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) result := monitorController.GetAnalysisIDErrorMessage(tools.Bandit, "test") @@ -96,7 +156,7 @@ func TestGetAnalysisIDErrorMessage(t *testing.T) { func TestGetCommitAuthor(t *testing.T) { t.Run("should get commit author", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) result := monitorController.GetCommitAuthor("", "") @@ -109,7 +169,7 @@ func TestGetConfigProjectPath(t *testing.T) { cliConfig := &config.Config{} cliConfig.ProjectPath = "test" - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, cliConfig) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, cliConfig) result := monitorController.GetConfigProjectPath() @@ -125,7 +185,7 @@ func TestAddWorkDirInCmd(t *testing.T) { CSharp: []string{"test"}, } - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, cliConfig) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, cliConfig) result := monitorController.AddWorkDirInCmd("test", "C#", tools.SecurityCodeScan) @@ -138,7 +198,7 @@ func TestAddWorkDirInCmd(t *testing.T) { CSharp: []string{"test"}, } - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, cliConfig) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, cliConfig) result := monitorController.AddWorkDirInCmd("test", "C#", tools.SecurityCodeScan) @@ -148,7 +208,7 @@ func TestAddWorkDirInCmd(t *testing.T) { func TestLogDebugWithReplace(t *testing.T) { t.Run("should log debug and not panics", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) assert.NotPanics(t, func() { monitorController.LogDebugWithReplace("test", tools.NpmAudit, languages.Javascript) @@ -159,21 +219,21 @@ func TestLogDebugWithReplace(t *testing.T) { func TestGetAnalysisID(t *testing.T) { t.Run("should success get analysis id", func(t *testing.T) { id := uuid.New() - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{ID: id}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{ID: id}, &docker.Mock{}, &config.Config{}) assert.Equal(t, id.String(), monitorController.GetAnalysisID()) }) } func TestLogAnalysisError(t *testing.T) { t.Run("should not panic when logging error", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) assert.NotPanics(t, func() { monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "") }) }) t.Run("should not panic when logging error and exists projectSubPath", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) assert.NotPanics(t, func() { monitorController.SetAnalysisError(errors.New("test"), tools.GoSec, "/tmp") @@ -188,7 +248,7 @@ func TestToolIsToIgnore(t *testing.T) { toolsconfig.ToolsConfigsStruct{GoSec: toolsconfig.ToolConfig{IsToIgnore: true}}, ) - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, configs) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, configs) assert.Equal(t, true, monitorController.ToolIsToIgnore(tools.GoSec)) }) @@ -198,7 +258,7 @@ func TestToolIsToIgnore(t *testing.T) { toolsconfig.ToolsConfigsStruct{GoSec: toolsconfig.ToolConfig{IsToIgnore: true}}, ) - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, configs) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, configs) assert.Equal(t, true, monitorController.ToolIsToIgnore(tools.GoSec)) }) @@ -211,7 +271,7 @@ func TestToolIsToIgnore(t *testing.T) { }, ) - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, configs) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, configs) assert.Equal(t, true, monitorController.ToolIsToIgnore(tools.GoSec)) }) @@ -221,7 +281,7 @@ func TestToolIsToIgnore(t *testing.T) { toolsconfig.ToolsConfigsStruct{SecurityCodeScan: toolsconfig.ToolConfig{IsToIgnore: true}}, ) - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, configs) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, configs) assert.Equal(t, false, monitorController.ToolIsToIgnore(tools.GoSec)) }) @@ -229,21 +289,21 @@ func TestToolIsToIgnore(t *testing.T) { func TestService_GetCodeWithMaxCharacters(t *testing.T) { t.Run("should return default code", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" column := 0 newCode := monitorController.GetCodeWithMaxCharacters(code, column) assert.Equal(t, "text", newCode) }) t.Run("should return default code if column is negative", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" column := -1 newCode := monitorController.GetCodeWithMaxCharacters(code, column) assert.Equal(t, "text", newCode) }) t.Run("should return 4:105 characters when text is so bigger", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" for i := 0; i < 10; i++ { for i := 0; i <= 9; i++ { @@ -255,7 +315,7 @@ func TestService_GetCodeWithMaxCharacters(t *testing.T) { assert.Equal(t, "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", newCode) }) t.Run("should return first 100 characters when text is so bigger", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" for i := 0; i < 10; i++ { for i := 0; i <= 9; i++ { @@ -267,7 +327,7 @@ func TestService_GetCodeWithMaxCharacters(t *testing.T) { assert.Equal(t, "text012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345", newCode) }) t.Run("should return first 100 characters when text contains breaking lines", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := `22: func GetMD5(s string) string { 23: h := md5.New() 24: io.WriteString(h, s) // #nohorus @@ -280,7 +340,7 @@ func TestService_GetCodeWithMaxCharacters(t *testing.T) { `, newCode) }) t.Run("should return first 100 characters when text is so bigger", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" for i := 0; i <= 200; i++ { code += strconv.Itoa(i) @@ -290,7 +350,7 @@ func TestService_GetCodeWithMaxCharacters(t *testing.T) { assert.Equal(t, "4041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889", newCode) }) t.Run("should return first 100 characters when text is so bigger", func(t *testing.T) { - monitorController := NewFormatterService(&entitiesAnalysis.Analysis{}, &docker.Mock{}, &config.Config{}) + monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, &config.Config{}) code := "text" for i := 0; i <= 200; i++ { code += strconv.Itoa(i) diff --git a/internal/utils/vuln_hash/vuln_hash.go b/internal/utils/vuln_hash/vuln_hash.go index fe514ab3d..4e1380b9a 100644 --- a/internal/utils/vuln_hash/vuln_hash.go +++ b/internal/utils/vuln_hash/vuln_hash.go @@ -15,6 +15,7 @@ package vulnhash import ( + "fmt" "regexp" "strings" @@ -22,6 +23,10 @@ import ( "github.com/ZupIT/horusec-devkit/pkg/utils/crypto" ) +// Bind generate and set the vulnerability hash on vuln. Note that Bind +// generate the valid and invalid vulnerability hashes. +// +// nolint:funlen func Bind(vuln *vulnerability.Vulnerability) *vulnerability.Vulnerability { vuln.VulnHash = crypto.GenerateSHA256( toOneLine(vuln.Code), @@ -31,6 +36,15 @@ func Bind(vuln *vulnerability.Vulnerability) *vulnerability.Vulnerability { vuln.CommitEmail, ) + // See vulnerability.Vulnerability.VulnHashInvalid docs for more info. + vuln.VulnHashInvalid = crypto.GenerateSHA256( + toOneLine(vuln.Code), + vuln.Line, + fmt.Sprintf("%s: %s", vuln.RuleID, vuln.Details), + vuln.File, + vuln.CommitEmail, + ) + return vuln }