diff --git a/.github/scripts/report/e2e-report b/.github/scripts/report/e2e-report
deleted file mode 100644
index 4616b566283..00000000000
Binary files a/.github/scripts/report/e2e-report and /dev/null differ
diff --git a/.github/scripts/report/go.sum b/.github/scripts/report/go.sum
index e83fb29040d..d9206ca3ae6 100644
--- a/.github/scripts/report/go.sum
+++ b/.github/scripts/report/go.sum
@@ -1,28 +1,28 @@
-github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
-github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
-github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/tdewolff/minify/v2 v2.9.21 h1:nO4s1PEMy7aRjlIlbr3Jgr+bJby8QYuifa2Vs2f9lh4=
-github.com/tdewolff/minify/v2 v2.9.21/go.mod h1:PoDBts2L7sCwUT28vTAlozGeD6qxjrrihtin4bR/RMM=
-github.com/tdewolff/parse/v2 v2.5.19 h1:Kjaj3KQOx/4elIxlBSglus4E2oMfdROphvbq2b+OBZ0=
-github.com/tdewolff/parse/v2 v2.5.19/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
-github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
-github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
+github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/tdewolff/minify/v2 v2.9.21 h1:nO4s1PEMy7aRjlIlbr3Jgr+bJby8QYuifa2Vs2f9lh4=
+github.com/tdewolff/minify/v2 v2.9.21/go.mod h1:PoDBts2L7sCwUT28vTAlozGeD6qxjrrihtin4bR/RMM=
+github.com/tdewolff/parse/v2 v2.5.19 h1:Kjaj3KQOx/4elIxlBSglus4E2oMfdROphvbq2b+OBZ0=
+github.com/tdewolff/parse/v2 v2.5.19/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
+github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
+github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/.github/scripts/report/main.go b/.github/scripts/report/main.go
index 3d0983453b9..e120914e4d7 100644
--- a/.github/scripts/report/main.go
+++ b/.github/scripts/report/main.go
@@ -7,6 +7,7 @@ import (
"math"
"os"
"path/filepath"
+ "regexp"
"sort"
"strings"
)
@@ -23,8 +24,26 @@ type Counters struct {
CountTotal int
}
+type ExpectedActual struct {
+ ExtraElements ActualExpectedWithStatus // list of extra elements
+ TestInfo []string
+ Messages ActualExpectedWithStatus
+ FailOutput []string
+}
+
+type ActualExpectedWithStatus struct {
+ ExpectedContent []CodeLineStatus
+ ActualContent []CodeLineStatus
+}
+
+type CodeLineStatus struct {
+ Line string
+ Status bool // differed or not
+}
+
type TestsData struct {
TestLog TestLog
+ ExpectedActual ExpectedActual
FailLog []string
}
@@ -42,6 +61,22 @@ type TestFail struct {
Output string `json:"Output"`
}
+const (
+ prefixActualPayload = "actualPayload"
+ prefixExpectedPayload = "expectedPayload"
+ prefixFail = "--- FAIL:"
+ prefixQueries = `"queries": [`
+ extraElementsListA = "extra elements in list A:"
+ extraElementsListB = "extra elements in list B:"
+ prefixTest = "Test:"
+ suffixExpectedQueries = "Expected Queries content: 'fixtures/{"
+ suffixActualQueries = "doesn't match the Actual Queries content: 'output/{"
+ prefixTypeInterface = "([]interface {})"
+ prefixTypeVulnerableFile = "(model.VulnerableFile) {"
+ expectedNumberOflines = "Expected file number of lines:"
+ actualNumberOfLines = "Actual file number of lines:"
+)
+
func FindTest(tests []TestsData, testName string) (*TestsData, bool) {
for i := range tests {
if tests[i].TestLog.Test == testName {
@@ -51,6 +86,256 @@ func FindTest(tests []TestsData, testName string) (*TestsData, bool) {
return nil, false
}
+func cleanOutput(s string) string {
+ // remove (len=N)
+ lenPattern := regexp.MustCompile(`\(len=\d+\)\s*`)
+ s = lenPattern.ReplaceAllString(s, "")
+ // Remove type annotations like (string), (int), (*string), (model.IssueType)...
+ typePattern := regexp.MustCompile(`\([a-zA-Z*\[][^)]*\)\s*`)
+ s = typePattern.ReplaceAllString(s, "")
+ return s
+}
+
+func extractPayloadDiffLines(failLog []string) ExpectedActual {
+ var testInfo []string
+ var messages ActualExpectedWithStatus
+ var failOutput []string
+
+ const (
+ stateNone = iota
+ stateMessagesExpected
+ stateMessagesActual
+ stateTestInfo
+ stateFailLog
+ )
+ state := stateTestInfo
+
+ for _, line := range failLog {
+ trimmed := strings.TrimSpace(line)
+ if strings.HasPrefix(trimmed, prefixActualPayload) {
+ state = stateMessagesActual
+ } else if strings.HasPrefix(trimmed, prefixExpectedPayload) {
+ state = stateMessagesExpected
+ } else if strings.HasPrefix(trimmed, prefixFail) {
+ state = stateFailLog
+ } else if strings.HasPrefix(trimmed, prefixQueries) {
+ state = stateNone
+ }
+
+ switch state {
+ case stateMessagesActual:
+ if !strings.HasPrefix(trimmed, prefixActualPayload) {
+ messages.ActualContent = append(messages.ActualContent, CodeLineStatus{
+ Line: line,
+ Status: false,
+ })
+ }
+ case stateMessagesExpected:
+ if !strings.HasPrefix(trimmed, prefixExpectedPayload) {
+ messages.ExpectedContent = append(messages.ExpectedContent, CodeLineStatus{
+ Line: line,
+ Status: false,
+ })
+ }
+ case stateFailLog:
+ failOutput = append(failOutput, line)
+ state = stateNone
+ case stateTestInfo:
+ testInfo = append(testInfo, line)
+ }
+ }
+ return ExpectedActual{
+ TestInfo: testInfo,
+ Messages: messages,
+ FailOutput: failOutput,
+ }
+}
+
+func isExtraElementsContentLine(trimmed string) bool {
+ return !strings.HasPrefix(trimmed, prefixTypeInterface) && !strings.HasPrefix(trimmed, prefixTypeVulnerableFile)
+}
+
+func extractExpectedActualLines(failLog []string) ExpectedActual {
+ var extraElements ActualExpectedWithStatus
+ var testInfo []string
+ var messages ActualExpectedWithStatus
+ var failOutput []string
+
+ const (
+ stateNone = iota
+ stateExtraA
+ stateExtraB
+ stateTestInfo
+ stateMessagesExpected
+ stateMessagesActual
+ stateFailLog
+ )
+ state := stateNone
+
+ for _, line := range failLog {
+ trimmed := strings.TrimSpace(line)
+
+ switch trimmed {
+ case extraElementsListA:
+ state = stateExtraA
+ continue
+ case extraElementsListB:
+ state = stateExtraB
+ continue
+ }
+
+ if strings.HasPrefix(trimmed, prefixTest) {
+ state = stateTestInfo
+ } else if strings.HasSuffix(trimmed, suffixExpectedQueries) {
+ state = stateMessagesExpected
+ } else if strings.HasSuffix(trimmed, suffixActualQueries) {
+ state = stateMessagesActual
+ } else if strings.HasPrefix(trimmed, prefixFail) {
+ state = stateFailLog
+ }
+
+ if trimmed == "" && (state == stateExtraA || state == stateExtraB) {
+ state = stateNone
+ continue
+ }
+
+ switch state {
+ case stateExtraA:
+ if isExtraElementsContentLine(trimmed) {
+ cleanedLine := cleanOutput(line)
+ extraElements.ExpectedContent = append(extraElements.ExpectedContent, CodeLineStatus{
+ Line: cleanedLine,
+ Status: false,
+ })
+ }
+ case stateExtraB:
+ if isExtraElementsContentLine(trimmed) {
+ cleanedLine := cleanOutput(line)
+ extraElements.ActualContent = append(extraElements.ActualContent, CodeLineStatus{
+ Line: cleanedLine,
+ Status: false,
+ })
+ }
+ case stateTestInfo:
+ testInfo = append(testInfo, line)
+ case stateMessagesActual:
+ if !strings.HasSuffix(trimmed, suffixActualQueries) {
+ messages.ActualContent = append(messages.ActualContent, CodeLineStatus{
+ Line: line,
+ Status: false,
+ })
+ }
+ case stateMessagesExpected:
+ if !strings.HasSuffix(trimmed, suffixExpectedQueries) {
+ messages.ExpectedContent = append(messages.ExpectedContent, CodeLineStatus{
+ Line: line,
+ Status: false,
+ })
+ }
+ case stateFailLog:
+ failOutput = append(failOutput, line)
+ state = stateNone
+ }
+ }
+
+ return ExpectedActual{
+ ExtraElements: extraElements,
+ TestInfo: testInfo,
+ Messages: messages,
+ FailOutput: failOutput,
+ }
+}
+
+func isDifferentNumberOfLines(failLog []string) bool {
+ var hasExpectedFileNumberLines, hasActualFileNumberLines bool
+ for _, failLogEntry := range failLog {
+ trimmedEntry := strings.TrimSpace(failLogEntry)
+ if trimmedEntry == "" {
+ continue
+ }
+ if strings.Contains(trimmedEntry, expectedNumberOflines) {
+ hasExpectedFileNumberLines = true
+ }
+ if strings.Contains(failLogEntry, actualNumberOfLines) {
+ hasActualFileNumberLines = true
+ }
+ if hasExpectedFileNumberLines && hasActualFileNumberLines {
+ return true
+ }
+ }
+ return false
+}
+
+func isExpectedVsActual(failLog []string) bool {
+ var hasExtraA, hasExtraB bool
+ for _, failLogEntry := range failLog {
+ trimmedEntry := strings.TrimSpace(failLogEntry)
+ if trimmedEntry == extraElementsListA {
+ hasExtraA = true
+ }
+ if trimmedEntry == extraElementsListB {
+ hasExtraB = true
+ }
+ if hasExtraA && hasExtraB {
+ return true
+ }
+ }
+ return false
+}
+
+func compareMessageContent(expectedActual *ExpectedActual) {
+ expectedLen := len(expectedActual.Messages.ExpectedContent)
+ actualLen := len(expectedActual.Messages.ActualContent)
+ actualLenExtraElements := len(expectedActual.ExtraElements.ExpectedContent)
+ expectedLenExtraElements := len(expectedActual.ExtraElements.ActualContent)
+
+ maxLen := expectedLen
+ if actualLen > maxLen {
+ maxLen = actualLen
+ }
+ maxLenExtraElements := expectedLenExtraElements
+ if actualLenExtraElements > maxLenExtraElements {
+ maxLenExtraElements = actualLenExtraElements
+ }
+
+ for i := range maxLen {
+ // if one side has no line at this index, the line is marked as different
+ if i >= expectedLen || i >= actualLen {
+ if i < expectedLen {
+ expectedActual.Messages.ExpectedContent[i].Status = true
+ }
+ if i < actualLen {
+ expectedActual.Messages.ActualContent[i].Status = true
+ }
+ continue
+ }
+ expectedContentLine := strings.TrimSpace(expectedActual.Messages.ExpectedContent[i].Line)
+ actualContentLine := strings.TrimSpace(expectedActual.Messages.ActualContent[i].Line)
+ if expectedContentLine != actualContentLine {
+ expectedActual.Messages.ExpectedContent[i].Status = true
+ expectedActual.Messages.ActualContent[i].Status = true
+ }
+ }
+
+ for j := range maxLenExtraElements {
+ if j >= expectedLenExtraElements || j >= actualLenExtraElements {
+ if j < expectedLenExtraElements {
+ expectedActual.ExtraElements.ExpectedContent[j].Status = true
+ }
+ if j < actualLenExtraElements {
+ expectedActual.ExtraElements.ActualContent[j].Status = true
+ }
+ continue
+ }
+ expectedContentLine := strings.TrimSpace(expectedActual.ExtraElements.ExpectedContent[j].Line)
+ actualContentLine := strings.TrimSpace(expectedActual.ExtraElements.ActualContent[j].Line)
+ if expectedContentLine != actualContentLine {
+ expectedActual.ExtraElements.ExpectedContent[j].Status = true
+ expectedActual.ExtraElements.ActualContent[j].Status = true
+ }
+ }
+}
+
func main() {
var testPath, testName, reportPath, reportName string
@@ -88,7 +373,6 @@ func main() {
fmt.Printf("Error when trying to decode: %v\n", err)
fmt.Printf("Verify if the JSON File has UTF8 encoding")
}
-
if log.Action == "pass" || log.Action == "fail" {
if log.Test == "" {
finalStatus = log
@@ -98,7 +382,6 @@ func main() {
hasFailures = true
}
test, exists := FindTest(testList, log.Test)
-
if exists {
if log.Action == "fail" {
test.TestLog = log
@@ -117,7 +400,6 @@ func main() {
fmt.Printf("Error when trying to open: %v\n", filepath.Join(filepath.ToSlash(testPath), testName))
os.Exit(1)
}
-
decoder2 := json.NewDecoder(jsonTestsOutputClean)
for decoder2.More() {
var log TestLog
@@ -132,13 +414,28 @@ func main() {
}
test, exists := FindTest(testList, log.Test)
-
if !exists || test.TestLog.Action != "fail" {
continue
}
-
test.FailLog = append(test.FailLog, log.Output)
}
+
+ for i := range testList {
+ test := &testList[i]
+ if test.TestLog.Action != "fail" {
+ continue
+ }
+
+ if isExpectedVsActual(test.FailLog) {
+ expectedActual := extractExpectedActualLines(test.FailLog)
+ compareMessageContent(&expectedActual)
+ test.ExpectedActual = expectedActual
+ } else if isDifferentNumberOfLines(test.FailLog) {
+ expectedActual := extractPayloadDiffLines(test.FailLog)
+ compareMessageContent(&expectedActual)
+ test.ExpectedActual = expectedActual
+ }
+ }
}
fmt.Printf("Parsing tests data... Done!\n")
diff --git a/.github/scripts/report/template/html/e2e-report.css b/.github/scripts/report/template/html/e2e-report.css
index d6cd1dd1fe7..d20778584b8 100644
--- a/.github/scripts/report/template/html/e2e-report.css
+++ b/.github/scripts/report/template/html/e2e-report.css
@@ -1,142 +1,199 @@
-* {
- margin: 0;
- padding: 0;
- outline: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: sans-serif;
-}
-
-.container {
- display: flex;
- align-items: center;
- flex-direction: column;
- margin: 5px;
- border: 1px solid #bebebe;
-}
-
-.report-header-footer {
- display: grid;
- align-items: center;
- grid-template-columns: 1fr 1fr 1fr;
- border-bottom: 1px solid #bebebe;
- width: 100%;
- padding: 15px 21px;
- background-color: #503e9e;
- height: 50px;
- font-weight: bold;
- font-size: 14px;
- color: #fff;
- cursor: default;
- user-select: none;
-}
-
-.report-header-footer > a {
- color: inherit;
- text-decoration: inherit;
- text-align: right;
-}
-
-.report-header-footer > .title {
- font-size: 18px;
-}
-
-.report-header-footer > .title > span {
- color: #000;
-}
-
-.report-header-footer > .timestamp {
- font-weight: normal;
- font-style: italic;
- opacity: 0.5;
- text-align: center;
-}
-
-.separator {
- border-top: 1px solid #979797;
- opacity: 0.5;
- width: 95%;
- margin: 22px 0;
-}
-
-.hide {
- display: none;
-}
-
-summary {
- cursor: pointer;
- user-select: none;
- font-size: 18px;
- font-weight: bold;
-}
-
-.testBlock {
- width: 95vw;
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-
-.test-status {
- font-weight: bold;
-}
-
-.test-status.fail {
- color: #d60000;
-}
-
-.test-status.pass {
- color: #248e01;
-}
-
-.test-status.all {
- color: blue;
-}
-
-.counters {
- display: flex;
- flex-direction: row;
- margin: 22px 0;
- gap: 15px;
-}
-
-.counter-btn {
- display: flex;
- flex-direction: column;
- align-items: center;
- border: 1px solid rgba(0,0,0,0.1);
- padding: 10px;
- border-radius: 5px;
- cursor: pointer;
- min-width: 100px;
- gap: 5px;
- -webkit-box-shadow: 0 0 10px 0px rgb(0 0 0 / 10%);
- box-shadow: 0 0 10px 0px rgb(0 0 0 / 10%);
-}
-
-.counter-btn.selected {
- border-color: #c000ff;
-}
-
-.counter-count {
- font-style: italic;
- color: gray;
-}
-
-.results {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- gap: 10px;
- margin-top: 22px;
-}
-
-.code-box {
- display: flex;
- flex-direction: column;
- background-color: #503e9e10;
- gap: 5px;
-}
+* {
+ margin: 0;
+ padding: 0;
+ outline: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: sans-serif;
+}
+
+.container {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ margin: 5px;
+ border: 1px solid #bebebe;
+}
+
+.report-header-footer {
+ display: grid;
+ align-items: center;
+ grid-template-columns: 1fr 1fr 1fr;
+ border-bottom: 1px solid #bebebe;
+ width: 100%;
+ padding: 15px 21px;
+ background-color: #503e9e;
+ height: 50px;
+ font-weight: bold;
+ font-size: 14px;
+ color: #fff;
+ cursor: default;
+ user-select: none;
+}
+
+.report-header-footer > a {
+ color: inherit;
+ text-decoration: inherit;
+ text-align: right;
+}
+
+.report-header-footer > .title {
+ font-size: 18px;
+}
+
+.report-header-footer > .title > span {
+ color: #000;
+}
+
+.report-header-footer > .timestamp {
+ font-weight: normal;
+ font-style: italic;
+ opacity: 0.5;
+ text-align: center;
+}
+
+.separator {
+ border-top: 1px solid #979797;
+ opacity: 0.5;
+ width: 95%;
+ margin: 22px 0;
+}
+
+.hide {
+ display: none;
+}
+
+summary {
+ cursor: pointer;
+ user-select: none;
+ font-size: 18px;
+ font-weight: bold;
+}
+
+summary.sub-summary {
+ font-size: 15px;
+ font-weight: 700;
+ margin: 5px 0;
+}
+
+summary.expected-actual {
+ font-size: 14px;
+ font-weight: 580;
+}
+
+.testBlock {
+ width: 95vw;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.test-status {
+ font-weight: bold;
+}
+
+.test-status.fail {
+ color: #d60000;
+}
+
+.test-status.pass {
+ color: #248e01;
+}
+
+.test-status.all {
+ color: blue;
+}
+
+.counters {
+ display: flex;
+ flex-direction: row;
+ margin: 22px 0;
+ gap: 15px;
+}
+
+.counter-btn {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border: 1px solid rgba(0,0,0,0.1);
+ padding: 10px;
+ border-radius: 5px;
+ cursor: pointer;
+ min-width: 100px;
+ gap: 5px;
+ -webkit-box-shadow: 0 0 10px 0px rgb(0 0 0 / 10%);
+ box-shadow: 0 0 10px 0px rgb(0 0 0 / 10%);
+}
+
+.counter-btn.selected {
+ border-color: #c000ff;
+}
+
+.counter-count {
+ font-style: italic;
+ color: gray;
+}
+
+.code.diff {
+ background-color: rgba(255, 0, 0, 0.2);
+ border-radius: 4px;
+}
+
+.results {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 10px;
+ margin-top: 22px;
+}
+
+.code-box {
+ display: flex;
+ flex-direction: column;
+ background-color: #503e9e10;
+ gap: 5px;
+}
+
+.code-box.side-by-side {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ gap: 10px;
+ background-color: transparent;
+ margin-bottom: 10px;
+ margin-top: 10px;
+}
+
+.code-box.first {
+ width: 50%;
+ float: none;
+ height: auto;
+ align-self: auto;
+}
+
+.code-box.second {
+ width: 50%;
+ float: none;
+ height: auto;
+ align-self: auto;
+}
+
+.code-box.test-info {
+ background-color: white;
+ margin-bottom: 5px;
+}
+
+.code.pre {
+ white-space: pre-wrap;
+}
+
+.container_expected_actual {
+ width: auto;
+ background-color: #fff;
+ margin: auto;
+ display: flex;
+ float: none;
+}
diff --git a/.github/scripts/report/template/html/e2e-report.js b/.github/scripts/report/template/html/e2e-report.js
index 2aab56abb84..5cb61538008 100644
--- a/.github/scripts/report/template/html/e2e-report.js
+++ b/.github/scripts/report/template/html/e2e-report.js
@@ -1,11 +1,11 @@
-function filter(filt) {
- const tests = document.querySelectorAll("[data-type='testInfo']");
- tests.forEach((query) => filt !== "all" && filt !== query.getAttribute("data-name") ? query.classList.add("hide") : query.classList.remove("hide"));
-
- const severitiesCaptions = document.querySelectorAll(".counters > .counter-btn");
- const selectedElement = document.getElementsByClassName(`counter test-status ${filt}`)[0]
-
- severitiesCaptions.forEach((counter) => {
- filt && selectedElement === counter.getElementsByClassName('counter test-status')[0] ? counter.classList.add("selected") : counter.classList.remove("selected")
- });
-}
+function filter(filt) {
+ const tests = document.querySelectorAll("[data-type='testInfo']");
+ tests.forEach((query) => filt !== "all" && filt !== query.getAttribute("data-name") ? query.classList.add("hide") : query.classList.remove("hide"));
+
+ const severitiesCaptions = document.querySelectorAll(".counters > .counter-btn");
+ const selectedElement = document.getElementsByClassName(`counter test-status ${filt}`)[0]
+
+ severitiesCaptions.forEach((counter) => {
+ filt && selectedElement === counter.getElementsByClassName('counter test-status')[0] ? counter.classList.add("selected") : counter.classList.remove("selected")
+ });
+}
\ No newline at end of file
diff --git a/.github/scripts/report/template/html/e2e-report.tmpl b/.github/scripts/report/template/html/e2e-report.tmpl
index 9c4407c905e..ff71b33421b 100644
--- a/.github/scripts/report/template/html/e2e-report.tmpl
+++ b/.github/scripts/report/template/html/e2e-report.tmpl
@@ -1,62 +1,163 @@
-
-
-
-
-
- KICS Scan Result
- {{ includeCSS "report.css" }}
- {{ includeJS "report.js" }}
-
-
-
-
-
-
-
E2E Tests Result: {{.Result.Action}}
- Time Elapsed: {{.Result.Elapsed}}s
- Kics Docker Image: {{ getCurrentDockerImage }}
-
-
-
Filters
-
-
-
- PASSED
- {{.Counters.CountPass}}
-
-
-
- FAILED
- {{.Counters.CountFail}}
-
-
-
- ALL
- {{.Counters.CountTotal}}
-
-
-
- {{- range $val := .TestsData}}
-
-
-
-
Test: {{$val.TestLog.Test}}
-
Elapsed: {{$val.TestLog.Elapsed}}s
-
Status: {{$val.TestLog.Action}}
- {{ if eq $val.TestLog.Action "fail" }}
-
- View Details
-
- {{ range $failLine := $val.FailLog }}
- {{ $failLine }}
- {{ end }}
-
-
- {{ end }}
-
-
- {{- end -}}
-
-
-
-
+
+
+
+
+
+ KICS Scan Result
+ {{ includeCSS "report.css" }}
+ {{ includeJS "report.js" }}
+
+
+
+
+
+
+
E2E Tests Result: {{.Result.Action}}
+ Time Elapsed: {{.Result.Elapsed}}s
+ Kics Docker Image: {{ getCurrentDockerImage }}
+
+
+
Filters
+
+
+
+ PASSED
+ {{.Counters.CountPass}}
+
+
+
+ FAILED
+ {{.Counters.CountFail}}
+
+
+
+ ALL
+ {{.Counters.CountTotal}}
+
+
+
+ {{- range $val := .TestsData}}
+
+
+
+
Test: {{$val.TestLog.Test}}
+
Elapsed: {{$val.TestLog.Elapsed}}s
+
Status: {{$val.TestLog.Action}}
+ {{ if eq $val.TestLog.Action "fail" }}
+
+ View Details
+ {{ if and $val.ExpectedActual.Messages.ExpectedContent $val.ExpectedActual.Messages.ActualContent (not (and $val.ExpectedActual.ExtraElements.ExpectedContent $val.ExpectedActual.ExtraElements.ActualContent)) }}
+
+ {{ range $line := $val.ExpectedActual.TestInfo }}
+ {{ $line }}
+ {{ end }}
+
+
+ {{ range $line := $val.ExpectedActual.FailOutput }}
+ {{ $line }}
+ {{ end }}
+
+
+ Show additional information
+
+
+ Expected in fixtures:
+ {{ range $ec := $val.ExpectedActual.Messages.ExpectedContent }}
+ {{ if $ec.Status }}
+ {{ $ec.Line }}
+ {{ else }}
+ {{ $ec.Line }}
+ {{ end }}
+ {{ end }}
+
+
+ Actual output:
+ {{ range $ac := $val.ExpectedActual.Messages.ActualContent }}
+ {{ if $ac.Status }}
+ {{ $ac.Line }}
+ {{ else }}
+ {{ $ac.Line }}
+ {{ end }}
+ {{ end }}
+
+
+
+ {{ else if and $val.ExpectedActual.Messages.ExpectedContent $val.ExpectedActual.Messages.ActualContent }}
+
+ {{ range $line := $val.ExpectedActual.TestInfo }}
+ {{ $line }}
+ {{ end }}
+
+
+ {{ range $line := $val.ExpectedActual.FailOutput }}
+ {{ $line }}
+ {{ end }}
+
+ {{ if and $val.ExpectedActual.ExtraElements.ExpectedContent $val.ExpectedActual.ExtraElements.ActualContent }}
+
+ View extra elements
+
+
+ Expected in fixtures:
+ {{ range $ec := $val.ExpectedActual.ExtraElements.ExpectedContent }}
+ {{ if $ec.Status }}
+ {{ $ec.Line }}
+ {{ else }}
+ {{ $ec.Line }}
+ {{ end }}
+ {{ end }}
+
+
+ Actual output
+ {{ range $ac := $val.ExpectedActual.ExtraElements.ActualContent }}
+ {{ if $ac.Status }}
+ {{ $ac.Line }}
+ {{ else }}
+ {{ $ac.Line }}
+ {{ end }}
+ {{ end }}
+
+
+
+ {{ end }}
+
+ Show full Actual and Expected
+
+
+ Expected in fixtures:
+ {{ range $ec := $val.ExpectedActual.Messages.ExpectedContent }}
+ {{ if $ec.Status }}
+ {{ $ec.Line }}
+ {{ else }}
+ {{ $ec.Line }}
+ {{ end }}
+ {{ end }}
+
+
+ Actual output:
+ {{ range $ac := $val.ExpectedActual.Messages.ActualContent }}
+ {{ if $ac.Status }}
+ {{ $ac.Line }}
+ {{ else }}
+ {{ $ac.Line }}
+ {{ end }}
+ {{ end }}
+
+
+
+ {{ else }}
+
+ {{ range $failLine := $val.FailLog }}
+ {{ $failLine }}
+ {{ end }}
+
+ {{ end }}
+
+ {{ end }}
+
+
+ {{- end -}}
+
+
+
+
diff --git a/e2e/utils/json.go b/e2e/utils/json.go
index 527e7e5fa89..43f9d61b92e 100644
--- a/e2e/utils/json.go
+++ b/e2e/utils/json.go
@@ -2,7 +2,9 @@ package utils
import (
"encoding/json"
+ "fmt"
"io"
+
"os"
"path/filepath"
"reflect"
@@ -132,8 +134,10 @@ func FileCheck(t *testing.T, actualPayloadName, expectPayloadName, location stri
require.NoError(t, err, "[output/%s] Reading a fixture should not yield an error", actualPayloadName)
require.Equal(t, len(expectPayload), len(actualPayload),
- "[fixtures/%s] Expected file number of lines: %d\n[output/%s] Actual file number of lines: %d\n",
- expectPayloadName, len(expectPayload), actualPayloadName, len(actualPayload))
+ "[fixtures/%s] Expected file number of lines: %d\n[output/%s] Actual file number of lines: %d\n"+
+ "expectedPayload:\n%v\nactualPayload:\n%v\n",
+ expectPayloadName, len(expectPayload), actualPayloadName, len(actualPayload),
+ formatPayload(expectPayload), formatPayload(actualPayload))
setFields(t, expectPayload, actualPayload, expectPayloadName, actualPayloadName, location)
}
@@ -151,6 +155,45 @@ func CheckLine(t *testing.T, expec, want string, line int) {
}
}
+func formatPayload(payload []string) string {
+ var sb strings.Builder
+ for _, line := range payload {
+ sb.WriteString(line)
+ sb.WriteString("\n")
+ }
+ return sb.String()
+}
+
+func formatVulnFiles(files []map[string]interface{}) string {
+ var sb strings.Builder
+ for _, f := range files {
+ b, err := json.MarshalIndent(f, "", " ")
+ if err != nil {
+ sb.WriteString(fmt.Sprintf("error formatting file: %v\n", err))
+ continue
+ }
+ sb.WriteString(string(b))
+ sb.WriteString("\n")
+ }
+ return sb.String()
+}
+
+func toComparableFiles(queries []model.QueryResult) []map[string]interface{} {
+ result := []map[string]interface{}{}
+ for i := range queries {
+ for j := range queries[i].Files {
+ b, _ := json.Marshal(queries[i].Files[j])
+ m := map[string]interface{}{}
+ if err := json.Unmarshal(b, &m); err != nil {
+ continue
+ }
+ m["queryName"] = queries[i].QueryName
+ result = append(result, m)
+ }
+ }
+ return result
+}
+
//nolint:funlen
func setFields(t *testing.T, expect, actual []string, expectFileName, actualFileName, location string) {
switch location {
@@ -240,21 +283,16 @@ func setFields(t *testing.T, expect, actual []string, expectFileName, actualFile
expectFileName, actualFileName)
// compare the results
- expectToCompare := []model.VulnerableFile{}
- for i := range expectI.Queries {
- expectToCompare = append(expectToCompare, expectI.Queries[i].Files...)
- }
- actualToCompare := []model.VulnerableFile{}
- for i := range actualI.Queries {
- actualToCompare = append(actualToCompare, actualI.Queries[i].Files...)
- }
+ expectToCompare := toComparableFiles(expectI.Queries)
+ actualToCompare := toComparableFiles(actualI.Queries)
+
require.ElementsMatch(t, expectToCompare, actualToCompare,
- "Expected Queries content: 'fixtures/%s' doesn't match the Actual Queries content: 'output/%s'.",
- expectToCompare, actualToCompare)
+ "Expected Queries content: 'fixtures/%s' doesn't match the Actual Queries content: 'output/%s",
+ formatVulnFiles(expectToCompare), formatVulnFiles(actualToCompare))
// compare severity counters
compare := reflect.DeepEqual(expectI.SeverityCounters, actualI.SeverityCounters)
- require.True(t, compare, "Expected Severity Counters content: 'fixtures/%s' doesn't match the Actual Severity Counters content: 'output/%s'.", //nolint:lll
+ require.True(t, compare, "Expected Severity Counters content: 'fixtures/%s' doesn't match the Actual Severity Counters content: 'output/%s", //nolint:lll
expectI.SeverityCounters, actualI.SeverityCounters)
}
}
diff --git a/internal/console/remediate.go b/internal/console/remediate.go
index 869e97bec8e..d3dce6fa3dd 100644
--- a/internal/console/remediate.go
+++ b/internal/console/remediate.go
@@ -107,7 +107,7 @@ func remediate() error {
for filePath := range remediationSets {
fix := remediationSets[filePath].(remediation.Set)
- err = summary.RemediateFile(filePath, fix, openAPIResolveReferences, maxResolverDepth)
+ err = summary.RemediateFile(filePath, "", fix, openAPIResolveReferences, maxResolverDepth)
if err != nil {
return err
}
diff --git a/pkg/remediation/remediation.go b/pkg/remediation/remediation.go
index 242eaf92aef..d4c4a3cb57a 100644
--- a/pkg/remediation/remediation.go
+++ b/pkg/remediation/remediation.go
@@ -53,10 +53,19 @@ type Set struct {
}
// RemediateFile remediationSets the replacements first and secondly, the additions sorted down
-func (s *Summary) RemediateFile(filePath string, remediationSet Set, openAPIResolveReferences bool, maxResolverDepth int) error {
+func (s *Summary) RemediateFile(
+ filePath, originalFileName string,
+ remediationSet Set,
+ openAPIResolveReferences bool,
+ maxResolverDepth int,
+) error {
filepath.Clean(filePath)
content, err := os.ReadFile(filePath)
+ if originalFileName == "" {
+ originalFileName = filePath
+ }
+
if err != nil {
log.Error().Msgf("failed to read file: %s", err)
return err
@@ -70,7 +79,7 @@ func (s *Summary) RemediateFile(filePath string, remediationSet Set, openAPIReso
r := remediationSet.Replacement[i]
remediatedLines := replacement(&r, lines)
if len(remediatedLines) > 0 && willRemediate(remediatedLines, filePath, &r, openAPIResolveReferences, maxResolverDepth) {
- lines = s.writeRemediation(remediatedLines, lines, filePath, r.SimilarityID)
+ lines = s.writeRemediation(remediatedLines, lines, filePath, originalFileName, r.SimilarityID)
}
}
}
@@ -86,7 +95,7 @@ func (s *Summary) RemediateFile(filePath string, remediationSet Set, openAPIReso
a := remediationSet.Addition[i]
remediatedLines := addition(&a, &lines)
if len(remediatedLines) > 0 && willRemediate(remediatedLines, filePath, &a, openAPIResolveReferences, maxResolverDepth) {
- lines = s.writeRemediation(remediatedLines, lines, filePath, a.SimilarityID)
+ lines = s.writeRemediation(remediatedLines, lines, filePath, originalFileName, a.SimilarityID)
}
}
}
@@ -159,7 +168,7 @@ const (
FilePermMode = 0777
)
-func (s *Summary) writeRemediation(remediatedLines, lines []string, filePath, similarityID string) []string {
+func (s *Summary) writeRemediation(remediatedLines, lines []string, filePath, originalFileName, similarityID string) []string {
remediated := []byte(strings.Join(remediatedLines, "\n"))
mode := os.FileMode(FilePermMode)
@@ -171,6 +180,7 @@ func (s *Summary) writeRemediation(remediatedLines, lines []string, filePath, si
log.Info().Msgf("file '%s' was remediated with '%s'", filePath, similarityID)
s.ActualRemediationDoneNumber++
+ s.RemediatedFiles = append(s.RemediatedFiles, originalFileName)
return remediatedLines
}
diff --git a/pkg/remediation/remediation_test.go b/pkg/remediation/remediation_test.go
index 4ad860955b5..a1852cb5230 100644
--- a/pkg/remediation/remediation_test.go
+++ b/pkg/remediation/remediation_test.go
@@ -111,7 +111,7 @@ func Test_RemediateFile(t *testing.T) {
tmpFileName := filepath.Join(os.TempDir(), "temporary-remediation"+utils.NextRandom()+filepath.Ext(filePathCopyFrom))
tmpFile := CreateTempFile(filePathCopyFrom, tmpFileName)
- s.RemediateFile(tmpFile, tt.args.remediate, false, 15)
+ s.RemediateFile(tmpFile, filePathCopyFrom, tt.args.remediate, false, 15)
os.Remove(tmpFile)
require.Equal(t, s.ActualRemediationDoneNumber, tt.actualRemediationDoneNumber)
diff --git a/pkg/remediation/utils.go b/pkg/remediation/utils.go
index 39c43e8428d..9f5ce63f099 100644
--- a/pkg/remediation/utils.go
+++ b/pkg/remediation/utils.go
@@ -15,6 +15,7 @@ import (
type Summary struct {
SelectedRemediationNumber int
ActualRemediationDoneNumber int
+ RemediatedFiles []string
}
// GetRemediationSets collects all the replacements and additions per file
diff --git a/pkg/report/template/html/report.css b/pkg/report/template/html/report.css
index c81416fbe1b..f8ee13f8e6d 100644
--- a/pkg/report/template/html/report.css
+++ b/pkg/report/template/html/report.css
@@ -1,325 +1,325 @@
-* {
- margin: 0;
- padding: 0;
- outline: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: sans-serif;
-}
-
-.container {
- display: flex;
- align-items: center;
- flex-direction: column;
- margin: 5px;
- border: 1px solid #bebebe;
-}
-
-.run-info {
- display: flex;
- flex-wrap: wrap;
- border: 1px solid #bebebe;
- margin-top: 10px;
- width: 50vw;
-}
-
-.run-info > span {
- flex-basis: 50%;
- text-align: center;
-}
-
-.counters {
- display: flex;
- flex-direction: row;
- margin: 22px 0;
-}
-
-.report-header-footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- border-bottom: 1px solid #bebebe;
- width: 100%;
- padding: 15px 21px;
- background-color: #503e9e;
- height: 50px;
- font-weight: bold;
- font-size: 14px;
- color: #fff;
- cursor: default;
- user-select: none;
-}
-
-.report-header-footer > a {
- color: inherit;
- text-decoration: inherit;
-}
-
-.report-header-footer > .title {
- font-size: 18px;
-}
-
-.report-header-footer > .title > span {
- color: #000;
-}
-
-.report-header-footer > .timestamp {
- font-weight: normal;
- font-style: italic;
- opacity: 0.5;
-}
-
-.severity {
- display: flex;
- flex-direction: column;
- cursor: pointer;
- position: relative;
- margin: 0 22px;
- align-items: center;
-}
-
-.severity > .caption.selected {
- text-decoration: underline overline;
-}
-
-.badge {
- color: #fff;
- border: 2px solid #e8e8e8;
- border-radius: 50%;
- cursor: default;
- user-select: none;
- padding: 3px;
- font-size: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 30px;
- height: 30px;
- position: absolute;
- left: 60%;
- top: 50%;
-}
-
-.kics-black {
- color: #000;
-}
-
-.kics-red {
- color: #EE3F3F;
-}
-
-.kics-red > svg {
- fill: #EE3F3F;
-}
-
-.kics-red ~ .badge{
- background-color: #503e9e;
-}
-
-.kics-orange {
- color: #fc6e3a;
-}
-
-.kics-orange > svg {
- fill: #fc6e3a;
-}
-
-.kics-orange ~ .badge {
- background-color: #503e9e;
-}
-
-.kics-purple {
- color: #503e9e;
-}
-
-.kics-purple > svg {
- fill: #503e9e;
-}
-
-.kics-purple ~ .badge {
- background-color: #fc6e3a;
-}
-
-.severity > .icon > svg {
- width: 80px;
- height: auto;
-}
-
-.severity > .caption {
- font-size: 16px;
- font-weight: bolder;
- user-select: none;
- cursor: default;
-}
-
-.separator {
- border-top: 1px solid #979797;
- opacity: 0.5;
- width: 95%;
- margin: 22px 0;
-}
-
-.query {
- width: 95vw;
-}
-
-.query-title {
- display: flex;
- align-items: flex-start;
- flex-direction: column;
- width: 100%;
-}
-
-.query-title > h2 {
- display: flex;
-}
-
-.query-title > h2 > div {
- width: 20px;
- margin-right: 12px;
- margin-left: -30px;
-}
-
-.query > * {
- margin-left: 30px;
-}
-
-.query-info {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-
-.query-details {
- margin: 12px 0;
- display: flex;
- flex-direction: column;
- text-align: justify;
-}
-
-.query-details > span.query-description-title {
- font-size: 18px;
- margin-top: 5px;
-}
-
-.query-details > span.cis-description-text {
- margin-top: 5px;
-}
-
-.query-details > span:last-child {
- font-size: 14px;
-}
-
-.vulnerable-info {
- border: 1px #969696 solid;
- border-radius: 2px;
- display: flex;
- flex-direction: column;
- margin: 6px 9px;
-}
-
-.vulnerable-info-header {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- margin: 6px 9px;
-}
-
-.vulnerable-info-details {
- display: flex;
- flex-direction: column;
- margin: 6px 9px;
-}
-
-.vulnerable-info-details > span > strong {
- width: 5vw;
-}
-
-.code-box {
- display: flex;
- flex-direction: column;
- background-color: #503e9e10;
-}
-
-.code-line {
- display: flex;
- flex-direction: row;
- align-items: center;
- height: 20px;
-}
-
-.code-box > .error {
- background-color: #fc6e3a50;
-}
-
-.code-line > .code-line-counter {
- font-size: 10px;
- margin-left: 9px;
- margin-right: 10vw;
-}
-
-.code-line > .code {
- font-family: monospace;
- font-size: 16px;
-}
-
-.kics-message {
- margin: 24px 30vw;
- text-align: center;
-}
-
-.love {
- color: #503e9d;
- font-style: italic;
-}
-
-.social-networks {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
- margin-bottom: 24px;
-}
-
-.social-networks > a {
- margin: 0 15px;
-}
-
-.social-networks > a > div > svg {
- width: 20px;
- height: 20px;
-}
-
-.footer-text {
- font-style: italic;
- opacity: 0.5;
- font-weight: normal;
- width: 100%;
- display: flex;
- align-self: center;
- justify-content: center;
-}
-
-a.checkmarx,
-a.checkmarx:visited,
-a.checkmarx:hover,
-a.checkmarx:active {
- cursor: pointer;
- font-weight: bold;
- text-decoration: underline;
- color: #fff;
- opacity: 0.8;
-}
-
-.hide {
- display: none;
-}
-
-summary {
- cursor: pointer;
- user-select: none;
- font-size: 18px;
- font-weight: bold;
-}
+* {
+ margin: 0;
+ padding: 0;
+ outline: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: sans-serif;
+}
+
+.container {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ margin: 5px;
+ border: 1px solid #bebebe;
+}
+
+.run-info {
+ display: flex;
+ flex-wrap: wrap;
+ border: 1px solid #bebebe;
+ margin-top: 10px;
+ width: 50vw;
+}
+
+.run-info > span {
+ flex-basis: 50%;
+ text-align: center;
+}
+
+.counters {
+ display: flex;
+ flex-direction: row;
+ margin: 22px 0;
+}
+
+.report-header-footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ border-bottom: 1px solid #bebebe;
+ width: 100%;
+ padding: 15px 21px;
+ background-color: #503e9e;
+ height: 50px;
+ font-weight: bold;
+ font-size: 14px;
+ color: #fff;
+ cursor: default;
+ user-select: none;
+}
+
+.report-header-footer > a {
+ color: inherit;
+ text-decoration: inherit;
+}
+
+.report-header-footer > .title {
+ font-size: 18px;
+}
+
+.report-header-footer > .title > span {
+ color: #000;
+}
+
+.report-header-footer > .timestamp {
+ font-weight: normal;
+ font-style: italic;
+ opacity: 0.5;
+}
+
+.severity {
+ display: flex;
+ flex-direction: column;
+ cursor: pointer;
+ position: relative;
+ margin: 0 22px;
+ align-items: center;
+}
+
+.severity > .caption.selected {
+ text-decoration: underline overline;
+}
+
+.badge {
+ color: #fff;
+ border: 2px solid #e8e8e8;
+ border-radius: 50%;
+ cursor: default;
+ user-select: none;
+ padding: 3px;
+ font-size: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 30px;
+ height: 30px;
+ position: absolute;
+ left: 60%;
+ top: 50%;
+}
+
+.kics-black {
+ color: #000;
+}
+
+.kics-red {
+ color: #EE3F3F;
+}
+
+.kics-red > svg {
+ fill: #EE3F3F;
+}
+
+.kics-red ~ .badge{
+ background-color: #503e9e;
+}
+
+.kics-orange {
+ color: #fc6e3a;
+}
+
+.kics-orange > svg {
+ fill: #fc6e3a;
+}
+
+.kics-orange ~ .badge {
+ background-color: #503e9e;
+}
+
+.kics-purple {
+ color: #503e9e;
+}
+
+.kics-purple > svg {
+ fill: #503e9e;
+}
+
+.kics-purple ~ .badge {
+ background-color: #fc6e3a;
+}
+
+.severity > .icon > svg {
+ width: 80px;
+ height: auto;
+}
+
+.severity > .caption {
+ font-size: 16px;
+ font-weight: bolder;
+ user-select: none;
+ cursor: default;
+}
+
+.separator {
+ border-top: 1px solid #979797;
+ opacity: 0.5;
+ width: 95%;
+ margin: 22px 0;
+}
+
+.query {
+ width: 95vw;
+}
+
+.query-title {
+ display: flex;
+ align-items: flex-start;
+ flex-direction: column;
+ width: 100%;
+}
+
+.query-title > h2 {
+ display: flex;
+}
+
+.query-title > h2 > div {
+ width: 20px;
+ margin-right: 12px;
+ margin-left: -30px;
+}
+
+.query > * {
+ margin-left: 30px;
+}
+
+.query-info {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.query-details {
+ margin: 12px 0;
+ display: flex;
+ flex-direction: column;
+ text-align: justify;
+}
+
+.query-details > span.query-description-title {
+ font-size: 18px;
+ margin-top: 5px;
+}
+
+.query-details > span.cis-description-text {
+ margin-top: 5px;
+}
+
+.query-details > span:last-child {
+ font-size: 14px;
+}
+
+.vulnerable-info {
+ border: 1px #969696 solid;
+ border-radius: 2px;
+ display: flex;
+ flex-direction: column;
+ margin: 6px 9px;
+}
+
+.vulnerable-info-header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ margin: 6px 9px;
+}
+
+.vulnerable-info-details {
+ display: flex;
+ flex-direction: column;
+ margin: 6px 9px;
+}
+
+.vulnerable-info-details > span > strong {
+ width: 5vw;
+}
+
+.code-box {
+ display: flex;
+ flex-direction: column;
+ background-color: #503e9e10;
+}
+
+.code-line {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: 20px;
+}
+
+.code-box > .error {
+ background-color: #fc6e3a50;
+}
+
+.code-line > .code-line-counter {
+ font-size: 10px;
+ margin-left: 9px;
+ margin-right: 10vw;
+}
+
+.code-line > .code {
+ font-family: monospace;
+ font-size: 16px;
+}
+
+.kics-message {
+ margin: 24px 30vw;
+ text-align: center;
+}
+
+.love {
+ color: #503e9d;
+ font-style: italic;
+}
+
+.social-networks {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 24px;
+}
+
+.social-networks > a {
+ margin: 0 15px;
+}
+
+.social-networks > a > div > svg {
+ width: 20px;
+ height: 20px;
+}
+
+.footer-text {
+ font-style: italic;
+ opacity: 0.5;
+ font-weight: normal;
+ width: 100%;
+ display: flex;
+ align-self: center;
+ justify-content: center;
+}
+
+a.checkmarx,
+a.checkmarx:visited,
+a.checkmarx:hover,
+a.checkmarx:active {
+ cursor: pointer;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #fff;
+ opacity: 0.8;
+}
+
+.hide {
+ display: none;
+}
+
+summary {
+ cursor: pointer;
+ user-select: none;
+ font-size: 18px;
+ font-weight: bold;
+}
diff --git a/pkg/report/template/html/report.js b/pkg/report/template/html/report.js
index 18cf173ef9a..e20085d0af0 100644
--- a/pkg/report/template/html/report.js
+++ b/pkg/report/template/html/report.js
@@ -1,7 +1,7 @@
-function filter(filt) {
- const queries = document.querySelectorAll("[data-type='severity']");
- queries.forEach((query) => filt !== "TOTAL" && filt !== query.getAttribute("data-name") ? query.classList.add("hide") : query.classList.remove("hide"));
-
- const severitiesCaptions = document.querySelectorAll(".severity > .caption");
- severitiesCaptions.forEach((caption) => filt && filt === caption.innerText ? caption.classList.add("selected") : caption.classList.remove("selected"));
-}
+function filter(filt) {
+ const queries = document.querySelectorAll("[data-type='severity']");
+ queries.forEach((query) => filt !== "TOTAL" && filt !== query.getAttribute("data-name") ? query.classList.add("hide") : query.classList.remove("hide"));
+
+ const severitiesCaptions = document.querySelectorAll(".severity > .caption");
+ severitiesCaptions.forEach((caption) => filt && filt === caption.innerText ? caption.classList.add("selected") : caption.classList.remove("selected"));
+}
diff --git a/pkg/report/template/html/report.tmpl b/pkg/report/template/html/report.tmpl
index feccf93f839..d3f3d45609d 100644
--- a/pkg/report/template/html/report.tmpl
+++ b/pkg/report/template/html/report.tmpl
@@ -1,142 +1,142 @@
-
-
-
-
-
- KICS Scan Result
- {{ includeCSS "report.css" }}
- {{ includeJS "report.js" }}
-
-
-
-
-
-
- KICS {{ getVersion }}
- Scanned paths: {{ getPaths .ScannedPaths }}
- Platforms: {{ getPlatforms .Queries }}
- {{- with .Times -}}
- Start time: {{ .Start.Format "15:04:05, Jan 02 2006" }}
- End time: {{ .End.Format "15:04:05, Jan 02 2006" }}
- {{- end}}
-
-
Vulnerabilities:
-
- {{- with .SeveritySummary -}}
-
-
{{ includeSVG "vulnerability_fill.svg" }}
-
{{ index .SeverityCounters (severity "critical") }}
-
CRITICAL
-
-
-
{{ includeSVG "vulnerability_fill.svg" }}
-
{{ index .SeverityCounters (severity "high") }}
-
HIGH
-
-
-
{{ includeSVG "vulnerability_out.svg" }}
-
{{ index .SeverityCounters (severity "medium") }}
-
MEDIUM
-
-
-
{{ includeSVG "vulnerability_out.svg" }}
-
{{ index .SeverityCounters (severity "low") }}
-
LOW
-
-
-
{{ includeSVG "info.svg" }}
-
{{ index .SeverityCounters (severity "info") }}
-
INFO
-
- {{- end}}
-
-
{{ includeSVG "info.svg" }}
-
{{ .TotalCounter }}
-
TOTAL
-
-
- {{- range .Queries}}
-
-
-
-
-
-
- {{- if eq .Severity "CRITICAL" -}}
-
{{ includeSVG "vulnerability_fill.svg" }}
- {{- end -}}
- {{- if eq .Severity "HIGH" -}}
- {{ includeSVG "vulnerability_fill.svg" }}
- {{- end -}}
- {{- if eq .Severity "MEDIUM" -}}
- {{ includeSVG "vulnerability_out.svg" }}
- {{- end -}}
- {{- if eq .Severity "LOW" -}}
- {{ includeSVG "vulnerability_out.svg" }}
- {{- end -}}
- {{- if eq .Severity "INFO" -}}
- {{ includeSVG "info.svg" }}
- {{- end -}}
- {{- .QueryName -}}
-
-
Platform: {{ .Platform }}
- {{ if .CWE }}
CWE: {{ .CWE }}{{ end }}
- {{ if .RiskScore }}
Risk Score: {{ .RiskScore }}{{ end }}
-
Category: {{ .Category }}
-
-
- {{- if not .CISDescriptionID -}}
-
{{ .Description }}
- {{- end -}}
- {{- if .CISDescriptionID -}}
-
{{ .CISDescriptionIDFormatted }}
-
{{ .CISDescriptionTitle }}
-
{{ .CISDescriptionTextFormatted }}
- {{- end -}}
-
{{ .QueryURI }}
-
-
-
- Results ({{ len .Files }})
- {{- range .Files}}
- {{- $vulLine := .Line -}}
-
-
-
- Expected: {{ .KeyExpectedValue }}
- Found: {{ .KeyActualValue }}
-
-
- {{- range .VulnLines -}}
-
- {{ .Position }}{{ trimSpaces .Line }}
-
- {{- end}}
-
-
- {{- end -}}
-
-
-
- {{- end -}}
-
-
- KICS is open and will always stay such. Both the scanning engine and the security queries are clear and open for the software development community.
-
-
- Spread the love:
-
-
-
-
-
-
+
+
+
+
+
+ KICS Scan Result
+ {{ includeCSS "report.css" }}
+ {{ includeJS "report.js" }}
+
+
+
+
+
+
+ KICS {{ getVersion }}
+ Scanned paths: {{ getPaths .ScannedPaths }}
+ Platforms: {{ getPlatforms .Queries }}
+ {{- with .Times -}}
+ Start time: {{ .Start.Format "15:04:05, Jan 02 2006" }}
+ End time: {{ .End.Format "15:04:05, Jan 02 2006" }}
+ {{- end}}
+
+
Vulnerabilities:
+
+ {{- with .SeveritySummary -}}
+
+
{{ includeSVG "vulnerability_fill.svg" }}
+
{{ index .SeverityCounters (severity "critical") }}
+
CRITICAL
+
+
+
{{ includeSVG "vulnerability_fill.svg" }}
+
{{ index .SeverityCounters (severity "high") }}
+
HIGH
+
+
+
{{ includeSVG "vulnerability_out.svg" }}
+
{{ index .SeverityCounters (severity "medium") }}
+
MEDIUM
+
+
+
{{ includeSVG "vulnerability_out.svg" }}
+
{{ index .SeverityCounters (severity "low") }}
+
LOW
+
+
+
{{ includeSVG "info.svg" }}
+
{{ index .SeverityCounters (severity "info") }}
+
INFO
+
+ {{- end}}
+
+
{{ includeSVG "info.svg" }}
+
{{ .TotalCounter }}
+
TOTAL
+
+
+ {{- range .Queries}}
+
+
+
+
+
+
+ {{- if eq .Severity "CRITICAL" -}}
+
{{ includeSVG "vulnerability_fill.svg" }}
+ {{- end -}}
+ {{- if eq .Severity "HIGH" -}}
+ {{ includeSVG "vulnerability_fill.svg" }}
+ {{- end -}}
+ {{- if eq .Severity "MEDIUM" -}}
+ {{ includeSVG "vulnerability_out.svg" }}
+ {{- end -}}
+ {{- if eq .Severity "LOW" -}}
+ {{ includeSVG "vulnerability_out.svg" }}
+ {{- end -}}
+ {{- if eq .Severity "INFO" -}}
+ {{ includeSVG "info.svg" }}
+ {{- end -}}
+ {{- .QueryName -}}
+
+
Platform: {{ .Platform }}
+ {{ if .CWE }}
CWE: {{ .CWE }}{{ end }}
+ {{ if .RiskScore }}
Risk Score: {{ .RiskScore }}{{ end }}
+
Category: {{ .Category }}
+
+
+ {{- if not .CISDescriptionID -}}
+
{{ .Description }}
+ {{- end -}}
+ {{- if .CISDescriptionID -}}
+
{{ .CISDescriptionIDFormatted }}
+
{{ .CISDescriptionTitle }}
+
{{ .CISDescriptionTextFormatted }}
+ {{- end -}}
+
{{ .QueryURI }}
+
+
+
+ Results ({{ len .Files }})
+ {{- range .Files}}
+ {{- $vulLine := .Line -}}
+
+
+
+ Expected: {{ .KeyExpectedValue }}
+ Found: {{ .KeyActualValue }}
+
+
+ {{- range .VulnLines -}}
+
+ {{ .Position }}{{ trimSpaces .Line }}
+
+ {{- end}}
+
+
+ {{- end -}}
+
+
+
+ {{- end -}}
+
+
+ KICS is open and will always stay such. Both the scanning engine and the security queries are clear and open for the software development community.
+
+
+ Spread the love:
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/queries_test.go b/test/queries_test.go
index 88e593d30cd..52d2d045c14 100644
--- a/test/queries_test.go
+++ b/test/queries_test.go
@@ -3,6 +3,7 @@ package test
import (
"context"
"encoding/json"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -58,6 +59,7 @@ func testRemediationQuery(t testing.TB, entry queryEntry, vulnerabilities []mode
summary := &remediation.Summary{
SelectedRemediationNumber: 0,
ActualRemediationDoneNumber: 0,
+ RemediatedFiles: []string{},
}
// get remediationSets from query vulns
@@ -85,26 +87,28 @@ func testRemediationQuery(t testing.TB, entry queryEntry, vulnerabilities []mode
)
temporaryRemediationSets := make(map[string]interface{})
+ tempToOriginal := make(map[string]string)
for k := range remediationSets {
tmpFilePath := filepath.Join(os.TempDir(), "temporary-remediation-"+utils.NextRandom()+filepath.Ext(k))
tmpFile := remediation.CreateTempFile(k, tmpFilePath)
temporaryRemediationSets[tmpFile] = remediationSets[k]
+ tempToOriginal[tmpFile] = k
}
for filePath := range temporaryRemediationSets {
fix := temporaryRemediationSets[filePath].(remediation.Set)
-
- err = summary.RemediateFile(filePath, fix, false, 15)
+ original_file_name := tempToOriginal[filePath]
+ err = summary.RemediateFile(filePath, original_file_name, fix, false, 15)
os.Remove(filePath)
if err != nil {
require.NoError(t, err)
}
}
- require.Equal(t, summary.SelectedRemediationNumber, summary.ActualRemediationDoneNumber,
- "'SelectedRemediationNumber' is different from 'ActualRemediationDoneNumber'")
+ errorMsg := fmt.Sprintf("'SelectedRemediationNumber' is different from 'ActualRemediationDoneNumber'\nRemediated files: %v", summary.RemediatedFiles)
+ require.Equal(t, summary.SelectedRemediationNumber, summary.ActualRemediationDoneNumber, errorMsg)
}
}