Skip to content

Commit

Permalink
feat: refactor and add more properties in report
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuelgautier committed Oct 7, 2024
1 parent d48e9d9 commit 93741f2
Show file tree
Hide file tree
Showing 77 changed files with 1,416 additions and 772 deletions.
6 changes: 3 additions & 3 deletions api/curl.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ func (h *Handler) ScanURL(ctx *gin.Context) {
return
}

if reporter.HasVulnerability() {
analyticsx.TrackEvent(ctx, serverApiUrlTracer, "Vulnerability Found", nil)
if reporter.HasIssue() {
analyticsx.TrackEvent(ctx, serverApiUrlTracer, "Issue Found", nil)

Check warning on line 57 in api/curl.go

View check run for this annotation

Codecov / codecov/patch

api/curl.go#L56-L57

Added lines #L56 - L57 were not covered by tests
}

ctx.JSON(http.StatusOK, HTTPResponseReports{
Reports: reporter.GetReports(),
Reports: reporter.GetScanReports(),

Check warning on line 61 in api/curl.go

View check run for this annotation

Codecov / codecov/patch

api/curl.go#L61

Added line #L61 was not covered by tests
})
}
6 changes: 3 additions & 3 deletions api/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ func (h *Handler) ScanGraphQL(ctx *gin.Context) {
return
}

if reporter.HasVulnerability() {
analyticsx.TrackEvent(ctx, serverApiGraphQLTracer, "Vulnerability Found", nil)
if reporter.HasIssue() {
analyticsx.TrackEvent(ctx, serverApiGraphQLTracer, "Issue Found", nil)

Check warning on line 53 in api/graphql.go

View check run for this annotation

Codecov / codecov/patch

api/graphql.go#L52-L53

Added lines #L52 - L53 were not covered by tests
}

ctx.JSON(http.StatusOK, HTTPResponseReports{
Reports: reporter.GetReports(),
Reports: reporter.GetScanReports(),

Check warning on line 57 in api/graphql.go

View check run for this annotation

Codecov / codecov/patch

api/graphql.go#L57

Added line #L57 was not covered by tests
})
}
8 changes: 4 additions & 4 deletions api/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type NewOpenAPIScanRequest struct {
Schema string `json:"schema" binding:"required"`
SecuritySchemes map[string]struct {
Value string `json:"value" binding:"required"`
} `json:"security_schemes"`
} `json:"securitySchemes"`

Opts *ScanOptions `json:"options"`
}
Expand Down Expand Up @@ -76,12 +76,12 @@ func (h *Handler) ScanOpenAPI(ctx *gin.Context) {
return
}

if reporter.HasVulnerability() {
analyticsx.TrackEvent(ctx, serverApiOpenAPITracer, "Vulnerability Found", nil)
if reporter.HasIssue() {
analyticsx.TrackEvent(ctx, serverApiOpenAPITracer, "Issue Found", nil)

Check warning on line 80 in api/openapi.go

View check run for this annotation

Codecov / codecov/patch

api/openapi.go#L79-L80

Added lines #L79 - L80 were not covered by tests
}

response := HTTPResponseReports{
Reports: reporter.GetReports(),
Reports: reporter.GetScanReports(),

Check warning on line 84 in api/openapi.go

View check run for this annotation

Codecov / codecov/patch

api/openapi.go#L84

Added line #L84 was not covered by tests
}
_, err = json.Marshal(response)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion api/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import (
)

type HTTPResponseReports struct {
Reports []*report.Report `json:"reports"`
Reports []*report.ScanReport `json:"reports"`
}
2 changes: 1 addition & 1 deletion api/response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestMarshalHTTPResponseReports(t *testing.T) {
sr.EndTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)

hrr := api.HTTPResponseReports{
Reports: []*report.Report{sr},
Reports: []*report.ScanReport{sr},
}

b, err := json.Marshal(hrr)
Expand Down
2 changes: 1 addition & 1 deletion cmd/scan/curl.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func NewCURLScanCmd() (scanCmd *cobra.Command) {
}

internalCmd.TrackScanReport(ctx, tracer, reporter)
err = internalCmd.PrintOrExportReport(internalCmd.GetOutputFormat(), internalCmd.GetOutputTransport(), reporter)
err = internalCmd.PrintOrExportReport(internalCmd.GetReportFormat(), internalCmd.GetReportTransport(), reporter)

Check warning on line 71 in cmd/scan/curl.go

View check run for this annotation

Codecov / codecov/patch

cmd/scan/curl.go#L71

Added line #L71 was not covered by tests
if err != nil {
analyticsx.TrackError(ctx, tracer, err)
log.Fatal(err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/scan/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func NewGraphQLScanCmd() (scanCmd *cobra.Command) {
}

internalCmd.TrackScanReport(ctx, tracer, reporter)
err = internalCmd.PrintOrExportReport(internalCmd.GetOutputFormat(), internalCmd.GetOutputTransport(), reporter)
err = internalCmd.PrintOrExportReport(internalCmd.GetReportFormat(), internalCmd.GetReportTransport(), reporter)

Check warning on line 63 in cmd/scan/graphql.go

View check run for this annotation

Codecov / codecov/patch

cmd/scan/graphql.go#L63

Added line #L63 was not covered by tests
if err != nil {
analyticsx.TrackError(ctx, tracer, err)
log.Fatal(err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/scan/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func NewOpenAPIScanCmd() (scanCmd *cobra.Command) {
}

internalCmd.TrackScanReport(ctx, tracer, reporter)
if err = internalCmd.PrintOrExportReport(internalCmd.GetOutputFormat(), internalCmd.GetOutputTransport(), reporter); err != nil {
if err = internalCmd.PrintOrExportReport(internalCmd.GetReportFormat(), internalCmd.GetReportTransport(), reporter); err != nil {

Check warning on line 105 in cmd/scan/openapi.go

View check run for this annotation

Codecov / codecov/patch

cmd/scan/openapi.go#L105

Added line #L105 was not covered by tests
analyticsx.TrackError(ctx, tracer, err)
log.Fatal(err)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/cmd/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (

func TrackScanReport(ctx context.Context, tracer trace.Tracer, reporter *report.Reporter) {
analyticsx.TrackEvent(ctx, tracer, "Scan Report", []attribute.KeyValue{
attribute.Int("vulnerabilityCount", len(reporter.GetVulnerabilityReports())),
attribute.Bool("hasVulnerability", reporter.HasVulnerability()),
attribute.Bool("hasHighRiskSeverityVulnerability", reporter.HasHighRiskOrHigherSeverityVulnerability()),
attribute.Int("issuesCount", len(reporter.GetIssueReports())),
attribute.Bool("hasIssue", reporter.HasIssue()),
attribute.Bool("hasHighRiskSeverityIssue", reporter.HasHighRiskOrHigherSeverityIssue()),

Check warning on line 16 in internal/cmd/analytics.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/analytics.go#L14-L16

Added lines #L14 - L16 were not covered by tests
})
}
24 changes: 12 additions & 12 deletions internal/cmd/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ var (
includeScans []string
excludeScans []string

outputFormat string
outputTransport string
outputPath string
outputURL string
reportFormat string
reportTransport string
reportFile string
reportURL string

noProgress bool
severityThreshold float64
Expand All @@ -34,10 +34,10 @@ func AddCommonArgs(cmd *cobra.Command) {
cmd.Flags().StringArrayVarP(&includeScans, "scans", "", includeScans, "Include specific scans")
cmd.Flags().StringArrayVarP(&excludeScans, "exclude-scans", "e", excludeScans, "Exclude specific scans")

cmd.Flags().StringVarP(&outputFormat, "format", "", "table", "Output format (table, json, yaml)")
cmd.Flags().StringVarP(&outputTransport, "output-transport", "", "file", "The transport to use for output (e.g. file, http)")
cmd.Flags().StringVarP(&outputPath, "output-path", "", "", "The file to write the output to")
cmd.Flags().StringVarP(&outputURL, "output-url", "", "", "The URL to send the output to")
cmd.Flags().StringVarP(&reportFormat, "report-format", "", "table", "Report format (table, json, yaml)")
cmd.Flags().StringVarP(&reportTransport, "report-transport", "", "file", "The transport to use for report (e.g. file, http)")
cmd.Flags().StringVarP(&reportFile, "report-file", "", "", "The file to write the report to")
cmd.Flags().StringVarP(&reportURL, "report-url", "", "", "The URL to send the report to")

cmd.Flags().BoolVarP(&noProgress, "no-progress", "", false, "Disable progress output")
cmd.Flags().Float64VarP(&severityThreshold, "severity-threshold", "", 1, "Threshold to trigger stderr output if at least one vulnerability CVSS is higher")
Expand Down Expand Up @@ -89,12 +89,12 @@ func GetExcludeScans() []string {
return filteredScans
}

func GetOutputFormat() string {
return outputFormat
func GetReportFormat() string {
return reportFormat
}

func GetOutputTransport() string {
return outputTransport
func GetReportTransport() string {
return reportTransport
}

func GetNoProgress() bool {
Expand Down
12 changes: 6 additions & 6 deletions internal/cmd/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ func TestAddCommonArgs(t *testing.T) {
"--cookie=sessionid=12345",
"--scans=scan1",
"--scans=scan2",
"--format=json",
"--output-transport=http",
"--output-path=/tmp/output",
"--output-url=http://example.com/output",
"--report-format=json",
"--report-transport=http",
"--report-file=/tmp/output",
"--report-url=http://example.com/output",
"--no-progress",
"--severity-threshold=5",
},
Expand Down Expand Up @@ -117,8 +117,8 @@ func TestAddCommonArgs(t *testing.T) {
assert.Equal(t, tt.expected.cookies, cmd.GetCookies())
assert.Equal(t, tt.expected.includeScans, cmd.GetIncludeScans())
assert.Equal(t, tt.expected.excludeScans, cmd.GetExcludeScans())
assert.Equal(t, tt.expected.outputFormat, cmd.GetOutputFormat())
assert.Equal(t, tt.expected.outputTransport, cmd.GetOutputTransport())
assert.Equal(t, tt.expected.outputFormat, cmd.GetReportFormat())
assert.Equal(t, tt.expected.outputTransport, cmd.GetReportTransport())
assert.Equal(t, tt.expected.noProgress, cmd.GetNoProgress())
assert.Equal(t, tt.expected.severityThreshold, cmd.GetSeverityThreshold())
})
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/printtable/fingerprint_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func FingerprintScanReport(reporter *report.Reporter) {
report := reporter.GetReportByID(fingerprint.DiscoverFingerPrintScanID)
report := reporter.GetScanReportByID(fingerprint.DiscoverFingerPrintScanID)

Check warning on line 12 in internal/cmd/printtable/fingerprint_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/fingerprint_table.go#L12

Added line #L12 was not covered by tests
if report == nil || !report.HasData() {
return
}
Expand Down
66 changes: 30 additions & 36 deletions internal/cmd/printtable/report_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@ package printtable

import (
"fmt"
"net/url"
"sort"

"github.com/cerberauth/vulnapi/report"
"github.com/olekukonko/tablewriter"
)

type ScanVulnerabilityReport struct {
type ScanIssueReport struct {
OperationMethod string `json:"method"`
OperationPath string `json:"path"`

Vuln *report.VulnerabilityReport `json:"vuln"`
Issue *report.IssueReport `json:"issue"`
}

type SortByPathAndSeverity []*ScanVulnerabilityReport
type SortByPathAndSeverity []*ScanIssueReport

func (a SortByPathAndSeverity) Len() int { return len(a) }
func (a SortByPathAndSeverity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortByPathAndSeverity) Less(i, j int) bool {
if a[i].OperationPath == a[j].OperationPath {
if a[i].OperationMethod == a[j].OperationMethod {
return a[i].Vuln.Issue.CVSS.Score > a[j].Vuln.Issue.CVSS.Score
return a[i].Issue.CVSS.Score > a[j].Issue.CVSS.Score
}

return a[i].OperationMethod < a[j].OperationMethod
Expand All @@ -32,38 +31,33 @@ func (a SortByPathAndSeverity) Less(i, j int) bool {
return a[i].OperationPath < a[j].OperationPath
}

func NewScanVulnerabilityReports(r *report.Report) []*ScanVulnerabilityReport {
vulnReports := r.GetFailedVulnerabilityReports()
vulns := make([]*ScanVulnerabilityReport, 0, len(vulnReports))
for _, vulnReport := range vulnReports {
url, urlErr := url.Parse(r.Operation.URL)
if urlErr != nil {
continue
}

vulns = append(vulns, &ScanVulnerabilityReport{
OperationMethod: r.Operation.Method,
OperationPath: url.Path,
func NewScanIssueReports(r *report.ScanReport) []*ScanIssueReport {
reports := r.GetFailedIssueReports()
issues := make([]*ScanIssueReport, 0, len(reports))
for _, ir := range reports {
issues = append(issues, &ScanIssueReport{
OperationMethod: ir.Operation.Method,
OperationPath: ir.Operation.URL.Path,

Vuln: vulnReport,
Issue: ir,
})
}

return vulns
return issues
}

func NewFullScanVulnerabilityReports(reports []*report.Report) []*ScanVulnerabilityReport {
vulns := make([]*ScanVulnerabilityReport, 0)
func NewFullScanIssueReports(reports []*report.ScanReport) []*ScanIssueReport {
vulns := make([]*ScanIssueReport, 0)
for _, r := range reports {
vulns = append(vulns, NewScanVulnerabilityReports(r)...)
vulns = append(vulns, NewScanIssueReports(r)...)
}

sort.Sort(SortByPathAndSeverity(vulns))

return vulns
}

func severityTableColor(v *report.VulnerabilityReport) int {
func severityTableColor(v *report.IssueReport) int {

Check warning on line 60 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L60

Added line #L60 was not covered by tests
switch {
case v.IsLowRiskSeverity() || v.IsInfoRiskSeverity():
return tablewriter.BgBlueColor
Expand All @@ -79,7 +73,7 @@ func severityTableColor(v *report.VulnerabilityReport) int {
}

func DisplayReportSummaryTable(r *report.Reporter) {
if r == nil || len(r.GetReports()) == 0 {
if r == nil || len(r.GetScanReports()) == 0 {

Check warning on line 76 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L76

Added line #L76 was not covered by tests
return
}

Expand All @@ -91,8 +85,8 @@ func DisplayReportSummaryTable(r *report.Reporter) {
tableColors[0] = tablewriter.Colors{tablewriter.Bold}
tableColors[1] = tablewriter.Colors{tablewriter.Bold}

for _, status := range report.VulnerabilityReportStatuses {
scansNumber := len(r.GetReportsByVulnerabilityStatus(status))
for _, status := range report.IssueReportStatuses {
scansNumber := len(r.GetReportsByIssueStatus(status))

Check warning on line 89 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L88-L89

Added lines #L88 - L89 were not covered by tests

row := []string{
status.String(),
Expand All @@ -107,27 +101,27 @@ func DisplayReportSummaryTable(r *report.Reporter) {
}

func DisplayReportTable(r *report.Reporter) {
if r == nil || !r.HasVulnerability() {
if r == nil || !r.HasIssue() {

Check warning on line 104 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L104

Added line #L104 was not covered by tests
return
}

headers := []string{"Operation", "Risk Level", "CVSS 4.0 Score", "OWASP", "Vulnerability"}
headers := []string{"Operation", "Risk Level", "CVSS 4.0 Score", "OWASP", "Issue"}

Check warning on line 108 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L108

Added line #L108 was not covered by tests
table := CreateTable(headers)

vulnerabilityReports := NewFullScanVulnerabilityReports(r.GetReports())
for _, vulnReport := range vulnerabilityReports {
IssueReports := NewFullScanIssueReports(r.GetScanReports())
for _, issueReport := range IssueReports {

Check warning on line 112 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L111-L112

Added lines #L111 - L112 were not covered by tests
row := []string{
fmt.Sprintf("%s %s", vulnReport.OperationMethod, vulnReport.OperationPath),
vulnReport.Vuln.SeverityLevelString(),
fmt.Sprintf("%.1f", vulnReport.Vuln.Issue.CVSS.Score),
string(vulnReport.Vuln.Classifications.OWASP),
vulnReport.Vuln.Name,
fmt.Sprintf("%s %s", issueReport.OperationMethod, issueReport.OperationPath),
issueReport.Issue.SeverityLevelString(),
fmt.Sprintf("%.1f", issueReport.Issue.CVSS.Score),
string(issueReport.Issue.Classifications.OWASP),
issueReport.Issue.Name,

Check warning on line 118 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L114-L118

Added lines #L114 - L118 were not covered by tests
}

tableColors := make([]tablewriter.Colors, len(headers))
for i := range tableColors {
if i == 1 {
tableColors[i] = tablewriter.Colors{tablewriter.Bold, severityTableColor(vulnReport.Vuln)}
tableColors[i] = tablewriter.Colors{tablewriter.Bold, severityTableColor(issueReport.Issue)}

Check warning on line 124 in internal/cmd/printtable/report_table.go

View check run for this annotation

Codecov / codecov/patch

internal/cmd/printtable/report_table.go#L124

Added line #L124 was not covered by tests
} else {
tableColors[i] = tablewriter.Colors{}
}
Expand Down
Loading

0 comments on commit 93741f2

Please sign in to comment.