Skip to content

Commit 1d848c7

Browse files
add limits fields to scan config
1 parent db73484 commit 1d848c7

3 files changed

Lines changed: 219 additions & 5 deletions

File tree

internal/resources/scanner.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@ type ScanConfig struct {
99
CustomRules []*ruledefine.Rule
1010
WithValidation bool
1111
PluginName string
12+
13+
// Limit settings
14+
MaxFindings uint64 // Total findings limit across entire scan (0 = no limit)
15+
MaxRuleMatchesPerFragment uint64 // Regex matches limit per rule per fragment (0 = no limit)
16+
MaxSecretSize uint64 // Maximum secret size in bytes (0 = no limit)
1217
}

pkg/scan.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ func (s *scanner) Reset(scanConfig resources.ScanConfig, opts ...engine.EngineOp
3838
defer s.mu.Unlock()
3939

4040
engineInstance, err := engine.Init(&engine.EngineConfig{
41-
IgnoredIds: scanConfig.IgnoreResultIds,
42-
SelectedList: scanConfig.SelectRules,
43-
CustomRules: scanConfig.CustomRules,
44-
IgnoreList: scanConfig.IgnoreRules,
45-
ScanConfig: scanConfig,
41+
IgnoredIds: scanConfig.IgnoreResultIds,
42+
SelectedList: scanConfig.SelectRules,
43+
CustomRules: scanConfig.CustomRules,
44+
IgnoreList: scanConfig.IgnoreRules,
45+
MaxFindings: scanConfig.MaxFindings,
46+
MaxRuleMatchesPerFragment: scanConfig.MaxRuleMatchesPerFragment,
47+
MaxSecretSize: scanConfig.MaxSecretSize,
48+
ScanConfig: scanConfig,
4649
}, opts...)
4750
if err != nil {
4851
return fmt.Errorf("error initializing engine: %w", err)

pkg/scan_test.go

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,212 @@ func compareOrUpdateTestData(t *testing.T, actualReport reporting.IReport, expec
10291029
assert.EqualValues(t, normalizedExpectedReport, normalizedActualReport)
10301030
}
10311031

1032+
func TestScan_LimitSettings(t *testing.T) {
1033+
// Load test data once for all subtests
1034+
githubPatBytes, err := os.ReadFile(githubPatPath)
1035+
assert.NoError(t, err, "failed to read github-pat file")
1036+
githubPatContent := string(githubPatBytes)
1037+
1038+
jwtBytes, err := os.ReadFile(jwtPath)
1039+
assert.NoError(t, err, "failed to read jwt file")
1040+
jwtContent := string(jwtBytes)
1041+
1042+
genericKeysBytes, err := os.ReadFile(genericKeysPath)
1043+
assert.NoError(t, err, "failed to read generic-api-keys file")
1044+
genericKeysContent := string(genericKeysBytes)
1045+
1046+
tests := []struct {
1047+
name string
1048+
filePaths []string
1049+
maxFindings uint64
1050+
maxRuleMatchesPerFragment uint64
1051+
maxSecretSize uint64
1052+
expectedMaxFindings int
1053+
expectedMaxSecretSize int
1054+
}{
1055+
{
1056+
name: "MaxFindings limits total secrets found",
1057+
filePaths: []string{githubPatPath, jwtPath, genericKeysPath},
1058+
maxFindings: 2,
1059+
maxRuleMatchesPerFragment: 0,
1060+
maxSecretSize: 0,
1061+
expectedMaxFindings: 2,
1062+
expectedMaxSecretSize: 1000,
1063+
},
1064+
{
1065+
name: "MaxRuleMatchesPerFragment limits matches per rule per fragment",
1066+
filePaths: []string{githubPatPath},
1067+
maxFindings: 0,
1068+
maxRuleMatchesPerFragment: 1,
1069+
maxSecretSize: 0,
1070+
expectedMaxFindings: 2,
1071+
expectedMaxSecretSize: 1000,
1072+
},
1073+
{
1074+
name: "MaxSecretSize filters out large secrets",
1075+
filePaths: []string{jwtPath, githubPatPath},
1076+
maxFindings: 0,
1077+
maxRuleMatchesPerFragment: 0,
1078+
maxSecretSize: 50,
1079+
expectedMaxFindings: 100,
1080+
expectedMaxSecretSize: 50,
1081+
},
1082+
{
1083+
name: "All limit settings work together",
1084+
filePaths: []string{githubPatPath, jwtPath, genericKeysPath},
1085+
maxFindings: 3,
1086+
maxRuleMatchesPerFragment: 1,
1087+
maxSecretSize: 100,
1088+
expectedMaxFindings: 3,
1089+
expectedMaxSecretSize: 100,
1090+
},
1091+
}
1092+
1093+
// Map file paths to content
1094+
contentMap := map[string]*string{
1095+
githubPatPath: &githubPatContent,
1096+
jwtPath: &jwtContent,
1097+
genericKeysPath: &genericKeysContent,
1098+
}
1099+
1100+
for _, tt := range tests {
1101+
t.Run(tt.name, func(t *testing.T) {
1102+
scanItems := make([]ScanItem, 0, len(tt.filePaths))
1103+
for _, path := range tt.filePaths {
1104+
scanItems = append(scanItems, ScanItem{
1105+
Content: contentMap[path],
1106+
ID: fmt.Sprintf("mock-%s", path),
1107+
Source: path,
1108+
})
1109+
}
1110+
1111+
testScanner := NewScanner()
1112+
actualReport, err := testScanner.Scan(scanItems, resources.ScanConfig{
1113+
MaxFindings: tt.maxFindings,
1114+
MaxRuleMatchesPerFragment: tt.maxRuleMatchesPerFragment,
1115+
MaxSecretSize: tt.maxSecretSize,
1116+
})
1117+
assert.NoError(t, err, "scanner encountered an error")
1118+
1119+
totalSecrets := actualReport.GetTotalSecretsFound()
1120+
assert.LessOrEqual(t, totalSecrets, tt.expectedMaxFindings, "total secrets should respect max findings limit")
1121+
1122+
results := actualReport.GetResults()
1123+
for _, secretsList := range results {
1124+
for _, secret := range secretsList {
1125+
assert.LessOrEqual(t, len(secret.Value), tt.expectedMaxSecretSize, "secret value exceeds max size")
1126+
}
1127+
}
1128+
})
1129+
}
1130+
}
1131+
1132+
func TestScanDynamic_LimitSettings(t *testing.T) {
1133+
// Load test data once for all subtests
1134+
githubPatBytes, err := os.ReadFile(githubPatPath)
1135+
assert.NoError(t, err, "failed to read github-pat file")
1136+
githubPatContent := string(githubPatBytes)
1137+
1138+
jwtBytes, err := os.ReadFile(jwtPath)
1139+
assert.NoError(t, err, "failed to read jwt file")
1140+
jwtContent := string(jwtBytes)
1141+
1142+
genericKeysBytes, err := os.ReadFile(genericKeysPath)
1143+
assert.NoError(t, err, "failed to read generic-api-keys file")
1144+
genericKeysContent := string(genericKeysBytes)
1145+
1146+
tests := []struct {
1147+
name string
1148+
filePaths []string
1149+
maxFindings uint64
1150+
maxRuleMatchesPerFragment uint64
1151+
maxSecretSize uint64
1152+
expectedMaxFindings int
1153+
expectedMaxSecretSize int
1154+
}{
1155+
{
1156+
name: "MaxFindings limits total secrets found",
1157+
filePaths: []string{githubPatPath, jwtPath, genericKeysPath},
1158+
maxFindings: 2,
1159+
maxRuleMatchesPerFragment: 0,
1160+
maxSecretSize: 0,
1161+
expectedMaxFindings: 2,
1162+
expectedMaxSecretSize: 1000,
1163+
},
1164+
{
1165+
name: "MaxRuleMatchesPerFragment limits matches per rule per fragment",
1166+
filePaths: []string{githubPatPath},
1167+
maxFindings: 0,
1168+
maxRuleMatchesPerFragment: 1,
1169+
maxSecretSize: 0,
1170+
expectedMaxFindings: 2,
1171+
expectedMaxSecretSize: 1000,
1172+
},
1173+
{
1174+
name: "MaxSecretSize filters out large secrets",
1175+
filePaths: []string{jwtPath, githubPatPath},
1176+
maxFindings: 0,
1177+
maxRuleMatchesPerFragment: 0,
1178+
maxSecretSize: 50,
1179+
expectedMaxFindings: 100,
1180+
expectedMaxSecretSize: 50,
1181+
},
1182+
{
1183+
name: "All limit settings work together",
1184+
filePaths: []string{githubPatPath, jwtPath, genericKeysPath},
1185+
maxFindings: 3,
1186+
maxRuleMatchesPerFragment: 1,
1187+
maxSecretSize: 100,
1188+
expectedMaxFindings: 3,
1189+
expectedMaxSecretSize: 100,
1190+
},
1191+
}
1192+
1193+
// Map file paths to content
1194+
contentMap := map[string]*string{
1195+
githubPatPath: &githubPatContent,
1196+
jwtPath: &jwtContent,
1197+
genericKeysPath: &genericKeysContent,
1198+
}
1199+
1200+
for _, tt := range tests {
1201+
t.Run(tt.name, func(t *testing.T) {
1202+
scanItems := make([]ScanItem, 0, len(tt.filePaths))
1203+
for _, path := range tt.filePaths {
1204+
scanItems = append(scanItems, ScanItem{
1205+
Content: contentMap[path],
1206+
ID: fmt.Sprintf("mock-%s", path),
1207+
Source: path,
1208+
})
1209+
}
1210+
1211+
itemsIn := make(chan ScanItem, len(scanItems))
1212+
for _, item := range scanItems {
1213+
itemsIn <- item
1214+
}
1215+
close(itemsIn)
1216+
1217+
testScanner := NewScanner()
1218+
actualReport, err := testScanner.ScanDynamic(itemsIn, resources.ScanConfig{
1219+
MaxFindings: tt.maxFindings,
1220+
MaxRuleMatchesPerFragment: tt.maxRuleMatchesPerFragment,
1221+
MaxSecretSize: tt.maxSecretSize,
1222+
})
1223+
assert.NoError(t, err, "scanner encountered an error")
1224+
1225+
totalSecrets := actualReport.GetTotalSecretsFound()
1226+
assert.LessOrEqual(t, totalSecrets, tt.expectedMaxFindings, "total secrets should respect max findings limit")
1227+
1228+
results := actualReport.GetResults()
1229+
for _, secretsList := range results {
1230+
for _, secret := range secretsList {
1231+
assert.LessOrEqual(t, len(secret.Value), tt.expectedMaxSecretSize, "secret value exceeds max size")
1232+
}
1233+
}
1234+
})
1235+
}
1236+
}
1237+
10321238
func cloneRules(rulesToClone []*ruledefine.Rule) []*ruledefine.Rule {
10331239
clonedRules := make([]*ruledefine.Rule, 0, len(rulesToClone))
10341240
for _, rule := range rulesToClone {

0 commit comments

Comments
 (0)