diff --git a/internal/formats/common/spdxhelpers/source_info.go b/internal/formats/common/spdxhelpers/source_info.go index 81c63348d652..fd692cd69393 100644 --- a/internal/formats/common/spdxhelpers/source_info.go +++ b/internal/formats/common/spdxhelpers/source_info.go @@ -47,6 +47,9 @@ func SourceInfo(p pkg.Package) string { default: answer = "acquired package info from the following paths" } + if p.FoundBy == "sbom-cataloger" { + answer = "acquired package info from SBOM" + } var paths []string for _, l := range p.Locations.ToSlice() { paths = append(paths, l.RealPath) diff --git a/syft/pkg/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go index 98d98436d2d7..20afe542cb0d 100644 --- a/syft/pkg/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -28,6 +28,7 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/ruby" "github.com/anchore/syft/syft/pkg/cataloger/rust" "github.com/anchore/syft/syft/pkg/cataloger/swift" + "github.com/anchore/syft/syft/pkg/cataloger/sbom" "github.com/anchore/syft/syft/source" ) @@ -58,6 +59,7 @@ func ImageCatalogers(cfg Config) []Cataloger { golang.NewGoModuleBinaryCataloger(), dotnet.NewDotnetDepsCataloger(), portage.NewPortageCataloger(), + sbom.NewSBOMCataloger(), }, cfg.Catalogers) } @@ -84,6 +86,7 @@ func DirectoryCatalogers(cfg Config) []Cataloger { cpp.NewConanfileCataloger(), portage.NewPortageCataloger(), haskell.NewHackageCataloger(), + sbom.NewSBOMCataloger(), }, cfg.Catalogers) } @@ -113,6 +116,7 @@ func AllCatalogers(cfg Config) []Cataloger { cpp.NewConanfileCataloger(), portage.NewPortageCataloger(), haskell.NewHackageCataloger(), + sbom.NewSBOMCataloger(), }, cfg.Catalogers) } diff --git a/syft/pkg/cataloger/sbom/cataloger.go b/syft/pkg/cataloger/sbom/cataloger.go new file mode 100644 index 000000000000..31a0d4611c9c --- /dev/null +++ b/syft/pkg/cataloger/sbom/cataloger.go @@ -0,0 +1,70 @@ +package sbom + +import ( + "bytes" + "fmt" + "github.com/anchore/syft/internal/formats/cyclonedxjson" + "github.com/anchore/syft/internal/formats/cyclonedxxml" + "github.com/anchore/syft/internal/formats/spdx22json" + "github.com/anchore/syft/internal/formats/spdx22tagvalue" + "github.com/anchore/syft/internal/formats/syftjson" + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" + "github.com/anchore/syft/syft/sbom" + "io" +) + +// NewSBOMCataloger returns a new SBOM cataloger object loaded from saved SBOM JSON. +func NewSBOMCataloger() *common.GenericCataloger { + globParsers := map[string]common.ParserFn{ + "**/*.syft.json": parseSyftJSON, + "**/bom.json": parseCyclonedxJSON, + "**/bom.xml": parseCyclonedxXML, + "**/*.cdx.json": parseCyclonedxJSON, + "**/*.cdx.xml": parseCyclonedxXML, + "**/*.spdx.json": parseSpdxJSON, + "**/*.spdx": parseSpdx, + } + return common.NewGenericCataloger(nil, globParsers, "sbom-cataloger") +} + +func parseSyftJSON(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) { + return parseSBOM(path, reader, syftjson.Format()) +} + +func parseCyclonedxJSON(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) { + return parseSBOM(path, reader, cyclonedxjson.Format()) +} + +func parseCyclonedxXML(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) { + return parseSBOM(path, reader, cyclonedxxml.Format()) +} + +func parseSpdxJSON(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) { + return parseSBOM(path, reader, spdx22json.Format()) +} + +func parseSpdx(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) { + return parseSBOM(path, reader, spdx22tagvalue.Format()) +} + +func parseSBOM(_ string, reader io.Reader, format sbom.Format) ([]*pkg.Package, []artifact.Relationship, error) { + by, err := io.ReadAll(reader) + if err != nil { + return nil, nil, fmt.Errorf("unable to read sbom: %w", err) + } + + s, err := format.Decode(bytes.NewReader(by)) + if err != nil { + return nil, nil, fmt.Errorf("unable to decode sbom: %w", err) + } + + var packages []*pkg.Package + for _, p := range s.Artifacts.PackageCatalog.Sorted() { + x := p // copy + packages = append(packages, &x) + } + + return packages, nil, nil +}