Skip to content

Commit f7f712c

Browse files
authored
Fix statistics calculation (#254)
* Fix statistics calculation * Add test * Update chromedp dependency * Small refactoring
1 parent 21eaa2d commit f7f712c

File tree

7 files changed

+301
-221
lines changed

7 files changed

+301
-221
lines changed

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module github.com/wallarm/gotestwaf
33
go 1.22
44

55
require (
6-
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd
7-
github.com/chromedp/chromedp v0.9.5
6+
github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476
7+
github.com/chromedp/chromedp v0.10.0
88
github.com/clbanning/mxj v1.8.4
99
github.com/getkin/kin-openapi v0.114.0
1010
github.com/go-echarts/go-echarts/v2 v2.2.5
@@ -55,7 +55,7 @@ require (
5555
github.com/spf13/cast v1.5.0 // indirect
5656
github.com/spf13/jwalterweatherman v1.1.0 // indirect
5757
github.com/subosito/gotenv v1.4.2 // indirect
58-
golang.org/x/sys v0.22.0 // indirect
58+
golang.org/x/sys v0.24.0 // indirect
5959
golang.org/x/term v0.22.0 // indirect
6060
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
6161
gopkg.in/ini.v1 v1.67.0 // indirect

go.sum

+7
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
4242
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
4343
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd h1:5/HXKq8EaAWVmnl6Hnyl4SVq7FF5990DBW6AuTrWtVw=
4444
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
45+
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
46+
github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU=
47+
github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
4548
github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg=
4649
github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y=
50+
github.com/chromedp/chromedp v0.10.0 h1:bRclRYVpMm/UVD76+1HcRW9eV3l58rFfy7AdBvKab1E=
51+
github.com/chromedp/chromedp v0.10.0/go.mod h1:ei/1ncZIqXX1YnAYDkxhD4gzBgavMEUu7JCKvztdomE=
4752
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
4853
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
4954
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -410,6 +415,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
410415
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
411416
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
412417
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
418+
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
419+
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
413420
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
414421
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
415422
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=

internal/db/statistics.go

+83-130
Original file line numberDiff line numberDiff line change
@@ -12,63 +12,36 @@ type Statistics struct {
1212

1313
TestCasesFingerprint string
1414

15-
TruePositiveTests struct {
16-
SummaryTable []*SummaryTableRow
17-
Blocked []*TestDetails
18-
Bypasses []*TestDetails
19-
Unresolved []*TestDetails
20-
Failed []*FailedDetails
21-
22-
AllRequestsNumber int
23-
BlockedRequestsNumber int
24-
BypassedRequestsNumber int
25-
UnresolvedRequestsNumber int
26-
FailedRequestsNumber int
27-
ResolvedRequestsNumber int
28-
29-
UnresolvedRequestsPercentage float64
30-
ResolvedBlockedRequestsPercentage float64
31-
ResolvedBypassedRequestsPercentage float64
32-
FailedRequestsPercentage float64
33-
}
34-
35-
TrueNegativeTests struct {
36-
SummaryTable []*SummaryTableRow
37-
FalsePositive []*TestDetails
38-
TruePositive []*TestDetails
39-
Unresolved []*TestDetails
40-
Failed []*FailedDetails
41-
42-
AllRequestsNumber int
43-
BlockedRequestsNumber int
44-
BypassedRequestsNumber int
45-
UnresolvedRequestsNumber int
46-
FailedRequestsNumber int
47-
ResolvedRequestsNumber int
48-
49-
UnresolvedRequestsPercentage float64
50-
ResolvedFalseRequestsPercentage float64
51-
ResolvedTrueRequestsPercentage float64
52-
FailedRequestsPercentage float64
53-
}
15+
TruePositiveTests TestsSummary
16+
TrueNegativeTests TestsSummary
5417

5518
Score struct {
56-
ApiSec struct {
57-
TruePositive float64
58-
TrueNegative float64
59-
Average float64
60-
}
61-
62-
AppSec struct {
63-
TruePositive float64
64-
TrueNegative float64
65-
Average float64
66-
}
67-
19+
ApiSec Score
20+
AppSec Score
6821
Average float64
6922
}
7023
}
7124

25+
type TestsSummary struct {
26+
SummaryTable []*SummaryTableRow
27+
Blocked []*TestDetails
28+
Bypasses []*TestDetails
29+
Unresolved []*TestDetails
30+
Failed []*FailedDetails
31+
32+
AllRequestsNumber int
33+
BlockedRequestsNumber int
34+
BypassedRequestsNumber int
35+
UnresolvedRequestsNumber int
36+
FailedRequestsNumber int
37+
ResolvedRequestsNumber int
38+
39+
UnresolvedRequestsPercentage float64
40+
ResolvedBlockedRequestsPercentage float64
41+
ResolvedBypassedRequestsPercentage float64
42+
FailedRequestsPercentage float64
43+
}
44+
7245
type SummaryTableRow struct {
7346
TestSet string `json:"test_set" validate:"required,printascii,max=256"`
7447
TestCase string `json:"test_case" validate:"required,printascii,max=256"`
@@ -101,6 +74,12 @@ type FailedDetails struct {
10174
Type string `json:"type" validate:"omitempty"`
10275
}
10376

77+
type Score struct {
78+
TruePositive float64
79+
TrueNegative float64
80+
Average float64
81+
}
82+
10483
type Path struct {
10584
Method string `json:"method" validate:"required,printascii,max=32"`
10685
Path string `json:"path" validate:"required,printascii,max=1024"`
@@ -233,35 +212,8 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
233212
}
234213
}
235214

236-
// Number of all negative requests
237-
s.TruePositiveTests.AllRequestsNumber = s.TruePositiveTests.BlockedRequestsNumber +
238-
s.TruePositiveTests.BypassedRequestsNumber +
239-
s.TruePositiveTests.UnresolvedRequestsNumber +
240-
s.TruePositiveTests.FailedRequestsNumber
241-
242-
// Number of negative resolved requests
243-
s.TruePositiveTests.ResolvedRequestsNumber = s.TruePositiveTests.BlockedRequestsNumber +
244-
s.TruePositiveTests.BypassedRequestsNumber
245-
246-
// Number of all negative requests
247-
s.TrueNegativeTests.AllRequestsNumber = s.TrueNegativeTests.BlockedRequestsNumber +
248-
s.TrueNegativeTests.BypassedRequestsNumber +
249-
s.TrueNegativeTests.UnresolvedRequestsNumber +
250-
s.TrueNegativeTests.FailedRequestsNumber
251-
252-
// Number of positive resolved requests
253-
s.TrueNegativeTests.ResolvedRequestsNumber = s.TrueNegativeTests.BlockedRequestsNumber +
254-
s.TrueNegativeTests.BypassedRequestsNumber
255-
256-
s.TruePositiveTests.UnresolvedRequestsPercentage = CalculatePercentage(s.TruePositiveTests.UnresolvedRequestsNumber, s.TruePositiveTests.AllRequestsNumber)
257-
s.TruePositiveTests.ResolvedBlockedRequestsPercentage = CalculatePercentage(s.TruePositiveTests.BlockedRequestsNumber, s.TruePositiveTests.ResolvedRequestsNumber)
258-
s.TruePositiveTests.ResolvedBypassedRequestsPercentage = CalculatePercentage(s.TruePositiveTests.BypassedRequestsNumber, s.TruePositiveTests.ResolvedRequestsNumber)
259-
s.TruePositiveTests.FailedRequestsPercentage = CalculatePercentage(s.TruePositiveTests.FailedRequestsNumber, s.TruePositiveTests.AllRequestsNumber)
260-
261-
s.TrueNegativeTests.UnresolvedRequestsPercentage = CalculatePercentage(s.TrueNegativeTests.UnresolvedRequestsNumber, s.TrueNegativeTests.AllRequestsNumber)
262-
s.TrueNegativeTests.ResolvedFalseRequestsPercentage = CalculatePercentage(s.TrueNegativeTests.BlockedRequestsNumber, s.TrueNegativeTests.ResolvedRequestsNumber)
263-
s.TrueNegativeTests.ResolvedTrueRequestsPercentage = CalculatePercentage(s.TrueNegativeTests.BypassedRequestsNumber, s.TrueNegativeTests.ResolvedRequestsNumber)
264-
s.TrueNegativeTests.FailedRequestsPercentage = CalculatePercentage(s.TrueNegativeTests.FailedRequestsNumber, s.TrueNegativeTests.AllRequestsNumber)
215+
calculateTestsSummaryStat(&s.TruePositiveTests)
216+
calculateTestsSummaryStat(&s.TrueNegativeTests)
265217

266218
for _, blockedTest := range db.blockedTests {
267219
sort.Strings(blockedTest.AdditionalInfo)
@@ -278,7 +230,7 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
278230
}
279231

280232
if isFalsePositiveTest(blockedTest.Set) {
281-
s.TrueNegativeTests.FalsePositive = append(s.TrueNegativeTests.FalsePositive, testDetails)
233+
s.TrueNegativeTests.Blocked = append(s.TrueNegativeTests.Blocked, testDetails)
282234
} else {
283235
s.TruePositiveTests.Blocked = append(s.TruePositiveTests.Blocked, testDetails)
284236
}
@@ -299,7 +251,7 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
299251
}
300252

301253
if isFalsePositiveTest(passedTest.Set) {
302-
s.TrueNegativeTests.TruePositive = append(s.TrueNegativeTests.TruePositive, testDetails)
254+
s.TrueNegativeTests.Bypasses = append(s.TrueNegativeTests.Bypasses, testDetails)
303255
} else {
304256
s.TruePositiveTests.Bypasses = append(s.TruePositiveTests.Bypasses, testDetails)
305257
}
@@ -321,7 +273,7 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
321273

322274
if ignoreUnresolved || nonBlockedAsPassed {
323275
if isFalsePositiveTest(unresolvedTest.Set) {
324-
s.TrueNegativeTests.FalsePositive = append(s.TrueNegativeTests.FalsePositive, testDetails)
276+
s.TrueNegativeTests.Blocked = append(s.TrueNegativeTests.Blocked, testDetails)
325277
} else {
326278
s.TruePositiveTests.Bypasses = append(s.TruePositiveTests.Bypasses, testDetails)
327279
}
@@ -395,7 +347,7 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
395347
var appSecTrueNegBypassNum int
396348
var appSecTrueNegNum int
397349

398-
for _, test := range s.TrueNegativeTests.TruePositive {
350+
for _, test := range s.TrueNegativeTests.Bypasses {
399351
if isApiTest(test.TestSet) {
400352
apiSecTrueNegNum++
401353
apiSecTrueNegBypassNum++
@@ -404,83 +356,84 @@ func (db *DB) GetStatistics(ignoreUnresolved, nonBlockedAsPassed bool) *Statisti
404356
appSecTrueNegBypassNum++
405357
}
406358
}
407-
for _, test := range s.TrueNegativeTests.FalsePositive {
359+
for _, test := range s.TrueNegativeTests.Blocked {
408360
if isApiTest(test.TestSet) {
409361
apiSecTrueNegNum++
410362
} else {
411363
appSecTrueNegNum++
412364
}
413365
}
414366

367+
calculateScorePercentage(&s.Score.ApiSec, apiSecTruePosBlockedNum, apiSecTruePosNum, apiSecTrueNegBypassNum, apiSecTrueNegNum)
368+
calculateScorePercentage(&s.Score.AppSec, appSecTruePosBlockedNum, appSecTruePosNum, appSecTrueNegBypassNum, appSecTrueNegNum)
369+
415370
var divider int
416371
var sum float64
417372

418-
s.Score.ApiSec.TruePositive = CalculatePercentage(apiSecTruePosBlockedNum, apiSecTruePosNum)
419-
s.Score.ApiSec.TrueNegative = CalculatePercentage(apiSecTrueNegBypassNum, apiSecTrueNegNum)
420-
421-
if apiSecTruePosNum != 0 {
373+
if s.Score.ApiSec.Average != -1.0 {
422374
divider++
423-
sum += s.Score.ApiSec.TruePositive
424-
} else {
425-
s.Score.ApiSec.TruePositive = -1.0
375+
sum += s.Score.ApiSec.Average
426376
}
427-
428-
if apiSecTrueNegNum != 0 {
377+
if s.Score.AppSec.Average != -1.0 {
429378
divider++
430-
sum += s.Score.ApiSec.TrueNegative
431-
} else {
432-
s.Score.ApiSec.TrueNegative = -1.0
379+
sum += s.Score.AppSec.Average
433380
}
434381

435382
if divider != 0 {
436-
s.Score.ApiSec.Average = Round(sum / float64(divider))
383+
s.Score.Average = Round(sum / float64(divider))
437384
} else {
438-
s.Score.ApiSec.Average = -1.0
385+
s.Score.Average = -1.0
439386
}
440387

441-
divider = 0
442-
sum = 0.0
388+
return s
389+
}
443390

444-
s.Score.AppSec.TruePositive = CalculatePercentage(appSecTruePosBlockedNum, appSecTruePosNum)
445-
s.Score.AppSec.TrueNegative = CalculatePercentage(appSecTrueNegBypassNum, appSecTrueNegNum)
391+
func calculateTestsSummaryStat(s *TestsSummary) {
392+
s.AllRequestsNumber = s.BlockedRequestsNumber +
393+
s.BypassedRequestsNumber +
394+
s.UnresolvedRequestsNumber +
395+
s.FailedRequestsNumber
446396

447-
if appSecTruePosNum != 0 {
448-
divider++
449-
sum += s.Score.AppSec.TruePositive
450-
} else {
451-
s.Score.AppSec.TruePositive = -1.0
452-
}
397+
s.ResolvedRequestsNumber = s.BlockedRequestsNumber +
398+
s.BypassedRequestsNumber
453399

454-
if appSecTrueNegNum != 0 {
455-
divider++
456-
sum += s.Score.AppSec.TrueNegative
457-
} else {
458-
s.Score.AppSec.TrueNegative = -1.0
459-
}
400+
s.UnresolvedRequestsPercentage = CalculatePercentage(s.UnresolvedRequestsNumber, s.AllRequestsNumber)
401+
s.ResolvedBlockedRequestsPercentage = CalculatePercentage(s.BlockedRequestsNumber, s.ResolvedRequestsNumber)
402+
s.ResolvedBypassedRequestsPercentage = CalculatePercentage(s.BypassedRequestsNumber, s.ResolvedRequestsNumber)
403+
s.FailedRequestsPercentage = CalculatePercentage(s.FailedRequestsNumber, s.AllRequestsNumber)
404+
}
460405

461-
if divider != 0 {
462-
s.Score.AppSec.Average = Round(sum / float64(divider))
463-
} else {
464-
s.Score.AppSec.Average = -1.0
465-
}
406+
func calculateScorePercentage(s *Score, truePosBlockedNum, truePosNum, trueNegBypassNum, trueNegNum int) {
407+
var (
408+
divider int
409+
sum float64
410+
)
466411

467-
divider = 0
468-
sum = 0.0
412+
s.TruePositive = CalculatePercentage(truePosBlockedNum, truePosNum)
413+
s.TrueNegative = CalculatePercentage(trueNegBypassNum, trueNegNum)
469414

470-
if s.Score.ApiSec.Average != -1.0 {
415+
if truePosNum != 0 {
471416
divider++
472-
sum += s.Score.ApiSec.Average
417+
sum += s.TruePositive
418+
} else {
419+
s.TruePositive = -1.0
473420
}
474-
if s.Score.AppSec.Average != -1.0 {
421+
422+
if trueNegNum != 0 {
475423
divider++
476-
sum += s.Score.AppSec.Average
424+
sum += s.TrueNegative
425+
} else {
426+
s.TrueNegative = -1.0
477427
}
478428

479429
if divider != 0 {
480-
s.Score.Average = Round(sum / float64(divider))
430+
// If all malicious request were passed then grade is 0.
431+
if truePosBlockedNum == 0 {
432+
s.Average = 0.0
433+
} else {
434+
s.Average = Round(sum / float64(divider))
435+
}
481436
} else {
482-
s.Score.Average = -1.0
437+
s.Average = -1.0
483438
}
484-
485-
return s
486439
}

0 commit comments

Comments
 (0)