mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 15:06:36 +01:00
Add secrets search capability (#367)
* add initial secrets cataloger Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update ETUI elements with new catalogers (file metadata, digests, and secrets) Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update secrets cataloger to read full contents into memory for searching Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * quick prototype of parallelization secret regex search Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * quick prototype with single aggregated regex Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * quick prototype for secret search line-by-line Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * quick prototype hybrid secrets search Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add secrets cataloger with line strategy Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * adjust verbiage towards SearchResults instead of Secrets + add tests Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update json schema with secrets cataloger results Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * address PR comments Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update readme with secrets config options Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * ensure file catalogers call AllLocations once Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
+135
-4
@@ -25,7 +25,7 @@ const maxBarWidth = 50
|
||||
const statusSet = common.SpinnerDotSet // SpinnerCircleOutlineSet
|
||||
const completedStatus = "✔" // "●"
|
||||
const tileFormat = color.Bold
|
||||
const statusTitleTemplate = " %s %-28s "
|
||||
const statusTitleTemplate = " %s %-31s "
|
||||
const interval = 150 * time.Millisecond
|
||||
|
||||
var (
|
||||
@@ -270,7 +270,7 @@ func ReadImageHandler(ctx context.Context, fr *frame.Frame, event partybus.Event
|
||||
|
||||
// PackageCatalogerStartedHandler periodically writes catalog statistics to a single line.
|
||||
func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
monitor, err := syftEventParsers.ParseCatalogerStarted(event)
|
||||
monitor, err := syftEventParsers.ParsePackageCatalogerStarted(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
||||
}
|
||||
@@ -284,7 +284,7 @@ func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event
|
||||
|
||||
_, spinner := startProcess()
|
||||
stream := progress.StreamMonitors(ctx, []progress.Monitorable{monitor.FilesProcessed, monitor.PackagesDiscovered}, interval)
|
||||
title := tileFormat.Sprint("Cataloging image")
|
||||
title := tileFormat.Sprint("Cataloging packages")
|
||||
|
||||
formatFn := func(p int64) {
|
||||
spin := color.Magenta.Sprint(spinner.Next())
|
||||
@@ -301,7 +301,7 @@ func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Cataloged image")
|
||||
title = tileFormat.Sprint("Cataloged packages")
|
||||
auxInfo := auxInfoFormat.Sprintf("[%d packages]", monitor.PackagesDiscovered.Current())
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
||||
}()
|
||||
@@ -309,6 +309,137 @@ func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event
|
||||
return nil
|
||||
}
|
||||
|
||||
// SecretsCatalogerStartedHandler shows the intermittent secrets searching progress.
|
||||
// nolint:dupl
|
||||
func SecretsCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
prog, err := syftEventParsers.ParseSecretsCatalogingStarted(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
formatter, spinner := startProcess()
|
||||
stream := progress.Stream(ctx, prog, interval)
|
||||
title := tileFormat.Sprint("Cataloging secrets")
|
||||
|
||||
formatFn := func(p progress.Progress) {
|
||||
progStr, err := formatter.Format(p)
|
||||
spin := color.Magenta.Sprint(spinner.Next())
|
||||
if err != nil {
|
||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
||||
} else {
|
||||
auxInfo := auxInfoFormat.Sprintf("[%d secrets]", prog.SecretsDiscovered.Current())
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s %s", spin, title, progStr, auxInfo))
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
formatFn(progress.Progress{})
|
||||
for p := range stream {
|
||||
formatFn(p)
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Cataloged secrets")
|
||||
auxInfo := auxInfoFormat.Sprintf("[%d secrets]", prog.SecretsDiscovered.Current())
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
||||
}()
|
||||
return err
|
||||
}
|
||||
|
||||
// FileMetadataCatalogerStartedHandler shows the intermittent secrets searching progress.
|
||||
// nolint:dupl
|
||||
func FileMetadataCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
prog, err := syftEventParsers.ParseFileMetadataCatalogingStarted(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
formatter, spinner := startProcess()
|
||||
stream := progress.Stream(ctx, prog, interval)
|
||||
title := tileFormat.Sprint("Cataloging file metadata")
|
||||
|
||||
formatFn := func(p progress.Progress) {
|
||||
progStr, err := formatter.Format(p)
|
||||
spin := color.Magenta.Sprint(spinner.Next())
|
||||
if err != nil {
|
||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
||||
} else {
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, progStr))
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
formatFn(progress.Progress{})
|
||||
for p := range stream {
|
||||
formatFn(p)
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Cataloged file metadata")
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
||||
}()
|
||||
return err
|
||||
}
|
||||
|
||||
// FileMetadataCatalogerStartedHandler shows the intermittent secrets searching progress.
|
||||
// nolint:dupl
|
||||
func FileDigestsCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
prog, err := syftEventParsers.ParseFileDigestsCatalogingStarted(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wg.Add(1)
|
||||
|
||||
formatter, spinner := startProcess()
|
||||
stream := progress.Stream(ctx, prog, interval)
|
||||
title := tileFormat.Sprint("Cataloging file digests")
|
||||
|
||||
formatFn := func(p progress.Progress) {
|
||||
progStr, err := formatter.Format(p)
|
||||
spin := color.Magenta.Sprint(spinner.Next())
|
||||
if err != nil {
|
||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
||||
} else {
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, progStr))
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
formatFn(progress.Progress{})
|
||||
for p := range stream {
|
||||
formatFn(p)
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Cataloged file digests")
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
||||
}()
|
||||
return err
|
||||
}
|
||||
|
||||
// ImportStartedHandler shows the intermittent upload progress to Anchore Enterprise.
|
||||
// nolint:dupl
|
||||
func ImportStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
|
||||
+10
-1
@@ -27,7 +27,7 @@ func NewHandler() *Handler {
|
||||
// RespondsTo indicates if the handler is capable of handling the given event.
|
||||
func (r *Handler) RespondsTo(event partybus.Event) bool {
|
||||
switch event.Type {
|
||||
case stereoscopeEvent.PullDockerImage, stereoscopeEvent.ReadImage, stereoscopeEvent.FetchImage, syftEvent.PackageCatalogerStarted, syftEvent.ImportStarted:
|
||||
case stereoscopeEvent.PullDockerImage, stereoscopeEvent.ReadImage, stereoscopeEvent.FetchImage, syftEvent.PackageCatalogerStarted, syftEvent.SecretsCatalogerStarted, syftEvent.FileDigestsCatalogerStarted, syftEvent.FileMetadataCatalogerStarted, syftEvent.ImportStarted:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@@ -49,6 +49,15 @@ func (r *Handler) Handle(ctx context.Context, fr *frame.Frame, event partybus.Ev
|
||||
case syftEvent.PackageCatalogerStarted:
|
||||
return PackageCatalogerStartedHandler(ctx, fr, event, wg)
|
||||
|
||||
case syftEvent.SecretsCatalogerStarted:
|
||||
return SecretsCatalogerStartedHandler(ctx, fr, event, wg)
|
||||
|
||||
case syftEvent.FileDigestsCatalogerStarted:
|
||||
return FileDigestsCatalogerStartedHandler(ctx, fr, event, wg)
|
||||
|
||||
case syftEvent.FileMetadataCatalogerStarted:
|
||||
return FileMetadataCatalogerStartedHandler(ctx, fr, event, wg)
|
||||
|
||||
case syftEvent.ImportStarted:
|
||||
return ImportStartedHandler(ctx, fr, event, wg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user