Add an opinionated console summary reporter

This commit is contained in:
abhisek 2023-02-02 17:51:43 +05:30
parent dde2ec6e03
commit 1057d9d36c
No known key found for this signature in database
GPG Key ID: CB92A4990C02A88F
4 changed files with 141 additions and 3 deletions

3
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/google/cel-go v0.13.0
github.com/google/osv-scanner v1.1.0
github.com/jedib0t/go-pretty/v6 v6.4.4
github.com/safedep/dry v0.0.0-20230201172119-ff40bd754419
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
@ -23,6 +23,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/masterminds/semver v1.5.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect

7
go.sum
View File

@ -1,5 +1,6 @@
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
@ -28,6 +29,8 @@ github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc=
github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/masterminds/semver v1.5.0 h1:hTxJTTY7tjvnWMrl08O6u3G6BLlKVwxSz01lVac9P8U=
github.com/masterminds/semver v1.5.0/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@ -41,8 +44,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/safedep/dry v0.0.0-20230201172119-ff40bd754419 h1:A41ZjwvBng3TLVZCBKXNKuheUblNnLABnZFELuznnNM=
github.com/safedep/dry v0.0.0-20230201172119-ff40bd754419/go.mod h1:BDeFh8rfhLz1H0F829C6adC7nkmoU9BfGyKlHE+ccF0=
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de h1:07LwA5P5bxaVK8SXtoBfP8qZGcWAtqiFbq54UZnMcyg=
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de/go.mod h1:H111d9khzpHFEqKXb9lgAZ1W5eeK7yEN7ToWu0ak+JI=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=

122
pkg/reporter/console.go Normal file
View File

@ -0,0 +1,122 @@
package reporter
import (
"fmt"
"os"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/safedep/dry/semver"
"github.com/safedep/dry/utils"
"github.com/safedep/vet/pkg/analyzer"
"github.com/safedep/vet/pkg/models"
"github.com/safedep/vet/pkg/policy"
)
type consoleReporter struct{}
func NewConsoleReporter() (Reporter, error) {
return &consoleReporter{}, nil
}
func (r *consoleReporter) Name() string {
return "Console Report Generator"
}
func (r *consoleReporter) AddManifest(manifest *models.PackageManifest) {
tbl := table.NewWriter()
tbl.SetOutputMirror(os.Stdout)
tbl.SetStyle(table.StyleLight)
tbl.AppendHeader(table.Row{"Package", "Attribute", "Summary"})
for _, pkg := range manifest.Packages {
r.report(tbl, pkg)
}
fmt.Print(text.Bold.Sprint("Rendering summary report for: ",
manifest.Path))
fmt.Print("\n")
tbl.Render()
}
func (r *consoleReporter) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
}
func (r *consoleReporter) AddPolicyEvent(event *policy.PolicyEvent) {
}
func (r *consoleReporter) Finish() error {
return nil
}
func (r *consoleReporter) report(tbl table.Writer, pkg *models.Package) {
insight := utils.SafelyGetValue(pkg.Insights)
headerAppended := false
headerAppender := func() {
if headerAppended {
return
}
// Header for this package
tbl.AppendRow(table.Row{
fmt.Sprintf("%s/%s", pkg.PackageDetails.Name, pkg.PackageDetails.Version),
"", "",
})
headerAppended = true
}
// Report vulnerabilities
sm := map[string]int{"CRITICAL": 0, "HIGH": 0}
for _, vuln := range utils.SafelyGetValue(insight.Vulnerabilities) {
for _, s := range utils.SafelyGetValue(vuln.Severities) {
risk := string(utils.SafelyGetValue(s.Risk))
if (risk == "CRITICAL") || (risk == "HIGH") {
sm[risk] += 1
}
}
}
if (sm["CRITICAL"] > 0) || (sm["HIGH"] > 0) {
headerAppender()
tbl.AppendRow(table.Row{"",
text.Bold.Sprint(text.BgRed.Sprint("Vulnerability")),
fmt.Sprintf("Critical:%d High:%d",
sm["CRITICAL"], sm["HIGH"])})
}
// Popularity
projects := utils.SafelyGetValue(insight.Projects)
if len(projects) > 0 {
p := projects[0]
sc := utils.SafelyGetValue(p.Stars)
ic := utils.SafelyGetValue(p.Issues)
if (sc > 0) && (sc < 10) && (ic > 0) && (ic < 5) {
headerAppender()
tbl.AppendRow(table.Row{"",
text.Bold.Sprint("Low Popularity"),
fmt.Sprintf("Stars:%d Issues:%d", sc, ic)})
}
}
// High version drift
version := pkg.PackageDetails.Version
latestVersion := utils.SafelyGetValue(insight.PackageCurrentVersion)
driftType, _ := semver.Diff(version, latestVersion)
if driftType.IsMajor() {
headerAppender()
tbl.AppendRow(table.Row{"",
text.Bold.Sprint("Version Drift"),
fmt.Sprintf("%s > %s", version, latestVersion),
})
}
if headerAppended {
tbl.AppendSeparator()
}
}

12
scan.go
View File

@ -24,6 +24,7 @@ var (
dumpJsonManifestDir string
celFilterExpression string
markdownReportPath string
consoleReport bool
)
func newScanCommand() *cobra.Command {
@ -61,6 +62,8 @@ func newScanCommand() *cobra.Command {
"Filter and print packages using CEL")
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
"Generate consolidated markdown report to file")
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", true,
"Minimal summary of package manifest")
cmd.AddCommand(listParsersCommand())
return cmd
@ -111,6 +114,15 @@ func internalStartScan() error {
}
reporters := []reporter.Reporter{}
if consoleReport {
rp, err := reporter.NewConsoleReporter()
if err != nil {
return err
}
reporters = append(reporters, rp)
}
if !utils.IsEmptyString(markdownReportPath) {
rp, err := reporter.NewMarkdownReportGenerator(reporter.MarkdownReportingConfig{
Path: markdownReportPath,