-
Notifications
You must be signed in to change notification settings - Fork 30
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
fix: flaky results: same start and end marker #413
base: main
Are you sure you want to change the base?
Changes from all commits
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 | ||||
---|---|---|---|---|---|---|
|
@@ -22,6 +22,13 @@ import ( | |||||
"github.com/coreruleset/go-ftw/waflog" | ||||||
) | ||||||
|
||||||
const ( | ||||||
// start and end UUID suffixes are used to disambiguate start and end markers. | ||||||
// It permits to make the markers unique, while still maintaining one UUID per stage. | ||||||
startUUIDSuffix = "-s" | ||||||
endUUIDSuffix = "-e" | ||||||
) | ||||||
|
||||||
// Run runs your tests with the specified Config. | ||||||
func Run(cfg *config.FTWConfiguration, tests []*test.FTWTest, c RunnerConfig, out *output.Output) (*TestRunContext, error) { | ||||||
out.Println("%s", out.Message("** Running go-ftw!")) | ||||||
|
@@ -166,7 +173,8 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase sch | |||||
} | ||||||
|
||||||
if notRunningInCloudMode(ftwCheck) { | ||||||
startMarker, err := markAndFlush(runContext, &testInput, stageId) | ||||||
startUUID := stageId + startUUIDSuffix | ||||||
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.
Suggested change
|
||||||
startMarker, err := markAndFlush(runContext, &testInput, startUUID) | ||||||
if err != nil && !expectErr { | ||||||
return fmt.Errorf("failed to find start marker: %w", err) | ||||||
} | ||||||
|
@@ -190,7 +198,8 @@ func RunStage(runContext *TestRunContext, ftwCheck *check.FTWCheck, testCase sch | |||||
} | ||||||
|
||||||
if notRunningInCloudMode(ftwCheck) { | ||||||
endMarker, err := markAndFlush(runContext, &testInput, stageId) | ||||||
endUUID := stageId + endUUIDSuffix | ||||||
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.
Suggested change
|
||||||
endMarker, err := markAndFlush(runContext, &testInput, endUUID) | ||||||
if err != nil && !expectErr { | ||||||
return fmt.Errorf("failed to find end marker: %w", err) | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -135,6 +135,10 @@ func (ll *FTWLogLines) getMarkedLines() [][]byte { | |||||||
log.Fatal().Msg("Both start and end marker must be set before the log can be inspected") | ||||||||
} | ||||||||
|
||||||||
if bytes.Equal(ll.startMarker, ll.endMarker) { | ||||||||
log.Fatal().Msg("Start and end markers must be different") | ||||||||
} | ||||||||
|
||||||||
fi, err := ll.logFile.Stat() | ||||||||
if err != nil { | ||||||||
log.Error().Caller().Msgf("cannot read file's size") | ||||||||
|
@@ -146,6 +150,7 @@ func (ll *FTWLogLines) getMarkedLines() [][]byte { | |||||||
ChunkSize: 4096, | ||||||||
} | ||||||||
scanner := backscanner.NewOptions(ll.logFile, int(fi.Size()), backscannerOptions) | ||||||||
startFound := false | ||||||||
endFound := false | ||||||||
// end marker is the *first* marker when reading backwards, | ||||||||
// start marker is the *last* marker | ||||||||
|
@@ -158,24 +163,34 @@ func (ll *FTWLogLines) getMarkedLines() [][]byte { | |||||||
break | ||||||||
} | ||||||||
lineLower := bytes.ToLower(line) | ||||||||
if !endFound && bytes.Equal(lineLower, ll.endMarker) { | ||||||||
endFound = true | ||||||||
|
||||||||
if !endFound { | ||||||||
// Skip lines until we find the end marker. Reading backwards, the line we are looking for are | ||||||||
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.
Suggested change
|
||||||||
// between the end and start markers. | ||||||||
if bytes.Equal(lineLower, ll.endMarker) { | ||||||||
endFound = true | ||||||||
} | ||||||||
continue | ||||||||
} | ||||||||
if endFound && bytes.Equal(lineLower, ll.startMarker) { | ||||||||
startFound = true | ||||||||
break | ||||||||
} | ||||||||
|
||||||||
saneCopy := make([]byte, len(line)) | ||||||||
copy(saneCopy, line) | ||||||||
ll.markedLines = append(ll.markedLines, saneCopy) | ||||||||
} | ||||||||
if !startFound { | ||||||||
log.Debug().Msgf("starter marker not found while getting marked lines") | ||||||||
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.
Suggested change
|
||||||||
} | ||||||||
|
||||||||
return ll.markedLines | ||||||||
} | ||||||||
|
||||||||
// CheckLogForMarker reads the log file and searches for a marker line. | ||||||||
// stageID is the ID of the current stage, which is part of the marker line | ||||||||
// At this point, stageID includes also the start or end suffix. | ||||||||
Comment on lines
192
to
+193
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.
Suggested change
|
||||||||
// readLimit is the maximum numbers of lines to check | ||||||||
func (ll *FTWLogLines) CheckLogForMarker(stageID string, readLimit uint) []byte { | ||||||||
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.
Suggested change
|
||||||||
offset, err := ll.logFile.Seek(0, io.SeekEnd) | ||||||||
|
@@ -223,7 +238,6 @@ func (ll *FTWLogLines) CheckLogForMarker(stageID string, readLimit uint) []byte | |||||||
if bytes.Contains(line, stageIDBytes) { | ||||||||
return line | ||||||||
} | ||||||||
|
||||||||
log.Debug().Msgf("found unexpected marker line while looking for %s: %s", stageID, line) | ||||||||
return nil | ||||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -148,7 +148,7 @@ func (s *readTestSuite) TestReadGetMarkedLinesWithTrailingEmptyLines() { | |||||
foundLines[i], foundLines[j] = foundLines[j], foundLines[i] | ||||||
} | ||||||
|
||||||
s.Len(foundLines, 6, "found unexpected number of log lines") | ||||||
s.Len(foundLines, 3, "found unexpected number of log lines") | ||||||
|
||||||
for index, line := range strings.Split(logLinesOnly, "\n") { | ||||||
s.Equalf(foundLines[index], []byte(line), "log lines don't match: \n%s\n%s", line, string(foundLines[index])) | ||||||
|
@@ -188,7 +188,7 @@ func (s *readTestSuite) TestReadGetMarkedLinesWithPrecedingLines() { | |||||
foundLines[i], foundLines[j] = foundLines[j], foundLines[i] | ||||||
} | ||||||
|
||||||
s.Len(foundLines, 4, "found unexpected number of log lines") | ||||||
s.Len(foundLines, 3, "found unexpected number of log lines") | ||||||
|
||||||
for index, line := range strings.Split(logLinesOnly, "\n") { | ||||||
s.Equalf(foundLines[index], []byte(line), "log lines don't match: \n%s\n%s", line, string(foundLines[index])) | ||||||
|
@@ -201,12 +201,15 @@ func (s *readTestSuite) TestFTWLogLines_Contains() { | |||||
s.NotNil(cfg) | ||||||
|
||||||
stageID := "dead-beaf-deadbeef-deadbeef-dead" | ||||||
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.
Suggested change
|
||||||
markerLine := "X-cRs-TeSt: " + stageID | ||||||
logLines := ` | ||||||
markerLineStart := "X-cRs-TeSt: " + stageID + "-s" | ||||||
markerLineEnd := "X-cRs-TeSt: " + stageID + "-e" | ||||||
logLines := | ||||||
markerLineStart + | ||||||
` | ||||||
[Tue Jan 05 02:21:09.637165 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Pattern match "\\\\b(?:keep-alive|close),\\\\s?(?:keep-alive|close)\\\\b" at REQUEST_HEADERS:Connection. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "339"] [id "920210"] [msg "Multiple/Conflicting Connection Header Data Found"] [data "close,close"] [severity "WARNING"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"] | ||||||
[Tue Jan 05 02:21:09.637731 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Match of "pm AppleWebKit Android" against "REQUEST_HEADERS:User-Agent" required. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "1230"] [id "920300"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [tag "PCI/6.5.10"] [tag "paranoia-level/2"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"] | ||||||
[Tue Jan 05 02:21:09.638572 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Operator GE matched 5 at TX:anomaly_score. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "91"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"] | ||||||
` + markerLine | ||||||
` + markerLineEnd | ||||||
s.filename, err = utils.CreateTempFileWithContent(logLines, "test-errorlog-") | ||||||
s.Require().NoError(err) | ||||||
|
||||||
|
@@ -223,8 +226,8 @@ func (s *readTestSuite) TestFTWLogLines_Contains() { | |||||
f := fields{ | ||||||
logFile: log, | ||||||
LogMarkerHeaderName: []byte(cfg.LogMarkerHeaderName), | ||||||
StartMarker: []byte(markerLine), | ||||||
EndMarker: []byte(markerLine), | ||||||
StartMarker: []byte(markerLineStart), | ||||||
EndMarker: []byte(markerLineEnd), | ||||||
} | ||||||
|
||||||
type args struct { | ||||||
|
@@ -273,13 +276,16 @@ func (s *readTestSuite) TestFTWLogLines_ContainsIn404() { | |||||
s.NotNil(cfg) | ||||||
|
||||||
stageID := "dead-beaf-deadbeef-deadbeef-dead" | ||||||
markerLine := fmt.Sprint(`[2022-11-12 23:08:18.012572] [-:error] 127.0.0.1:36126 Y3AZUo3Gja4gB-tPE9uasgAAAA4 [client 127.0.0.1] ModSecurity: Warning. Unconditional match in SecAction. [file "/apache/conf/httpd.conf_pod_2022-11-12_22:23"] [line "265"] [id "999999"] [msg "`, | ||||||
"X-cRs-TeSt ", stageID, | ||||||
markerLineStart := fmt.Sprint(`[2022-11-12 23:08:18.012572] [-:error] 127.0.0.1:36126 Y3AZUo3Gja4gB-tPE9uasgAAAA4 [client 127.0.0.1] ModSecurity: Warning. Unconditional match in SecAction. [file "/apache/conf/httpd.conf_pod_2022-11-12_22:23"] [line "265"] [id "999999"] [msg "`, | ||||||
"X-cRs-TeSt ", stageID+"-s", | ||||||
`"] [hostname "localhost"] [uri "/status/200"] [unique_id "Y3AZUo3Gja4gB-tPE9uasgAAAA4"]`) | ||||||
logLines := fmt.Sprint("\n", markerLine, | ||||||
markerLineEnd := fmt.Sprint(`[2022-11-12 23:08:18.012580] [-:error] 127.0.0.1:36126 Y3AZUo3Gja4gB-tPE9uasgAAAA4 [client 127.0.0.1] ModSecurity: Warning. Unconditional match in SecAction. [file "/apache/conf/httpd.conf_pod_2022-11-12_22:23"] [line "265"] [id "999999"] [msg "`, | ||||||
"X-cRs-TeSt ", stageID+"-e", | ||||||
`"] [hostname "localhost"] [uri "/status/200"] [unique_id "Y3AZUo3Gja4gB-tPE9uasgBBBB4"]`) | ||||||
logLines := fmt.Sprint("\n", markerLineStart, | ||||||
`[Tue Jan 05 02:21:09.637165 2021] [:error] [pid 76:tid 139683434571520] [client 172.23.0.1:58998] [client 172.23.0.1] ModSecurity: Warning. Pattern match "\\\\b(?:keep-alive|close),\\\\s?(?:keep-alive|close)\\\\b" at REQUEST_HEADERS:Connection. [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "339"] [id "920210"] [msg "Multiple/Conflicting Connection Header Data Found"] [data "close,close"] [severity "WARNING"] [ver "OWASP_CRS/3.3.0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/210/272"] [hostname "localhost"] [uri "/"] [unique_id "X-PNFSe1VwjCgYRI9FsbHgAAAIY"]`, | ||||||
`[2022-11-12 23:08:18.013007] [core:info] 127.0.0.1:36126 Y3AZUo3Gja4gB-tPE9uasgAAAA4 AH00128: File does not exist: /apache/htdocs/status/200`, | ||||||
"\n", markerLine) | ||||||
"\n", markerLineEnd) | ||||||
filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-") | ||||||
s.Require().NoError(err) | ||||||
|
||||||
|
@@ -296,8 +302,8 @@ func (s *readTestSuite) TestFTWLogLines_ContainsIn404() { | |||||
f := fields{ | ||||||
logFile: log, | ||||||
LogMarkerHeaderName: []byte(cfg.LogMarkerHeaderName), | ||||||
StartMarker: []byte(markerLine), | ||||||
EndMarker: []byte(markerLine), | ||||||
StartMarker: []byte(markerLineStart), | ||||||
EndMarker: []byte(markerLineEnd), | ||||||
} | ||||||
|
||||||
type args struct { | ||||||
|
@@ -336,7 +342,6 @@ func (s *readTestSuite) TestFTWLogLines_CheckForLogMarkerIn404() { | |||||
cfg, err := config.NewConfigFromEnv() | ||||||
s.Require().NoError(err) | ||||||
s.NotNil(cfg) | ||||||
|
||||||
stageID := "dead-beaf-deadbeef-deadbeef-dead" | ||||||
markerLine := fmt.Sprint(`[2022-11-12 23:08:18.012572] [-:error] 127.0.0.1:36126 Y3AZUo3Gja4gB-tPE9uasgAAAA4 [client 127.0.0.1] ModSecurity: Warning. Unconditional match in SecAction. [file "/apache/conf/httpd.conf_pod_2022-11-12_22:23"] [line "265"] [id "999999"] [msg "`, | ||||||
"X-cRs-TeSt ", stageID, | ||||||
|
@@ -368,12 +373,13 @@ func (s *readTestSuite) TestFindAllIdsInLogs() { | |||||
s.NotNil(cfg) | ||||||
|
||||||
stageID := "dead-beaf-deadbeef-deadbeef-dead" | ||||||
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.
Suggested change
|
||||||
markerLine := "X-cRs-TeSt: " + stageID | ||||||
logLines := fmt.Sprint("\n", markerLine, | ||||||
markerLineStart := "X-cRs-TeSt: " + stageID + "-s" | ||||||
markerLineEnd := "X-cRs-TeSt: " + stageID + "-e" | ||||||
logLines := fmt.Sprint("\n", markerLineStart, | ||||||
`[id "1"] something else [id "2"]`, | ||||||
`"id": 3, something else {"id":4},`, | ||||||
`something else [id \"5\"]`+"\n", | ||||||
"\n", markerLine) | ||||||
"\n", markerLineEnd) | ||||||
filename, err := utils.CreateTempFileWithContent(logLines, "test-errorlog-") | ||||||
s.Require().NoError(err) | ||||||
cfg.LogFile = filename | ||||||
|
@@ -384,8 +390,8 @@ func (s *readTestSuite) TestFindAllIdsInLogs() { | |||||
logFile: log, | ||||||
LogMarkerHeaderName: bytes.ToLower([]byte(cfg.LogMarkerHeaderName)), | ||||||
} | ||||||
ll.WithStartMarker([]byte(markerLine)) | ||||||
ll.WithEndMarker([]byte(markerLine)) | ||||||
ll.WithStartMarker([]byte(markerLineStart)) | ||||||
ll.WithEndMarker([]byte(markerLineEnd)) | ||||||
|
||||||
foundRuleIds := ll.TriggeredRules() | ||||||
s.Len(foundRuleIds, 5) | ||||||
|
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.