Skip to content

Commit

Permalink
fix: handle individual cataloger panics (anchore#1636)
Browse files Browse the repository at this point in the history
  • Loading branch information
kzantow authored Mar 1, 2023
1 parent c2dcfbe commit 0ee95d1
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 20 deletions.
5 changes: 1 addition & 4 deletions cmd/syft/cli/eventloop/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,11 @@ func generateCatalogPackagesTask(app *config.Application) (Task, error) {

task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, app.ToCatalogerConfig())
if err != nil {
return nil, err
}

results.PackageCatalog = packageCatalog
results.LinuxDistribution = theDistro

return relationships, nil
return relationships, err
}

return task, nil
Expand Down
5 changes: 1 addition & 4 deletions syft/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,10 @@ func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []
}

catalog, relationships, err := cataloger.Catalog(resolver, release, cfg.Parallelism, catalogers...)
if err != nil {
return nil, nil, nil, err
}

relationships = append(relationships, newSourceRelationshipsFromCatalog(src, catalog)...)

return catalog, relationships, release, nil
return catalog, relationships, release, err
}

func newSourceRelationshipsFromCatalog(src *source.Source, c *pkg.Catalog) []artifact.Relationship {
Expand Down
28 changes: 16 additions & 12 deletions syft/pkg/cataloger/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cataloger
import (
"fmt"
"math"
"runtime/debug"
"sync"

"github.com/hashicorp/go-multierror"
Expand Down Expand Up @@ -49,8 +50,15 @@ func newMonitor() (*progress.Manual, *progress.Manual) {
return &filesProcessed, &packagesDiscovered
}

func runCataloger(cataloger pkg.Cataloger, resolver source.FileResolver) (*catalogResult, error) {
catalogerResult := new(catalogResult)
func runCataloger(cataloger pkg.Cataloger, resolver source.FileResolver) (catalogerResult *catalogResult, err error) {
// handle individual cataloger panics
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v at:\n%s", e, string(debug.Stack()))
}
}()

catalogerResult = new(catalogResult)

// find packages from the underlying raw data
log.WithFields("cataloger", cataloger.Name()).Trace("cataloging started")
Expand Down Expand Up @@ -88,7 +96,7 @@ func runCataloger(cataloger pkg.Cataloger, resolver source.FileResolver) (*catal
}
catalogerResult.Relationships = append(catalogerResult.Relationships, relationships...)
log.WithFields("cataloger", cataloger.Name()).Trace("cataloging complete")
return catalogerResult, nil
return catalogerResult, err
}

// Catalog a given source (container image or filesystem) with the given catalogers, returning all discovered packages.
Expand All @@ -100,7 +108,11 @@ func runCataloger(cataloger pkg.Cataloger, resolver source.FileResolver) (*catal
func Catalog(resolver source.FileResolver, release *linux.Release, parallelism int, catalogers ...pkg.Cataloger) (*pkg.Catalog, []artifact.Relationship, error) {
catalog := pkg.NewCatalog()
var allRelationships []artifact.Relationship

filesProcessed, packagesDiscovered := newMonitor()
defer filesProcessed.SetCompleted()
defer packagesDiscovered.SetCompleted()

// perform analysis, accumulating errors for each failed analysis
var errs error

Expand Down Expand Up @@ -158,7 +170,6 @@ func Catalog(resolver source.FileResolver, release *linux.Release, parallelism i
for result := range results {
if result.Error != nil {
errs = multierror.Append(errs, result.Error)
continue
}
for _, p := range result.Packages {
catalog.Add(p)
Expand All @@ -168,14 +179,7 @@ func Catalog(resolver source.FileResolver, release *linux.Release, parallelism i

allRelationships = append(allRelationships, pkg.NewRelationships(catalog)...)

if errs != nil {
return nil, nil, errs
}

filesProcessed.SetCompleted()
packagesDiscovered.SetCompleted()

return catalog, allRelationships, nil
return catalog, allRelationships, errs
}

func packageFileOwnershipRelationships(p pkg.Package, resolver source.FilePathResolver) ([]artifact.Relationship, error) {
Expand Down
67 changes: 67 additions & 0 deletions syft/pkg/cataloger/catalog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cataloger

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)

func Test_CatalogPanicHandling(t *testing.T) {
catalog, relationships, err := Catalog(
source.NewMockResolverForPaths(),
&linux.Release{},
1,
panickingCataloger{},
returningCataloger{},
)

require.Error(t, err)
require.Contains(t, err.Error(), "catalog_test.go")
require.Len(t, catalog.Sorted(), 2)
require.Len(t, relationships, 1)
}

type panickingCataloger struct{}

func (p panickingCataloger) Name() string {
return "panicking-cataloger"
}

func (p panickingCataloger) Catalog(_ source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
panic("something bad happened")
}

var _ pkg.Cataloger = (*panickingCataloger)(nil)

type returningCataloger struct{}

func (p returningCataloger) Name() string {
return "returning-cataloger"
}

func (p returningCataloger) Catalog(_ source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
pkg1 := pkg.Package{
Name: "package-1",
Version: "1.0",
}
pkg1.SetID()
pkg2 := pkg.Package{
Name: "package-2",
Version: "2.0",
}
pkg2.SetID()
return []pkg.Package{pkg1, pkg2}, []artifact.Relationship{
{
From: pkg1,
To: pkg2,
Type: artifact.DependencyOfRelationship,
},
}, nil
}

var _ pkg.Cataloger = (*returningCataloger)(nil)

0 comments on commit 0ee95d1

Please sign in to comment.