diff --git a/.2ms.yml b/.2ms.yml index d643fc01..e82c9692 100644 --- a/.2ms.yml +++ b/.2ms.yml @@ -89,4 +89,8 @@ ignore-result: - 777f3d460d69a70e2ce760ca757b18f2aa984392 # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10 - e392318c730d4cd0a04340f1e3d41d4c61f6eb20 # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10 - 8f0e0442b01c18b02cfb8e59555103f8233fc7bf # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10 - - 353627158f2e7fa5bb60271cee17da80e5fbba17 # value used as true positive, found at https://github.com/Checkmarx/2ms/pull/292/commits/cc44c8f8bee92250bdcd69bf9fbaffabf0eb442a \ No newline at end of file + - 353627158f2e7fa5bb60271cee17da80e5fbba17 # value used as true positive, found at https://github.com/Checkmarx/2ms/pull/292/commits/cc44c8f8bee92250bdcd69bf9fbaffabf0eb442a + - bf9302d29d7167f39041b0561ae9d1d3677faa2f # value used for testing + - 44912790c892213daa0df821a006e1e1659e6e24 # value used for testing + - ac3704513c4ab9bde3fa3539b14152c95ba5698f # value used for testing + - ac2d6adbeca8901c1655bcf3e0eac027ca681825 # value used for testing diff --git a/pkg/scan.go b/pkg/scan.go index 27899eb1..7d00b213 100644 --- a/pkg/scan.go +++ b/pkg/scan.go @@ -12,6 +12,7 @@ import ( type ScanConfig struct { IgnoreResultIds []string + IgnoreRules []string } type scanner struct{} @@ -37,7 +38,7 @@ func (s *scanner) Scan(scanItems []ScanItem, scanConfig ScanConfig) (*reporting. }() // Initialize engine configuration - engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds} + engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules} engineInstance, err := engine.Init(engineConfig) if err != nil { return &reporting.Report{}, fmt.Errorf("error initializing engine: %w", err) @@ -93,7 +94,7 @@ func (s *scanner) ScanDynamic(itemsIn <-chan ScanItem, scanConfig ScanConfig) (* errorsCh := cmd.Channels.Errors // Initialize engine configuration. - engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds} + engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules} engineInstance, err := engine.Init(engineConfig) if err != nil { return &reporting.Report{}, fmt.Errorf("error initializing engine: %w", err) diff --git a/pkg/scan_test.go b/pkg/scan_test.go index 75ebad25..191f9ce0 100644 --- a/pkg/scan_test.go +++ b/pkg/scan_test.go @@ -16,10 +16,11 @@ import ( ) const ( - githubPatPath = "testData/secrets/github-pat.txt" - jwtPath = "testData/secrets/jwt.txt" - expectedReportPath = "testData/expectedReport.json" - expectedReportResultsIgnoredPath = "testData/expectedReportWithIgnoredResults.json" + githubPatPath = "testData/secrets/github-pat.txt" + jwtPath = "testData/secrets/jwt.txt" + expectedReportPath = "testData/expectedReport.json" + expectedReportResultsIgnoredResultsPath = "testData/expectedReportWithIgnoredResults.json" + expectedReportResultsIgnoredRulePath = "testData/expectedReportWithIgnoredRule.json" ) func TestScan(t *testing.T) { @@ -135,7 +136,74 @@ func TestScan(t *testing.T) { }) assert.NoError(t, err, "scanner encountered an error") - expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredPath) + expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredResultsPath) + assert.NoError(t, err, "failed to read expected report file") + + var expectedReport, actualReportMap map[string]interface{} + + err = json.Unmarshal(expectedReportBytes, &expectedReport) + assert.NoError(t, err, "failed to unmarshal expected report JSON") + + actualReportBytes, err := json.Marshal(actualReport) + assert.NoError(t, err, "failed to marshal actual report to JSON") + err = json.Unmarshal(actualReportBytes, &actualReportMap) + assert.NoError(t, err, "failed to unmarshal actual report JSON") + + normalizedExpectedReport, err := utils.NormalizeReportData(expectedReport) + assert.NoError(t, err, "Failed to normalize actual report") + + normalizedActualReport, err := utils.NormalizeReportData(actualReportMap) + assert.NoError(t, err, "Failed to normalize actual report") + + assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport) + }) + t.Run("Successful scan with multiple items and ignored rule", func(t *testing.T) { + cmd.Report = reporting.Init() + cmd.SecretsChan = make(chan *secrets.Secret) + cmd.SecretsExtrasChan = make(chan *secrets.Secret) + cmd.ValidationChan = make(chan *secrets.Secret) + cmd.CvssScoreWithoutValidationChan = make(chan *secrets.Secret) + cmd.Channels.Items = make(chan plugins.ISourceItem) + cmd.Channels.Errors = make(chan error) + + githubPatBytes, err := os.ReadFile(githubPatPath) + assert.NoError(t, err, "failed to read github-pat file") + githubPatContent := string(githubPatBytes) + + jwtBytes, err := os.ReadFile(jwtPath) + assert.NoError(t, err, "failed to read jwt file") + jwtContent := string(jwtBytes) + + emptyContent := "" + emptyMockPath := "mockPath" + + scanItems := []ScanItem{ + { + Content: &githubPatContent, + ID: fmt.Sprintf("mock-%s", githubPatPath), + Source: githubPatPath, + }, + { + Content: &emptyContent, + ID: fmt.Sprintf("mock-%s", emptyMockPath), + Source: emptyMockPath, + }, + { + Content: &jwtContent, + ID: fmt.Sprintf("mock-%s", jwtPath), + Source: jwtPath, + }, + } + + testScanner := NewScanner() + actualReport, err := testScanner.Scan(scanItems, ScanConfig{ + IgnoreRules: []string{ + "github-pat", + }, + }) + assert.NoError(t, err, "scanner encountered an error") + + expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredRulePath) assert.NoError(t, err, "failed to read expected report file") var expectedReport, actualReportMap map[string]interface{} @@ -352,7 +420,7 @@ func TestScanDynamic(t *testing.T) { }) assert.NoError(t, err, "scanner encountered an error") - expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredPath) + expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredResultsPath) assert.NoError(t, err, "failed to read expected report file") var expectedReport, actualReportMap map[string]interface{} @@ -374,7 +442,81 @@ func TestScanDynamic(t *testing.T) { assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport) }) + t.Run("Successful ScanDynamic with Multiple Items and Ignored Rule", func(t *testing.T) { + cmd.Report = reporting.Init() + cmd.SecretsChan = make(chan *secrets.Secret) + cmd.SecretsExtrasChan = make(chan *secrets.Secret) + cmd.ValidationChan = make(chan *secrets.Secret) + cmd.CvssScoreWithoutValidationChan = make(chan *secrets.Secret) + cmd.Channels.Items = make(chan plugins.ISourceItem) + cmd.Channels.Errors = make(chan error) + cmd.Channels.WaitGroup = &sync.WaitGroup{} + + githubPatBytes, err := os.ReadFile(githubPatPath) + assert.NoError(t, err, "failed to read github-pat file") + githubPatContent := string(githubPatBytes) + + jwtBytes, err := os.ReadFile(jwtPath) + assert.NoError(t, err, "failed to read jwt file") + jwtContent := string(jwtBytes) + + emptyContent := "" + emptyMockPath := "mockPath" + + scanItems := []ScanItem{ + { + Content: &githubPatContent, + ID: fmt.Sprintf("mock-%s", githubPatPath), + Source: githubPatPath, + }, + { + Content: &emptyContent, + ID: fmt.Sprintf("mock-%s", emptyMockPath), + Source: emptyMockPath, + }, + { + Content: &jwtContent, + ID: fmt.Sprintf("mock-%s", jwtPath), + Source: jwtPath, + }, + } + itemsIn := make(chan ScanItem, len(scanItems)) + for _, item := range scanItems { + itemsIn <- item + } + close(itemsIn) + + testScanner := NewScanner() + actualReport, err := testScanner.ScanDynamic(itemsIn, ScanConfig{ + IgnoreRules: []string{ + "github-pat", + }, + }) + assert.NoError(t, err, "scanner encountered an error") + + expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredRulePath) + assert.NoError(t, err, "failed to read expected report file") + + var expectedReport, actualReportMap map[string]interface{} + + err = json.Unmarshal(expectedReportBytes, &expectedReport) + assert.NoError(t, err, "failed to unmarshal expected report JSON") + + actualReportBytes, err := json.Marshal(actualReport) + assert.NoError(t, err, "failed to marshal actual report to JSON") + err = json.Unmarshal(actualReportBytes, &actualReportMap) + assert.NoError(t, err, "failed to unmarshal actual report JSON") + + // Normalize both maps. + normalizedExpectedReport, err := utils.NormalizeReportData(expectedReport) + assert.NoError(t, err, "Failed to normalize actual report") + + normalizedActualReport, err := utils.NormalizeReportData(actualReportMap) + assert.NoError(t, err, "Failed to normalize actual report") + + assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport) + }) t.Run("error handling should work", func(t *testing.T) { cmd.Report = reporting.Init() cmd.SecretsChan = make(chan *secrets.Secret) diff --git a/pkg/testData/expectedReportWithIgnoredRule.json b/pkg/testData/expectedReportWithIgnoredRule.json new file mode 100644 index 00000000..8e713981 --- /dev/null +++ b/pkg/testData/expectedReportWithIgnoredRule.json @@ -0,0 +1,62 @@ +{ + "totalItemsScanned" : 3, + "totalSecretsFound" : 3, + "results" : { + "a0cd293e6e122a1c7384d5a56781e39ba350c54b" : [ { + "id" : "a0cd293e6e122a1c7384d5a56781e39ba350c54b", + "source" : "testData/secrets/jwt.txt", + "ruleId" : "jwt", + "startLine" : 0, + "endLine" : 0, + "lineContent" : "TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1 TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2 TextExample\r", + "startColumn" : 129, + "endColumn" : 232, + "value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2", + "ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.", + "extraDetails" : { + "secretDetails" : { + "name" : "mockName2", + "sub" : "mockSub2" + } + }, + "cvssScore" : 8.2 + }, { + "id" : "a0cd293e6e122a1c7384d5a56781e39ba350c54b", + "source" : "testData/secrets/jwt.txt", + "ruleId" : "jwt", + "startLine" : 1, + "endLine" : 1, + "lineContent": "\n Text_Example = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2", + "startColumn" : 64, + "endColumn" : 167, + "value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2", + "ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.", + "extraDetails" : { + "secretDetails" : { + "name" : "mockName2", + "sub" : "mockSub2" + } + }, + "cvssScore" : 8.2 + } ], + "f29abe9eacc233a8e5e9c7762bca48589d9c76a2" : [ { + "id" : "f29abe9eacc233a8e5e9c7762bca48589d9c76a2", + "source" : "testData/secrets/jwt.txt", + "ruleId" : "jwt", + "startLine" : 0, + "endLine" : 0, + "lineContent" : "TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1 TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2 TextExample\r", + "startColumn" : 13, + "endColumn" : 116, + "value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1", + "ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.", + "extraDetails" : { + "secretDetails" : { + "name" : "mockName1", + "sub" : "mockSub1" + } + }, + "cvssScore" : 8.2 + } ] + } +} \ No newline at end of file