mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 00:22:08 -06:00
Merge pull request #19 from safedep/develop
Sync Develop with Main for Multiple Fixes
This commit is contained in:
commit
5939b9df10
@ -4,7 +4,10 @@
|
||||
helps engineering and security teams to identify potential issues in their open
|
||||
source dependencies and evaluate them against organizational policies.
|
||||
|
||||
[](https://api.securityscorecards.dev/projects/github.com/safedep/vet)
|
||||
[](https://github.com/safedep/vet/actions/workflows/codeql.yml)
|
||||
[](https://github.com/safedep/vet/actions/workflows/scorecard.yml)
|
||||
|
||||
|
||||
## TL;DR
|
||||
|
||||
|
||||
5
auth.go
5
auth.go
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
@ -22,9 +23,7 @@ func newAuthCommand() *cobra.Command {
|
||||
Use: "auth",
|
||||
Short: "Configure and verify Insights API authentication",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("You must choose an appropriate command: configure, verify\n")
|
||||
os.Exit(1)
|
||||
return nil
|
||||
return errors.New("a valid sub-command is required")
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@ -8,7 +8,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-20230203134955-367834d99b1c
|
||||
github.com/safedep/dry v0.0.0-20230216112435-385c68e56634
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
|
||||
2
go.sum
2
go.sum
@ -45,6 +45,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safedep/dry v0.0.0-20230203134955-367834d99b1c h1:zbhTBT463mwcIuCq89GT8pFTU8UtGalBWFaa/wsgVXA=
|
||||
github.com/safedep/dry v0.0.0-20230203134955-367834d99b1c/go.mod h1:yZ8R6kv4pR0yertVoxgBmnN4bvHT8TLubE7aahpWDDk=
|
||||
github.com/safedep/dry v0.0.0-20230216112435-385c68e56634 h1:JRIzwT2Xo7TFH2O1gMJpHS5Fn6jDJdF+/+2JdyhzI3A=
|
||||
github.com/safedep/dry v0.0.0-20230216112435-385c68e56634/go.mod h1:yZ8R6kv4pR0yertVoxgBmnN4bvHT8TLubE7aahpWDDk=
|
||||
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=
|
||||
|
||||
66
internal/ui/progress.go
Normal file
66
internal/ui/progress.go
Normal file
@ -0,0 +1,66 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/progress"
|
||||
)
|
||||
|
||||
var progressWriter progress.Writer
|
||||
|
||||
func StartProgressWriter() {
|
||||
pw := progress.NewWriter()
|
||||
|
||||
pw.SetTrackerLength(25)
|
||||
pw.SetMessageWidth(20)
|
||||
pw.SetSortBy(progress.SortByPercentDsc)
|
||||
pw.SetStyle(progress.StyleDefault)
|
||||
pw.SetOutputWriter(os.Stderr)
|
||||
pw.SetTrackerPosition(progress.PositionRight)
|
||||
pw.SetUpdateFrequency(time.Millisecond * 100)
|
||||
pw.Style().Colors = progress.StyleColorsExample
|
||||
pw.Style().Options.PercentFormat = "%4.1f%%"
|
||||
pw.Style().Visibility.Pinned = true
|
||||
pw.Style().Visibility.ETA = true
|
||||
pw.Style().Visibility.Value = true
|
||||
|
||||
progressWriter = pw
|
||||
go progressWriter.Render()
|
||||
}
|
||||
|
||||
func StopProgressWriter() {
|
||||
if progressWriter != nil {
|
||||
progressWriter.Stop()
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TrackProgress(message string, total int) any {
|
||||
tracker := progress.Tracker{Message: message, Total: int64(total),
|
||||
Units: progress.UnitsDefault}
|
||||
|
||||
if progressWriter != nil {
|
||||
progressWriter.AppendTracker(&tracker)
|
||||
}
|
||||
|
||||
return &tracker
|
||||
}
|
||||
|
||||
func MarkTrackerAsDone(i any) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.MarkAsDone()
|
||||
}
|
||||
}
|
||||
|
||||
func IncrementTrackerTotal(i any, count int) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.UpdateTotal(tracker.Total + int64(count))
|
||||
}
|
||||
}
|
||||
|
||||
func IncrementProgress(i any, count int) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.Increment(int64(count))
|
||||
}
|
||||
}
|
||||
39
internal/ui/spinner.go
Normal file
39
internal/ui/spinner.go
Normal file
@ -0,0 +1,39 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var spinnerChan chan bool
|
||||
|
||||
func StartSpinner(msg string) {
|
||||
style := `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`
|
||||
frames := []rune(style)
|
||||
length := len(frames)
|
||||
|
||||
spinnerChan = make(chan bool)
|
||||
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
go func() {
|
||||
pos := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-spinnerChan:
|
||||
ticker.Stop()
|
||||
return
|
||||
case <-ticker.C:
|
||||
fmt.Printf("\r%s ... %s", msg, string(frames[pos%length]))
|
||||
pos += 1
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func StopSpinner() {
|
||||
spinnerChan <- true
|
||||
|
||||
fmt.Printf("\r")
|
||||
fmt.Println()
|
||||
}
|
||||
@ -2,96 +2,9 @@ package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/progress"
|
||||
"os"
|
||||
)
|
||||
|
||||
var progressWriter progress.Writer
|
||||
var spinnerChan chan bool
|
||||
|
||||
func StartSpinner(msg string) {
|
||||
style := `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`
|
||||
frames := []rune(style)
|
||||
length := len(frames)
|
||||
|
||||
spinnerChan = make(chan bool)
|
||||
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
go func() {
|
||||
pos := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-spinnerChan:
|
||||
ticker.Stop()
|
||||
return
|
||||
case <-ticker.C:
|
||||
fmt.Printf("\r%s ... %s", msg, string(frames[pos%length]))
|
||||
pos += 1
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func StopSpinner() {
|
||||
spinnerChan <- true
|
||||
|
||||
fmt.Printf("\r")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func StartProgressWriter() {
|
||||
pw := progress.NewWriter()
|
||||
|
||||
pw.SetTrackerLength(25)
|
||||
pw.SetMessageWidth(20)
|
||||
pw.SetSortBy(progress.SortByPercentDsc)
|
||||
pw.SetStyle(progress.StyleDefault)
|
||||
pw.SetTrackerPosition(progress.PositionRight)
|
||||
pw.SetUpdateFrequency(time.Millisecond * 100)
|
||||
pw.Style().Colors = progress.StyleColorsExample
|
||||
pw.Style().Options.PercentFormat = "%4.1f%%"
|
||||
pw.Style().Visibility.Pinned = true
|
||||
pw.Style().Visibility.ETA = true
|
||||
pw.Style().Visibility.Value = true
|
||||
|
||||
progressWriter = pw
|
||||
go progressWriter.Render()
|
||||
}
|
||||
|
||||
func StopProgressWriter() {
|
||||
if progressWriter != nil {
|
||||
progressWriter.Stop()
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TrackProgress(message string, total int) any {
|
||||
tracker := progress.Tracker{Message: message, Total: int64(total),
|
||||
Units: progress.UnitsDefault}
|
||||
|
||||
if progressWriter != nil {
|
||||
progressWriter.AppendTracker(&tracker)
|
||||
}
|
||||
|
||||
return &tracker
|
||||
}
|
||||
|
||||
func MarkTrackerAsDone(i any) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.MarkAsDone()
|
||||
}
|
||||
}
|
||||
|
||||
func IncrementTrackerTotal(i any, count int) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.UpdateTotal(tracker.Total + int64(count))
|
||||
}
|
||||
}
|
||||
|
||||
func IncrementProgress(i any, count int) {
|
||||
if tracker, ok := i.(*progress.Tracker); ok {
|
||||
tracker.Increment(int64(count))
|
||||
}
|
||||
func PrintBanner(s string) {
|
||||
fmt.Fprintf(os.Stderr, s)
|
||||
}
|
||||
|
||||
3
main.go
3
main.go
@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/internal/ui"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -68,7 +69,7 @@ func main() {
|
||||
func printBanner() {
|
||||
bRet, err := strconv.ParseBool(os.Getenv("VET_DISABLE_BANNER"))
|
||||
if (err != nil) || (!bRet) {
|
||||
fmt.Print(banner)
|
||||
ui.PrintBanner(banner)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -85,6 +85,8 @@ func (pw *parserWrapper) Ecosystem() string {
|
||||
return models.EcosystemPub
|
||||
case "requirements.txt":
|
||||
return models.EcosystemPyPI
|
||||
case "Pipfile.lock":
|
||||
return models.EcosystemPyPI
|
||||
case "yarn.lock":
|
||||
return models.EcosystemNpm
|
||||
case "gradle.lockfile":
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestListParser(t *testing.T) {
|
||||
parsers := List()
|
||||
assert.Equal(t, 9, len(parsers))
|
||||
assert.Equal(t, 10, len(parsers))
|
||||
}
|
||||
|
||||
func TestInvalidEcosystemMapping(t *testing.T) {
|
||||
|
||||
@ -26,12 +26,17 @@ const (
|
||||
summaryWeightUnpopular = 2
|
||||
summaryWeightMajorDrift = 2
|
||||
|
||||
tagVuln = "vulnerabiity"
|
||||
tagUnpopular = "low popularity"
|
||||
tagDrift = "drift"
|
||||
|
||||
summaryReportMaxUpgradeAdvice = 5
|
||||
)
|
||||
|
||||
type summaryReporterRemediationData struct {
|
||||
pkg *models.Package
|
||||
score int
|
||||
tags []string
|
||||
}
|
||||
|
||||
type summaryReporter struct {
|
||||
@ -100,7 +105,7 @@ func (r *summaryReporter) processForVersionDrift(pkg *models.Package) {
|
||||
driftType, _ := semver.Diff(version, latestVersion)
|
||||
if driftType.IsMajor() {
|
||||
r.summary.metrics.drifts += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightMajorDrift)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightMajorDrift, tagDrift)
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +126,7 @@ func (r *summaryReporter) processForPopularity(pkg *models.Package) {
|
||||
|
||||
if (strings.EqualFold(projectType, "github")) && (starsCount < 10) {
|
||||
r.summary.metrics.unpopular += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightUnpopular)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightUnpopular, tagUnpopular)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,33 +146,39 @@ func (r *summaryReporter) processForVulns(pkg *models.Package) {
|
||||
switch risk {
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskCRITICAL:
|
||||
r.summary.vulns.critical += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightCriticalVuln)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightCriticalVuln, tagVuln)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskHIGH:
|
||||
r.summary.vulns.high += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightHighVuln)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightHighVuln, tagVuln)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskMEDIUM:
|
||||
r.summary.vulns.medium += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightMediumVuln)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightMediumVuln, tagVuln)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskLOW:
|
||||
r.summary.vulns.low += 1
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightLowVuln)
|
||||
r.addPkgForRemediationAdvice(pkg, summaryWeightLowVuln, tagVuln)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *summaryReporter) addPkgForRemediationAdvice(pkg *models.Package, weight int) {
|
||||
func (r *summaryReporter) addPkgForRemediationAdvice(pkg *models.Package,
|
||||
weight int, tag string) {
|
||||
if _, ok := r.remediationScores[pkg.Id()]; !ok {
|
||||
r.remediationScores[pkg.Id()] = &summaryReporterRemediationData{
|
||||
pkg: pkg,
|
||||
pkg: pkg,
|
||||
tags: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
r.remediationScores[pkg.Id()].score += weight
|
||||
|
||||
if utils.FindInSlice(r.remediationScores[pkg.Id()].tags, tag) == -1 {
|
||||
r.remediationScores[pkg.Id()].tags = append(r.remediationScores[pkg.Id()].tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *summaryReporter) Finish() error {
|
||||
@ -181,11 +192,10 @@ func (r *summaryReporter) Finish() error {
|
||||
fmt.Println()
|
||||
fmt.Println(text.Faint.Sprint(summaryListPrependText, r.manifestCountStatement()))
|
||||
fmt.Println()
|
||||
|
||||
r.renderRemediationAdvice()
|
||||
fmt.Println()
|
||||
fmt.Println("Install as a security gate in CI for incremental scan and blocking risky dependencies")
|
||||
fmt.Println("Run `vet ci` to generate CI scripts")
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("Run with `vet --filter=\"...\"` for custom filters to identify risky libraries")
|
||||
fmt.Println()
|
||||
fmt.Println("For more details", text.Bold.Sprint("https://github.com/safedep/vet"))
|
||||
@ -221,7 +231,7 @@ func (r *summaryReporter) renderRemediationAdvice() {
|
||||
tbl.SetOutputMirror(os.Stdout)
|
||||
tbl.SetStyle(table.StyleLight)
|
||||
|
||||
tbl.AppendHeader(table.Row{"Package", "Update To", "Risk Score"})
|
||||
tbl.AppendHeader(table.Row{"Package", "Update To", "Impact"})
|
||||
for idx, sp := range sortedPackages {
|
||||
if idx >= summaryReportMaxUpgradeAdvice {
|
||||
break
|
||||
@ -234,6 +244,17 @@ func (r *summaryReporter) renderRemediationAdvice() {
|
||||
utils.SafelyGetValue(insight.PackageCurrentVersion),
|
||||
sp.score,
|
||||
})
|
||||
|
||||
tagText := ""
|
||||
for _, t := range sp.tags {
|
||||
tagText += text.BgMagenta.Sprint(" "+t+" ") + " "
|
||||
}
|
||||
|
||||
tbl.AppendRow(table.Row{
|
||||
tagText, "", "",
|
||||
})
|
||||
|
||||
tbl.AppendSeparator()
|
||||
}
|
||||
|
||||
tbl.Render()
|
||||
@ -255,7 +276,7 @@ func (r *summaryReporter) packageNameForRemediationAdvice(pkg *models.Package) s
|
||||
}
|
||||
|
||||
func (r *summaryReporter) vulnSummaryStatement() string {
|
||||
return fmt.Sprintf("%d critical, %d high and %d other vulnerabilities were identifier",
|
||||
return fmt.Sprintf("%d critical, %d high and %d other vulnerabilities were identified",
|
||||
r.summary.vulns.critical, r.summary.vulns.high,
|
||||
r.summary.vulns.medium+r.summary.vulns.low)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user