-
Notifications
You must be signed in to change notification settings - Fork 259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
loki.secretfilter: utilize fuzz testing for complex input #2630
base: main
Are you sure you want to change the base?
Changes from all commits
4bc2cdf
b30d3b7
e6fe5f9
9226aa1
4deb959
3c35f7f
91bbc36
af7887f
1040fd1
c6bc434
e4c0f52
68f6057
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -602,6 +602,133 @@ func runBenchmarks(b *testing.B, config string, percentageSecrets int, secretNam | |
} | ||
} | ||
|
||
var sampleFuzzLogLines = []string{ | ||
`key=value1,value2 log=fmt test=1 secret=password`, | ||
`{"key":["value1","value2"],"log":"fmt","test":1,"secret":"password"}`, | ||
`1970-01-01 00:00:00 pattern value1,value2 1 secret`, | ||
} | ||
|
||
func FuzzProcessEntry(f *testing.F) { | ||
for _, line := range sampleFuzzLogLines { | ||
f.Add(line) | ||
} | ||
for _, testLog := range testLogs { | ||
f.Add(testLog.log) | ||
} | ||
|
||
comps := make([]*Component, 0, len(testConfigs)) | ||
opts := component.Options{ | ||
Logger: util.TestLogger(f), | ||
OnStateChange: func(e component.Exports) {}, | ||
GetServiceData: getServiceData, | ||
} | ||
ch1 := loki.NewLogsReceiver() | ||
|
||
// Create components | ||
for _, config := range testConfigs { | ||
var args Arguments | ||
require.NoError(f, syntax.Unmarshal([]byte(config), &args)) | ||
if args.GitleaksConfig != "" { | ||
continue // Skip the configs using a custom gitleaks config file | ||
} | ||
|
||
args.ForwardTo = []loki.LogsReceiver{ch1} | ||
c, err := New(opts, args) | ||
require.NoError(f, err) | ||
comps = append(comps, c) | ||
} | ||
|
||
f.Fuzz(func(t *testing.T, log string) { | ||
for _, c := range comps { | ||
entry := loki.Entry{Labels: model.LabelSet{}, Entry: logproto.Entry{Timestamp: time.Now(), Line: log}} | ||
c.processEntry(entry) | ||
} | ||
}) | ||
} | ||
|
||
func FuzzConfig(f *testing.F) { | ||
for _, testConf := range testConfigs { | ||
for _, testLog := range testLogs { | ||
f.Add(testConf, testLog.log) | ||
} | ||
} | ||
opts := component.Options{ | ||
Logger: util.TestLogger(f), | ||
OnStateChange: func(e component.Exports) {}, | ||
GetServiceData: getServiceData, | ||
} | ||
ch1 := loki.NewLogsReceiver() | ||
|
||
f.Fuzz(func(t *testing.T, config string, log string) { | ||
var args Arguments | ||
err := syntax.Unmarshal([]byte(config), &args) | ||
if err != nil { | ||
// ignore parsing errors, as we aren't fuzz testing the Alloy config parser | ||
return | ||
} | ||
if args.GitleaksConfig != "" { | ||
return // Skip the configs that use a custom gitleaks config file | ||
} | ||
|
||
args.ForwardTo = []loki.LogsReceiver{ch1} | ||
c, err := New(opts, args) | ||
if err != nil { | ||
// ignore regex parsing errors | ||
if strings.HasPrefix(err.Error(), "error parsing regexp") { | ||
return | ||
} | ||
t.Errorf("error configuring component: %v", err) | ||
} | ||
|
||
entry := loki.Entry{Labels: model.LabelSet{}, Entry: logproto.Entry{Timestamp: time.Now(), Line: log}} | ||
c.processEntry(entry) | ||
}) | ||
} | ||
|
||
func FuzzGitleaksConfig(f *testing.F) { | ||
for _, testConf := range testConfigs { | ||
for _, testGitleaksConf := range customGitleaksConfig { | ||
for _, testLog := range testLogs { | ||
f.Add(testConf, testGitleaksConf, testLog.log) | ||
} | ||
} | ||
} | ||
opts := component.Options{ | ||
Logger: util.TestLogger(f), | ||
OnStateChange: func(e component.Exports) {}, | ||
GetServiceData: getServiceData, | ||
} | ||
ch1 := loki.NewLogsReceiver() | ||
|
||
f.Fuzz(func(t *testing.T, config string, gitleaksConfig string, log string) { | ||
var args Arguments | ||
err := syntax.Unmarshal([]byte(config), &args) | ||
if err != nil { | ||
// ignore parsing errors, as we aren't fuzz testing the Alloy config parser | ||
return | ||
} | ||
args.GitleaksConfig = createTempGitleaksConfig(t, gitleaksConfig) | ||
defer deleteTempGitLeaksConfig(t, args.GitleaksConfig) | ||
|
||
args.ForwardTo = []loki.LogsReceiver{ch1} | ||
c, err := New(opts, args) | ||
if err != nil { | ||
// ignore regex parsing errors - out of scope | ||
if strings.HasPrefix(err.Error(), "error parsing regexp") { | ||
return | ||
} | ||
// ignore toml parsing errors - out of scope | ||
if strings.HasPrefix(err.Error(), "toml:") { | ||
return | ||
} | ||
t.Errorf("error configuring component: %v", err) | ||
} | ||
|
||
entry := loki.Entry{Labels: model.LabelSet{}, Entry: logproto.Entry{Timestamp: time.Now(), Line: log}} | ||
c.processEntry(entry) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we not also check the output on |
||
}) | ||
} | ||
|
||
func getServiceData(name string) (interface{}, error) { | ||
switch name { | ||
case livedebugging.ServiceName: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
go test fuzz v1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure if these are needed, and would be happy to hear other reviewers' opinions. I guess including them as test cases are enough. |
||
string("forward_to=[]") | ||
string("\n\t\ttitle = \"gitleaks custom config\"\n\n\t\t[[rules]]\n\t\tid = \"my-fake-secret\"\n\t\tdescription = \"Identified a fake secret\"\n\t\t") | ||
string("{\n\t\t\t\"message\": \"This is a simple log message with a secret value AIzaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA !\n\t\t}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
go test fuzz v1 | ||
string("\n\t\tforward_to = []\n\t\tredact_with = \"<ALLOY-REDACTED-SECR<ALLOY-ET:$SECRET_NAME>\"\n\t") | ||
string("\n\t\ttitle = \"gitleaks custom config\"\n\n\t\t[[rules]]\n\t\tid = \"my-fake-secret\"\n\t\tdescription = \"Identified a fake secret\"\n\t\tregex = '''(?i)\\b(fakeSecret\\d\", \"faiption ='|\\\"|\\n|\\r||;]|$)'''\t\n\t\t[allowlist]\n\t\tregexes = [\"abc\\\\d{3}\", \"fakeSecret[9]{5}\"]\n\t") | ||
Comment on lines
+2
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm new to fuzz testing - what sorts of variations of these configs is Go actually going to come up with? E.g. if it just puts in some random malformed string as a config, how do we know we should reject it? And even for secrets, how can we make sure in our test that we filter the secrets we want to filter? |
||
string("{\n\t\t\t\"message\": \"This is a simple log message with a secret value fakeSecret12345 !\n\t\t}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
go test fuzz v1 | ||
string("forward_to=[]") | ||
string("[[rules]]\nd=\"\"\ne=\"\"\nregex='''()'''\n[[rules.allowlista]]\ns=[\"\\\\\",\"\\\\\"]\n[[rules.allowlists]]\nregexes=[\"\\\\{\",\"]\"\"") | ||
string("{\n\t\t\t\"message\": \"This is a simple log message with a secret value eyJrIjoiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA and another secret value AIzaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA !\n\t\t}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if we're not fuzz testing the config parser, wouldn't we still want to know if this fails? Presumably it should succeed so that we can test other code? And if it fails silently, it could mean the fuzz tests didn't really run?
I guess that
testConfigs
contains some invalid configurations and we want to ignore them, but wouldn't it be cleaner to only have valid configs as input and to not haveconfig
as an input tof.Fuzz
?