Skip to content

Commit

Permalink
with tui interactions for vex discovery
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <[email protected]>
  • Loading branch information
wagoodman committed Jun 11, 2024
1 parent 9f91ffd commit cf78dc9
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 2 deletions.
55 changes: 55 additions & 0 deletions cmd/grype/cli/ui/handle_vex_document_discovery_started.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ui

import (
"fmt"

tea "github.com/charmbracelet/bubbletea"
"github.com/dustin/go-humanize"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"

"github.com/anchore/bubbly/bubbles/taskprogress"
"github.com/anchore/grype/grype/event/parsers"
"github.com/anchore/grype/internal/log"
)

type vexDocumentDiscoveryStager struct {
prog progress.StagedProgressable
}

func (s vexDocumentDiscoveryStager) Stage() string {
stage := s.prog.Stage()
if stage == "downloading" {
// note: since validation is baked into the download progress there is no visibility into this stage.
// for that reason we report "validating" on the last byte being downloaded (which tends to be the longest
// since go-downloader is doing this work).
if s.prog.Current() >= s.prog.Size()-1 {
return "validating"
}
// show intermediate progress of the download
return fmt.Sprintf("%s / %s", humanize.Bytes(uint64(s.prog.Current())), humanize.Bytes(uint64(s.prog.Size())))
}
return stage
}

func (m *Handler) handleVexDocumentDiscoveryStarted(e partybus.Event) ([]tea.Model, tea.Cmd) {
prog, err := parsers.ParseVexDocumentDiscoveryStarted(e)
if err != nil {
log.WithFields("error", err).Warn("unable to parse event")
return nil, nil
}

tsk := m.newTaskProgress(
taskprogress.Title{
Default: "Search for VEX Documents",
Running: "Searching for VEX Documents",
Success: "Searched for VEX Documents",
},
taskprogress.WithStagedProgressable(prog), // ignore the static stage provided by the event
taskprogress.WithStager(vexDocumentDiscoveryStager{prog: prog}),
)

tsk.HideStageOnSuccess = false

return []tea.Model{tsk}, tsk.Init()
}
1 change: 1 addition & 0 deletions cmd/grype/cli/ui/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func New(cfg HandlerConfig) *Handler {
event.UpdateVulnerabilityDatabase: h.handleUpdateVulnerabilityDatabase,
event.VulnerabilityScanningStarted: h.handleVulnerabilityScanningStarted,
event.DatabaseDiffingStarted: h.handleDatabaseDiffStarted,
event.VexDocumentDiscoveryStarted: h.handleVexDocumentDiscoveryStarted,
})

return h
Expand Down
1 change: 1 addition & 0 deletions grype/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
UpdateVulnerabilityDatabase partybus.EventType = typePrefix + "-update-vulnerability-database"
VulnerabilityScanningStarted partybus.EventType = typePrefix + "-vulnerability-scanning-started"
DatabaseDiffingStarted partybus.EventType = typePrefix + "-database-diffing-started"
VexDocumentDiscoveryStarted partybus.EventType = typePrefix + "-vex-document-discovery-started"

// Events exclusively for the CLI

Expand Down
13 changes: 13 additions & 0 deletions grype/event/parsers/parsers.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ func ParseDatabaseDiffingStarted(e partybus.Event) (*monitor.DBDiff, error) {
return &mon, nil
}

func ParseVexDocumentDiscoveryStarted(e partybus.Event) (progress.StagedProgressable, error) {
if err := checkEventType(e.Type, event.VexDocumentDiscoveryStarted); err != nil {
return nil, err
}

prog, ok := e.Value.(progress.StagedProgressable)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}

return prog, nil
}

type UpdateCheck struct {
New string
Current string
Expand Down
46 changes: 44 additions & 2 deletions grype/vex/openvex/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ package openvex
import (
"errors"
"fmt"
"strings"

"github.com/anchore/grype/grype/event"
"github.com/anchore/grype/internal/bus"
"github.com/openvex/discovery/pkg/discovery"
"github.com/openvex/discovery/pkg/oci"
openvex "github.com/openvex/go-vex/pkg/vex"
"github.com/scylladb/go-set/strset"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"strings"

"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/pkg"
Expand Down Expand Up @@ -293,6 +297,8 @@ func (ovm *Processor) DiscoverVexDocuments(pkgContext *pkg.Context, rawVexData i
return nil, fmt.Errorf("extracting identifiers from context")
}

prog, stage := trackVexDiscovery(identifiers)

allDocs := []*openvex.VEX{}

// If we already have some vex data, add it
Expand All @@ -301,18 +307,34 @@ func (ovm *Processor) DiscoverVexDocuments(pkgContext *pkg.Context, rawVexData i
}

agent := discovery.NewAgent()
ids := strset.New()

for _, i := range identifiers {
if !strings.HasPrefix(i, "pkg:") {
continue
}

stage.Set(fmt.Sprintf("searching %s", i))

discoveredDocs, err := agent.ProbePurl(i)
if err != nil {
prog.SetError(err)
return nil, fmt.Errorf("probing package url or vex data: %w", err)
}

// prune any existing documents so they are not applied multiple times
for j, doc := range discoveredDocs {
if ids.Has(doc.ID) {
discoveredDocs = append(discoveredDocs[:j], discoveredDocs[j+1:]...)
}
ids.Add(doc.ID)
}

allDocs = append(allDocs, discoveredDocs...)
}
stage.Set(fmt.Sprintf("%d documents", len(allDocs)))

prog.SetCompleted()

vexdata, err := openvex.MergeDocuments(allDocs)
if err != nil {
Expand All @@ -321,3 +343,23 @@ func (ovm *Processor) DiscoverVexDocuments(pkgContext *pkg.Context, rawVexData i

return vexdata, nil
}

func trackVexDiscovery(identifiers []string) (*progress.Manual, *progress.AtomicStage) {
stage := progress.NewAtomicStage("")
prog := progress.NewManual(-1)

bus.Publish(partybus.Event{
Type: event.VexDocumentDiscoveryStarted,
Source: identifiers,
Value: progress.StagedProgressable(struct {
progress.Stager
progress.Progressable
}{
Stager: stage,
Progressable: prog,
}),
Error: nil,
})

return prog, stage
}

0 comments on commit cf78dc9

Please sign in to comment.