mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 22:46:36 +01:00
Switch UI to bubbletea (#1888)
* add bubbletea UI Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * swap pipeline to go 1.20.x and add attest guard for cosign binary Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * update note in developing.md about the required golang version Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix merge conflict for windows path handling Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * temp test for attest handler Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add addtional test iterations for background reader Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
+30
-16
@@ -4,37 +4,51 @@ defined here there should be a corresponding event parser defined in the parsers
|
||||
*/
|
||||
package event
|
||||
|
||||
import "github.com/wagoodman/go-partybus"
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
)
|
||||
|
||||
const (
|
||||
// AppUpdateAvailable is a partybus event that occurs when an application update is available
|
||||
AppUpdateAvailable partybus.EventType = "syft-app-update-available"
|
||||
typePrefix = internal.ApplicationName
|
||||
cliTypePrefix = typePrefix + "-cli"
|
||||
|
||||
// Events from the syft library
|
||||
|
||||
// PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun
|
||||
PackageCatalogerStarted partybus.EventType = "syft-package-cataloger-started-event"
|
||||
PackageCatalogerStarted partybus.EventType = typePrefix + "-package-cataloger-started-event"
|
||||
|
||||
//nolint:gosec
|
||||
// SecretsCatalogerStarted is a partybus event that occurs when the secrets cataloging has begun
|
||||
SecretsCatalogerStarted partybus.EventType = "syft-secrets-cataloger-started-event"
|
||||
SecretsCatalogerStarted partybus.EventType = typePrefix + "-secrets-cataloger-started-event"
|
||||
|
||||
// FileMetadataCatalogerStarted is a partybus event that occurs when the file metadata cataloging has begun
|
||||
FileMetadataCatalogerStarted partybus.EventType = "syft-file-metadata-cataloger-started-event"
|
||||
FileMetadataCatalogerStarted partybus.EventType = typePrefix + "-file-metadata-cataloger-started-event"
|
||||
|
||||
// FileDigestsCatalogerStarted is a partybus event that occurs when the file digests cataloging has begun
|
||||
FileDigestsCatalogerStarted partybus.EventType = "syft-file-digests-cataloger-started-event"
|
||||
FileDigestsCatalogerStarted partybus.EventType = typePrefix + "-file-digests-cataloger-started-event"
|
||||
|
||||
// FileIndexingStarted is a partybus event that occurs when the directory resolver begins indexing a filesystem
|
||||
FileIndexingStarted partybus.EventType = "syft-file-indexing-started-event"
|
||||
|
||||
// Exit is a partybus event that occurs when an analysis result is ready for final presentation
|
||||
Exit partybus.EventType = "syft-exit-event"
|
||||
|
||||
// ImportStarted is a partybus event that occurs when an SBOM upload process has begun
|
||||
ImportStarted partybus.EventType = "syft-import-started-event"
|
||||
FileIndexingStarted partybus.EventType = typePrefix + "-file-indexing-started-event"
|
||||
|
||||
// AttestationStarted is a partybus event that occurs when starting an SBOM attestation process
|
||||
AttestationStarted partybus.EventType = "syft-attestation-started-event"
|
||||
AttestationStarted partybus.EventType = typePrefix + "-attestation-started-event"
|
||||
|
||||
// CatalogerTaskStarted is a partybus event that occurs when starting a task within a cataloger
|
||||
CatalogerTaskStarted partybus.EventType = "syft-cataloger-task-started"
|
||||
CatalogerTaskStarted partybus.EventType = typePrefix + "-cataloger-task-started"
|
||||
|
||||
// Events exclusively for the CLI
|
||||
|
||||
// CLIAppUpdateAvailable is a partybus event that occurs when an application update is available
|
||||
CLIAppUpdateAvailable partybus.EventType = cliTypePrefix + "-app-update-available"
|
||||
|
||||
// CLIReport is a partybus event that occurs when an analysis result is ready for final presentation to stdout
|
||||
CLIReport partybus.EventType = cliTypePrefix + "-report"
|
||||
|
||||
// CLINotification is a partybus event that occurs when auxiliary information is ready for presentation to stderr
|
||||
CLINotification partybus.EventType = cliTypePrefix + "-notification"
|
||||
|
||||
// CLIExit is a partybus event that occurs when an analysis result is ready for final presentation
|
||||
CLIExit partybus.EventType = cliTypePrefix + "-exit-event"
|
||||
)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package event
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
)
|
||||
|
||||
// TODO: this should be refactored to support read-only/write-only access using idioms of the progress lib
|
||||
|
||||
type CatalogerTask struct {
|
||||
prog *progress.Manual
|
||||
// Title
|
||||
@@ -25,7 +28,7 @@ func (e *CatalogerTask) init() {
|
||||
e.prog = progress.NewManual(-1)
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: CatalogerTaskStarted,
|
||||
Type: event.CatalogerTaskStarted,
|
||||
Source: e,
|
||||
})
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
type ShellProgress struct {
|
||||
io.Reader
|
||||
*progress.Manual
|
||||
progress.Progressable
|
||||
}
|
||||
|
||||
type Title struct {
|
||||
|
||||
@@ -23,7 +23,7 @@ type ErrBadPayload struct {
|
||||
}
|
||||
|
||||
func (e *ErrBadPayload) Error() string {
|
||||
return fmt.Sprintf("event='%s' has bad event payload field='%v': '%+v'", string(e.Type), e.Field, e.Value)
|
||||
return fmt.Sprintf("event='%s' has bad event payload field=%q: %q", string(e.Type), e.Field, e.Value)
|
||||
}
|
||||
|
||||
func newPayloadErr(t partybus.EventType, field string, value interface{}) error {
|
||||
@@ -111,12 +111,12 @@ func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgress
|
||||
return path, prog, nil
|
||||
}
|
||||
|
||||
func ParseCatalogerTaskStarted(e partybus.Event) (*event.CatalogerTask, error) {
|
||||
func ParseCatalogerTaskStarted(e partybus.Event) (*monitor.CatalogerTask, error) {
|
||||
if err := checkEventType(e.Type, event.CatalogerTaskStarted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
source, ok := e.Source.(*event.CatalogerTask)
|
||||
source, ok := e.Source.(*monitor.CatalogerTask)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Source", e.Source)
|
||||
}
|
||||
@@ -124,50 +124,6 @@ func ParseCatalogerTaskStarted(e partybus.Event) (*event.CatalogerTask, error) {
|
||||
return source, nil
|
||||
}
|
||||
|
||||
func ParseExit(e partybus.Event) (func() error, error) {
|
||||
if err := checkEventType(e.Type, event.Exit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fn, ok := e.Value.(func() error)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return fn, nil
|
||||
}
|
||||
|
||||
func ParseAppUpdateAvailable(e partybus.Event) (string, error) {
|
||||
if err := checkEventType(e.Type, event.AppUpdateAvailable); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newVersion, ok := e.Value.(string)
|
||||
if !ok {
|
||||
return "", newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return newVersion, nil
|
||||
}
|
||||
|
||||
func ParseImportStarted(e partybus.Event) (string, progress.StagedProgressable, error) {
|
||||
if err := checkEventType(e.Type, event.ImportStarted); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
host, ok := e.Source.(string)
|
||||
if !ok {
|
||||
return "", nil, newPayloadErr(e.Type, "Source", e.Source)
|
||||
}
|
||||
|
||||
prog, ok := e.Value.(progress.StagedProgressable)
|
||||
if !ok {
|
||||
return "", nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return host, prog, nil
|
||||
}
|
||||
|
||||
func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progressable, *monitor.GenericTask, error) {
|
||||
if err := checkEventType(e.Type, event.AttestationStarted); err != nil {
|
||||
return nil, nil, nil, err
|
||||
@@ -183,5 +139,71 @@ func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progres
|
||||
return nil, nil, nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return sp.Reader, sp.Manual, &source, nil
|
||||
return sp.Reader, sp.Progressable, &source, nil
|
||||
}
|
||||
|
||||
// CLI event types
|
||||
|
||||
func ParseCLIExit(e partybus.Event) (func() error, error) {
|
||||
if err := checkEventType(e.Type, event.CLIExit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fn, ok := e.Value.(func() error)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return fn, nil
|
||||
}
|
||||
|
||||
func ParseCLIAppUpdateAvailable(e partybus.Event) (string, error) {
|
||||
if err := checkEventType(e.Type, event.CLIAppUpdateAvailable); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
newVersion, ok := e.Value.(string)
|
||||
if !ok {
|
||||
return "", newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return newVersion, nil
|
||||
}
|
||||
|
||||
func ParseCLIReport(e partybus.Event) (string, string, error) {
|
||||
if err := checkEventType(e.Type, event.CLIReport); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
context, ok := e.Source.(string)
|
||||
if !ok {
|
||||
// this is optional
|
||||
context = ""
|
||||
}
|
||||
|
||||
report, ok := e.Value.(string)
|
||||
if !ok {
|
||||
return "", "", newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return context, report, nil
|
||||
}
|
||||
|
||||
func ParseCLINotification(e partybus.Event) (string, string, error) {
|
||||
if err := checkEventType(e.Type, event.CLINotification); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
context, ok := e.Source.(string)
|
||||
if !ok {
|
||||
// this is optional
|
||||
context = ""
|
||||
}
|
||||
|
||||
notification, ok := e.Value.(string)
|
||||
if !ok {
|
||||
return "", "", newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return context, notification, nil
|
||||
}
|
||||
|
||||
@@ -332,14 +332,15 @@ func (r directoryIndexer) addFileToIndex(p string, info os.FileInfo) error {
|
||||
func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string, error) {
|
||||
linkTarget, err := os.Readlink(p)
|
||||
if err != nil {
|
||||
if runtime.GOOS == WindowsOS {
|
||||
p = posixToWindows(p)
|
||||
isOnWindows := windows.HostRunningOnWindows()
|
||||
if isOnWindows {
|
||||
p = windows.FromPosix(p)
|
||||
}
|
||||
|
||||
linkTarget, err = filepath.EvalSymlinks(p)
|
||||
|
||||
if runtime.GOOS == WindowsOS {
|
||||
p = windowsToPosix(p)
|
||||
if isOnWindows {
|
||||
p = windows.ToPosix(p)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
+2
-2
@@ -94,10 +94,10 @@ func newSourceRelationshipsFromCatalog(src source.Source, c *pkg.Collection) []a
|
||||
|
||||
// SetLogger sets the logger object used for all syft logging calls.
|
||||
func SetLogger(logger logger.Logger) {
|
||||
log.Log = logger
|
||||
log.Set(logger)
|
||||
}
|
||||
|
||||
// SetBus sets the event bus for all syft library bus publish events onto (in-library subscriptions are not allowed).
|
||||
func SetBus(b *partybus.Bus) {
|
||||
bus.SetPublisher(b)
|
||||
bus.Set(b)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ package golang
|
||||
import (
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
@@ -37,7 +37,7 @@ func NewGoModuleBinaryCataloger(opts GoCatalogerOpts) pkg.Cataloger {
|
||||
}
|
||||
|
||||
type progressingCataloger struct {
|
||||
progress *event.CatalogerTask
|
||||
progress *monitor.CatalogerTask
|
||||
cataloger *generic.Cataloger
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/internal/fileresolver"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -30,14 +30,14 @@ import (
|
||||
type goLicenses struct {
|
||||
opts GoCatalogerOpts
|
||||
localModCacheResolver file.WritableResolver
|
||||
progress *event.CatalogerTask
|
||||
progress *monitor.CatalogerTask
|
||||
}
|
||||
|
||||
func newGoLicenses(opts GoCatalogerOpts) goLicenses {
|
||||
return goLicenses{
|
||||
opts: opts,
|
||||
localModCacheResolver: modCacheResolver(opts.localModCacheDir),
|
||||
progress: &event.CatalogerTask{
|
||||
progress: &monitor.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: true,
|
||||
Title: "Downloading go mod",
|
||||
@@ -195,7 +195,7 @@ func processCaps(s string) string {
|
||||
})
|
||||
}
|
||||
|
||||
func getModule(progress *event.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
|
||||
func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
|
||||
for _, proxy := range proxies {
|
||||
u, _ := url.Parse(proxy)
|
||||
if proxy == "direct" {
|
||||
@@ -217,7 +217,7 @@ func getModule(progress *event.CatalogerTask, proxies []string, moduleName, modu
|
||||
return
|
||||
}
|
||||
|
||||
func getModuleProxy(progress *event.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
|
||||
func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
|
||||
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
|
||||
progress.SetValue(u)
|
||||
// get the module zip
|
||||
@@ -265,7 +265,7 @@ func findVersionPath(f fs.FS, dir string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func getModuleRepository(progress *event.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
|
||||
func getModuleRepository(progress *monitor.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
|
||||
repoName := moduleName
|
||||
parts := strings.Split(moduleName, "/")
|
||||
if len(parts) > 2 {
|
||||
|
||||
@@ -49,8 +49,7 @@ func parseAuditBinaryEntry(reader unionreader.UnionReader, filename string) []ru
|
||||
// binary, we should not show warnings/logs in this case.
|
||||
return nil
|
||||
}
|
||||
// Use an Info level log here like golang/scan_bin.go
|
||||
log.Infof("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
|
||||
log.Tracef("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user