Skip to content

Commit be5ad6f

Browse files
feat: add ignore rules to scan config from scanner interface (#294)
1 parent 1583adc commit be5ad6f

File tree

4 files changed

+218
-9
lines changed

4 files changed

+218
-9
lines changed

.2ms.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,8 @@ ignore-result:
8989
- 777f3d460d69a70e2ce760ca757b18f2aa984392 # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10
9090
- e392318c730d4cd0a04340f1e3d41d4c61f6eb20 # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10
9191
- 8f0e0442b01c18b02cfb8e59555103f8233fc7bf # value used for testing, found at https://github.com/Checkmarx/2ms/commit/07aab5bb214c03fd9e75e46cebe2b407c88d4f73/reporting/report_test.go#diff-31d71ec2c2ba169dce79b1c2de097e30b43f1695ce364054ee7d6b33896c7040R10
92-
- 353627158f2e7fa5bb60271cee17da80e5fbba17 # value used as true positive, found at https://github.com/Checkmarx/2ms/pull/292/commits/cc44c8f8bee92250bdcd69bf9fbaffabf0eb442a
92+
- 353627158f2e7fa5bb60271cee17da80e5fbba17 # value used as true positive, found at https://github.com/Checkmarx/2ms/pull/292/commits/cc44c8f8bee92250bdcd69bf9fbaffabf0eb442a
93+
- bf9302d29d7167f39041b0561ae9d1d3677faa2f # value used for testing
94+
- 44912790c892213daa0df821a006e1e1659e6e24 # value used for testing
95+
- ac3704513c4ab9bde3fa3539b14152c95ba5698f # value used for testing
96+
- ac2d6adbeca8901c1655bcf3e0eac027ca681825 # value used for testing

pkg/scan.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
type ScanConfig struct {
1414
IgnoreResultIds []string
15+
IgnoreRules []string
1516
}
1617

1718
type scanner struct{}
@@ -37,7 +38,7 @@ func (s *scanner) Scan(scanItems []ScanItem, scanConfig ScanConfig) (*reporting.
3738
}()
3839

3940
// Initialize engine configuration
40-
engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds}
41+
engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules}
4142
engineInstance, err := engine.Init(engineConfig)
4243
if err != nil {
4344
return &reporting.Report{}, fmt.Errorf("error initializing engine: %w", err)
@@ -93,7 +94,7 @@ func (s *scanner) ScanDynamic(itemsIn <-chan ScanItem, scanConfig ScanConfig) (*
9394
errorsCh := cmd.Channels.Errors
9495

9596
// Initialize engine configuration.
96-
engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds}
97+
engineConfig := engine.EngineConfig{IgnoredIds: scanConfig.IgnoreResultIds, IgnoreList: scanConfig.IgnoreRules}
9798
engineInstance, err := engine.Init(engineConfig)
9899
if err != nil {
99100
return &reporting.Report{}, fmt.Errorf("error initializing engine: %w", err)

pkg/scan_test.go

Lines changed: 148 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import (
1616
)
1717

1818
const (
19-
githubPatPath = "testData/secrets/github-pat.txt"
20-
jwtPath = "testData/secrets/jwt.txt"
21-
expectedReportPath = "testData/expectedReport.json"
22-
expectedReportResultsIgnoredPath = "testData/expectedReportWithIgnoredResults.json"
19+
githubPatPath = "testData/secrets/github-pat.txt"
20+
jwtPath = "testData/secrets/jwt.txt"
21+
expectedReportPath = "testData/expectedReport.json"
22+
expectedReportResultsIgnoredResultsPath = "testData/expectedReportWithIgnoredResults.json"
23+
expectedReportResultsIgnoredRulePath = "testData/expectedReportWithIgnoredRule.json"
2324
)
2425

2526
func TestScan(t *testing.T) {
@@ -135,7 +136,74 @@ func TestScan(t *testing.T) {
135136
})
136137
assert.NoError(t, err, "scanner encountered an error")
137138

138-
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredPath)
139+
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredResultsPath)
140+
assert.NoError(t, err, "failed to read expected report file")
141+
142+
var expectedReport, actualReportMap map[string]interface{}
143+
144+
err = json.Unmarshal(expectedReportBytes, &expectedReport)
145+
assert.NoError(t, err, "failed to unmarshal expected report JSON")
146+
147+
actualReportBytes, err := json.Marshal(actualReport)
148+
assert.NoError(t, err, "failed to marshal actual report to JSON")
149+
err = json.Unmarshal(actualReportBytes, &actualReportMap)
150+
assert.NoError(t, err, "failed to unmarshal actual report JSON")
151+
152+
normalizedExpectedReport, err := utils.NormalizeReportData(expectedReport)
153+
assert.NoError(t, err, "Failed to normalize actual report")
154+
155+
normalizedActualReport, err := utils.NormalizeReportData(actualReportMap)
156+
assert.NoError(t, err, "Failed to normalize actual report")
157+
158+
assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport)
159+
})
160+
t.Run("Successful scan with multiple items and ignored rule", func(t *testing.T) {
161+
cmd.Report = reporting.Init()
162+
cmd.SecretsChan = make(chan *secrets.Secret)
163+
cmd.SecretsExtrasChan = make(chan *secrets.Secret)
164+
cmd.ValidationChan = make(chan *secrets.Secret)
165+
cmd.CvssScoreWithoutValidationChan = make(chan *secrets.Secret)
166+
cmd.Channels.Items = make(chan plugins.ISourceItem)
167+
cmd.Channels.Errors = make(chan error)
168+
169+
githubPatBytes, err := os.ReadFile(githubPatPath)
170+
assert.NoError(t, err, "failed to read github-pat file")
171+
githubPatContent := string(githubPatBytes)
172+
173+
jwtBytes, err := os.ReadFile(jwtPath)
174+
assert.NoError(t, err, "failed to read jwt file")
175+
jwtContent := string(jwtBytes)
176+
177+
emptyContent := ""
178+
emptyMockPath := "mockPath"
179+
180+
scanItems := []ScanItem{
181+
{
182+
Content: &githubPatContent,
183+
ID: fmt.Sprintf("mock-%s", githubPatPath),
184+
Source: githubPatPath,
185+
},
186+
{
187+
Content: &emptyContent,
188+
ID: fmt.Sprintf("mock-%s", emptyMockPath),
189+
Source: emptyMockPath,
190+
},
191+
{
192+
Content: &jwtContent,
193+
ID: fmt.Sprintf("mock-%s", jwtPath),
194+
Source: jwtPath,
195+
},
196+
}
197+
198+
testScanner := NewScanner()
199+
actualReport, err := testScanner.Scan(scanItems, ScanConfig{
200+
IgnoreRules: []string{
201+
"github-pat",
202+
},
203+
})
204+
assert.NoError(t, err, "scanner encountered an error")
205+
206+
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredRulePath)
139207
assert.NoError(t, err, "failed to read expected report file")
140208

141209
var expectedReport, actualReportMap map[string]interface{}
@@ -352,7 +420,7 @@ func TestScanDynamic(t *testing.T) {
352420
})
353421
assert.NoError(t, err, "scanner encountered an error")
354422

355-
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredPath)
423+
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredResultsPath)
356424
assert.NoError(t, err, "failed to read expected report file")
357425

358426
var expectedReport, actualReportMap map[string]interface{}
@@ -374,7 +442,81 @@ func TestScanDynamic(t *testing.T) {
374442

375443
assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport)
376444
})
445+
t.Run("Successful ScanDynamic with Multiple Items and Ignored Rule", func(t *testing.T) {
446+
cmd.Report = reporting.Init()
447+
cmd.SecretsChan = make(chan *secrets.Secret)
448+
cmd.SecretsExtrasChan = make(chan *secrets.Secret)
449+
cmd.ValidationChan = make(chan *secrets.Secret)
450+
cmd.CvssScoreWithoutValidationChan = make(chan *secrets.Secret)
451+
cmd.Channels.Items = make(chan plugins.ISourceItem)
452+
cmd.Channels.Errors = make(chan error)
453+
cmd.Channels.WaitGroup = &sync.WaitGroup{}
454+
455+
githubPatBytes, err := os.ReadFile(githubPatPath)
456+
assert.NoError(t, err, "failed to read github-pat file")
457+
githubPatContent := string(githubPatBytes)
458+
459+
jwtBytes, err := os.ReadFile(jwtPath)
460+
assert.NoError(t, err, "failed to read jwt file")
461+
jwtContent := string(jwtBytes)
462+
463+
emptyContent := ""
464+
emptyMockPath := "mockPath"
465+
466+
scanItems := []ScanItem{
467+
{
468+
Content: &githubPatContent,
469+
ID: fmt.Sprintf("mock-%s", githubPatPath),
470+
Source: githubPatPath,
471+
},
472+
{
473+
Content: &emptyContent,
474+
ID: fmt.Sprintf("mock-%s", emptyMockPath),
475+
Source: emptyMockPath,
476+
},
477+
{
478+
Content: &jwtContent,
479+
ID: fmt.Sprintf("mock-%s", jwtPath),
480+
Source: jwtPath,
481+
},
482+
}
377483

484+
itemsIn := make(chan ScanItem, len(scanItems))
485+
for _, item := range scanItems {
486+
itemsIn <- item
487+
}
488+
close(itemsIn)
489+
490+
testScanner := NewScanner()
491+
actualReport, err := testScanner.ScanDynamic(itemsIn, ScanConfig{
492+
IgnoreRules: []string{
493+
"github-pat",
494+
},
495+
})
496+
assert.NoError(t, err, "scanner encountered an error")
497+
498+
expectedReportBytes, err := os.ReadFile(expectedReportResultsIgnoredRulePath)
499+
assert.NoError(t, err, "failed to read expected report file")
500+
501+
var expectedReport, actualReportMap map[string]interface{}
502+
503+
err = json.Unmarshal(expectedReportBytes, &expectedReport)
504+
assert.NoError(t, err, "failed to unmarshal expected report JSON")
505+
506+
actualReportBytes, err := json.Marshal(actualReport)
507+
assert.NoError(t, err, "failed to marshal actual report to JSON")
508+
err = json.Unmarshal(actualReportBytes, &actualReportMap)
509+
assert.NoError(t, err, "failed to unmarshal actual report JSON")
510+
511+
// Normalize both maps.
512+
normalizedExpectedReport, err := utils.NormalizeReportData(expectedReport)
513+
assert.NoError(t, err, "Failed to normalize actual report")
514+
515+
normalizedActualReport, err := utils.NormalizeReportData(actualReportMap)
516+
assert.NoError(t, err, "Failed to normalize actual report")
517+
518+
assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport)
519+
})
378520
t.Run("error handling should work", func(t *testing.T) {
379521
cmd.Report = reporting.Init()
380522
cmd.SecretsChan = make(chan *secrets.Secret)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"totalItemsScanned" : 3,
3+
"totalSecretsFound" : 3,
4+
"results" : {
5+
"a0cd293e6e122a1c7384d5a56781e39ba350c54b" : [ {
6+
"id" : "a0cd293e6e122a1c7384d5a56781e39ba350c54b",
7+
"source" : "testData/secrets/jwt.txt",
8+
"ruleId" : "jwt",
9+
"startLine" : 0,
10+
"endLine" : 0,
11+
"lineContent" : "TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1 TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2 TextExample\r",
12+
"startColumn" : 129,
13+
"endColumn" : 232,
14+
"value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2",
15+
"ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.",
16+
"extraDetails" : {
17+
"secretDetails" : {
18+
"name" : "mockName2",
19+
"sub" : "mockSub2"
20+
}
21+
},
22+
"cvssScore" : 8.2
23+
}, {
24+
"id" : "a0cd293e6e122a1c7384d5a56781e39ba350c54b",
25+
"source" : "testData/secrets/jwt.txt",
26+
"ruleId" : "jwt",
27+
"startLine" : 1,
28+
"endLine" : 1,
29+
"lineContent": "\n Text_Example = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2",
30+
"startColumn" : 64,
31+
"endColumn" : 167,
32+
"value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2",
33+
"ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.",
34+
"extraDetails" : {
35+
"secretDetails" : {
36+
"name" : "mockName2",
37+
"sub" : "mockSub2"
38+
}
39+
},
40+
"cvssScore" : 8.2
41+
} ],
42+
"f29abe9eacc233a8e5e9c7762bca48589d9c76a2" : [ {
43+
"id" : "f29abe9eacc233a8e5e9c7762bca48589d9c76a2",
44+
"source" : "testData/secrets/jwt.txt",
45+
"ruleId" : "jwt",
46+
"startLine" : 0,
47+
"endLine" : 0,
48+
"lineContent" : "TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1 TextExample eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMiIsIm5hbWUiOiJtb2NrTmFtZTIifQ.dummysignature2 TextExample\r",
49+
"startColumn" : 13,
50+
"endColumn" : 116,
51+
"value" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtb2NrU3ViMSIsIm5hbWUiOiJtb2NrTmFtZTEifQ.dummysignature1",
52+
"ruleDescription" : "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.",
53+
"extraDetails" : {
54+
"secretDetails" : {
55+
"name" : "mockName1",
56+
"sub" : "mockSub1"
57+
}
58+
},
59+
"cvssScore" : 8.2
60+
} ]
61+
}
62+
}

0 commit comments

Comments
 (0)