diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index daeea115..b8307520 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: with: go-version: "^1.22" - name: Go Linter - run: docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.61.0 golangci-lint run -v -E gofmt --timeout=5m + run: docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v2.1.5 golangci-lint run --timeout=5m - name: Unit Tests run: go test ./... diff --git a/engine/rules/rules.go b/engine/rules/rules.go index c2eb08ee..7e187891 100644 --- a/engine/rules/rules.go +++ b/engine/rules/rules.go @@ -70,7 +70,7 @@ const TagPublicSecret = "public-secret" const TagSensitiveUrl = "sensitive-url" const TagWebhook = "webhook" -func getDefaultRules() *[]Rule { +func GetDefaultRules() *[]Rule { allRules := &[]Rule{ {Rule: *rules.AdafruitAPIKey(), Tags: []string{TagApiKey}, ScoreParameters: ScoreParameters{Category: CategoryIoTPlatform, RuleType: 4}}, {Rule: *rules.AdobeClientID(), Tags: []string{TagClientId}, ScoreParameters: ScoreParameters{Category: CategorySaaS, RuleType: 1}}, @@ -293,7 +293,7 @@ func FilterRules(selectedList, ignoreList, specialList []string) *[]Rule { log.Warn().Msgf("Both 'rule' and 'ignoreRule' flags were provided, I will first take all in 'rule' and then remove all in 'ignoreRule' from the list.") } - selectedRules := getDefaultRules() + selectedRules := GetDefaultRules() if len(selectedList) > 0 { selectedRules = selectRules(selectedRules, selectedList) } diff --git a/engine/rules/rules_test.go b/engine/rules/rules_test.go index 2a36a125..8d3dffa8 100644 --- a/engine/rules/rules_test.go +++ b/engine/rules/rules_test.go @@ -7,7 +7,7 @@ import ( ) func TestLoadAllRules(t *testing.T) { - rules := getDefaultRules() + rules := GetDefaultRules() if len(*rules) <= 1 { t.Error("no rules were loaded") @@ -16,7 +16,7 @@ func TestLoadAllRules(t *testing.T) { func TestLoadAllRules_DuplicateRuleID(t *testing.T) { ruleIDMap := make(map[string]bool) - allRules := getDefaultRules() + allRules := GetDefaultRules() for _, rule := range *allRules { if _, ok := ruleIDMap[rule.Rule.RuleID]; ok { @@ -29,7 +29,7 @@ func TestLoadAllRules_DuplicateRuleID(t *testing.T) { func Test_FilterRules_SelectRules(t *testing.T) { specialRule := HardcodedPassword() - allRules := *getDefaultRules() + allRules := *GetDefaultRules() rulesCount := len(allRules) tests := []struct { diff --git a/pkg/scan.go b/pkg/scan.go index bb5cb9c2..7c280fba 100644 --- a/pkg/scan.go +++ b/pkg/scan.go @@ -3,6 +3,8 @@ package scanner import ( "errors" "fmt" + "github.com/checkmarx/2ms/v3/lib/secrets" + "github.com/checkmarx/2ms/v3/plugins" "sync" "github.com/checkmarx/2ms/v3/lib/reporting" @@ -23,15 +25,29 @@ func NewScanner() Scanner { return &scanner{} } +func resetCmdGlobals() { + cmd.Channels = plugins.Channels{ + Items: make(chan plugins.ISourceItem), + Errors: make(chan error), + WaitGroup: &sync.WaitGroup{}, + } + + 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) +} + func (s *scanner) Scan(scanItems []ScanItem, scanConfig ScanConfig) (*reporting.Report, error) { - itemsCh := cmd.Channels.Items - errorsCh := cmd.Channels.Errors + resetCmdGlobals() + bufferedErrors := make(chan error, len(scanItems)+1) wg := &sync.WaitGroup{} - // Error listener go func() { - for err := range errorsCh { + for err := range cmd.Channels.Errors { if err != nil { bufferedErrors <- err } @@ -39,7 +55,6 @@ func (s *scanner) Scan(scanItems []ScanItem, scanConfig ScanConfig) (*reporting. close(bufferedErrors) }() - // Initialize engine engineConfig := engine.EngineConfig{ IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules, @@ -49,25 +64,21 @@ func (s *scanner) Scan(scanItems []ScanItem, scanConfig ScanConfig) (*reporting. return &reporting.Report{}, fmt.Errorf("error initializing engine: %w", err) } - // Start processing pipeline startPipeline(engineInstance, scanConfig.WithValidation) - // Send scan items for _, item := range scanItems { wg.Add(1) go func(si ScanItem) { defer wg.Done() - itemsCh <- si + cmd.Channels.Items <- si }(item) } wg.Wait() - close(itemsCh) + close(cmd.Channels.Items) - // Wait for all processing cmd.Channels.WaitGroup.Wait() - close(errorsCh) + close(cmd.Channels.Errors) - // Collect errors var errs []error for err = range bufferedErrors { errs = append(errs, err) @@ -96,46 +107,34 @@ func startPipeline(engineInstance engine.IEngine, withValidation bool) { } func (s *scanner) ScanDynamic(itemsIn <-chan ScanItem, scanConfig ScanConfig) (*reporting.Report, error) { - itemsCh := cmd.Channels.Items - errorsCh := cmd.Channels.Errors + resetCmdGlobals() - // Initialize engine configuration. - engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules} + 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) } - // Start processing routines. - cmd.Channels.WaitGroup.Add(1) - go cmd.ProcessItems(engineInstance, "custom") - - cmd.Channels.WaitGroup.Add(1) - go cmd.ProcessSecrets() - - cmd.Channels.WaitGroup.Add(1) - go cmd.ProcessSecretsExtras() - - cmd.Channels.WaitGroup.Add(1) - go cmd.ProcessScoreWithoutValidation(engineInstance) + startPipeline(engineInstance, false) - for item := range itemsIn { - itemsCh <- item - } - close(itemsCh) + go func() { + for item := range itemsIn { + cmd.Channels.Items <- item + } + close(cmd.Channels.Items) + }() - // Wait for all processing routines. cmd.Channels.WaitGroup.Wait() - close(errorsCh) + close(cmd.Channels.Errors) - // Check if any error occurred. - for err := range errorsCh { + for err := range cmd.Channels.Errors { if err != nil { return &reporting.Report{}, fmt.Errorf("error processing scan items: %w", err) } } - // Finalize and generate report. - report := cmd.Report - return report, nil + return cmd.Report, nil } diff --git a/pkg/scan_test.go b/pkg/scan_test.go index 73919836..eab8d74b 100644 --- a/pkg/scan_test.go +++ b/pkg/scan_test.go @@ -3,16 +3,14 @@ package scanner import ( "encoding/json" "fmt" - "os" - "sync" - "testing" - "github.com/checkmarx/2ms/v3/cmd" + "github.com/checkmarx/2ms/v3/engine/rules" "github.com/checkmarx/2ms/v3/lib/reporting" "github.com/checkmarx/2ms/v3/lib/secrets" "github.com/checkmarx/2ms/v3/lib/utils" - "github.com/checkmarx/2ms/v3/plugins" "github.com/stretchr/testify/assert" + "os" + "testing" ) const ( @@ -26,14 +24,6 @@ const ( func TestScan(t *testing.T) { t.Run("Successful Scan with Multiple Items", 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) @@ -91,14 +81,6 @@ func TestScan(t *testing.T) { assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport) }) t.Run("Successful scan with multiple items and ignored results", 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) @@ -159,14 +141,6 @@ func TestScan(t *testing.T) { 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) @@ -226,14 +200,6 @@ func TestScan(t *testing.T) { 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) - 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) - emptyContent := "" scanItems := []ScanItem{ { @@ -262,47 +228,107 @@ func TestScan(t *testing.T) { assert.Equal(t, "error(s) processing scan items:\nmock processing error 1\nmock processing error 2", err.Error()) }) t.Run("scan with scanItems empty", 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) - testScanner := NewScanner() actualReport, err := testScanner.Scan([]ScanItem{}, ScanConfig{}) assert.NoError(t, err, "scanner encountered an error") assert.Equal(t, &reporting.Report{Results: map[string][]*secrets.Secret{}}, actualReport) }) t.Run("scan with scanItems nil", 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) - testScanner := NewScanner() actualReport, err := testScanner.Scan(nil, ScanConfig{}) assert.NoError(t, err, "scanner encountered an error") assert.Equal(t, &reporting.Report{Results: map[string][]*secrets.Secret{}}, actualReport) }) + t.Run("scan more than 1 time using the same scanner instance", func(t *testing.T) { + 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{}) + assert.NoError(t, err, "scanner encountered an error") + + // scan 1 + expectedReportBytes, err := os.ReadFile(expectedReportPath) + 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") + + // Marshal actual report and unmarshal back into a map. + 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 expected and actual 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) + + // scan 2 + actualReport, err = testScanner.Scan(scanItems, ScanConfig{ + IgnoreResultIds: []string{ + "a0cd293e6e122a1c7384d5a56781e39ba350c54b", + "40483a2b07fa3beaf234d1a0b5d0931d7b7ae9f7", + }, + }) + assert.NoError(t, err, "scanner encountered an error") + + expectedReportBytes, err = os.ReadFile(expectedReportResultsIgnoredResultsPath) + assert.NoError(t, err, "failed to read expected report file") + + 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) + }) } func TestScanDynamic(t *testing.T) { t.Run("Successful ScanDynamic with Multiple Items", func(t *testing.T) { - // Reset global channels and report. - 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{} - // Read file contents. githubPatBytes, err := os.ReadFile(githubPatPath) assert.NoError(t, err, "failed to read github-pat file") @@ -368,15 +394,6 @@ func TestScanDynamic(t *testing.T) { }) t.Run("Successful ScanDynamic with Multiple Items and Ignored Results", 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) @@ -444,15 +461,6 @@ 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) @@ -519,42 +527,33 @@ func TestScanDynamic(t *testing.T) { 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) - 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, 2) - cmd.Channels.WaitGroup = &sync.WaitGroup{} - - itemsIn := make(chan ScanItem) + content := "content" + itemsIn := make(chan ScanItem, 1) + itemsIn <- ScanItem{ + Content: &content, + ID: "id", + Source: "source", + } close(itemsIn) - go func() { - cmd.Channels.Errors <- fmt.Errorf("mock processing error 1") - cmd.Channels.Errors <- fmt.Errorf("mock processing error 2") - }() + // get rules to filter all and force an error + defaultRules := rules.GetDefaultRules() + var idOfRules []string + for _, rule := range *defaultRules { + idOfRules = append(idOfRules, rule.Rule.RuleID) + } testScanner := NewScanner() - report, err := testScanner.ScanDynamic(itemsIn, ScanConfig{}) - - assert.Equal(t, &reporting.Report{}, report) - assert.NotNil(t, err) - expectedErrMsg := "error processing scan items: mock processing error 1" - assert.Equal(t, expectedErrMsg, err.Error()) + report, err := testScanner.ScanDynamic(itemsIn, ScanConfig{IgnoreRules: idOfRules}) + + assert.Error(t, err) + assert.Equal(t, "error initializing engine: no rules were selected", err.Error()) + assert.Equal(t, &reporting.Report{ + TotalItemsScanned: 0, + TotalSecretsFound: 0, + }, report) }) - t.Run("scan with empty channel", 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{} - itemsIn := make(chan ScanItem) close(itemsIn) @@ -563,18 +562,107 @@ func TestScanDynamic(t *testing.T) { assert.NoError(t, err, "scanner encountered an error") assert.Equal(t, &reporting.Report{Results: map[string][]*secrets.Secret{}}, actualReport) }) + t.Run("scan more than 1 time using the same scanner instance", func(t *testing.T) { + 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, + }, + } + + // Create an input channel and feed it the scan items. + itemsIn1 := make(chan ScanItem, len(scanItems)) + itemsIn2 := make(chan ScanItem, len(scanItems)) + for _, item := range scanItems { + itemsIn1 <- item + itemsIn2 <- item + } + close(itemsIn1) + close(itemsIn2) + + testScanner := NewScanner() + + // scan 2 + actualReport, err := testScanner.ScanDynamic(itemsIn1, ScanConfig{}) + assert.NoError(t, err, "scanner encountered an error") + + expectedReportBytes, err := os.ReadFile(expectedReportPath) + 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) + + // scan 2 + actualReport, err = testScanner.ScanDynamic(itemsIn2, ScanConfig{ + IgnoreResultIds: []string{ + "a0cd293e6e122a1c7384d5a56781e39ba350c54b", + "40483a2b07fa3beaf234d1a0b5d0931d7b7ae9f7", + }, + }) + assert.NoError(t, err, "scanner encountered an error") + + expectedReportBytes, err = os.ReadFile(expectedReportResultsIgnoredResultsPath) + assert.NoError(t, err, "failed to read expected report file") + + 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) + }) } func TestScanWithValidation(t *testing.T) { t.Run("Successful Scan with Multiple Items", 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)