mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 00:43:20 +01:00
--------- Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
114 lines
3.5 KiB
Go
114 lines
3.5 KiB
Go
package task
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/anchore/archiver/v3"
|
|
"github.com/anchore/syft/internal/log"
|
|
"github.com/anchore/syft/internal/sbomsync"
|
|
"github.com/anchore/syft/syft/cataloging"
|
|
"github.com/anchore/syft/syft/file"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
"github.com/anchore/syft/syft/sbom"
|
|
)
|
|
|
|
const unknownsLabelerTaskName = "unknowns-labeler"
|
|
|
|
func NewUnknownsLabelerTask(cfg cataloging.UnknownsConfig) Task {
|
|
return NewTask(unknownsLabelerTaskName, unknownsLabelerTask{cfg}.processUnknowns)
|
|
}
|
|
|
|
type unknownsLabelerTask struct {
|
|
cataloging.UnknownsConfig
|
|
}
|
|
|
|
// processUnknowns removes unknown entries that have valid packages reported for the locations
|
|
func (c unknownsLabelerTask) processUnknowns(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
|
|
accessor := builder.(sbomsync.Accessor)
|
|
accessor.WriteToSBOM(func(s *sbom.SBOM) {
|
|
c.finalize(resolver, s)
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (c unknownsLabelerTask) finalize(resolver file.Resolver, s *sbom.SBOM) {
|
|
hasPackageReference := coordinateReferenceLookup(resolver, s)
|
|
|
|
if c.RemoveWhenPackagesDefined {
|
|
for coords := range s.Artifacts.Unknowns {
|
|
if !hasPackageReference(coords) {
|
|
continue
|
|
}
|
|
delete(s.Artifacts.Unknowns, coords)
|
|
}
|
|
}
|
|
|
|
if s.Artifacts.Unknowns == nil {
|
|
s.Artifacts.Unknowns = map[file.Coordinates][]string{}
|
|
}
|
|
|
|
if c.IncludeExecutablesWithoutPackages {
|
|
for coords := range s.Artifacts.Executables {
|
|
if !hasPackageReference(coords) {
|
|
s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], formatUnknown("no package identified in executable file", unknownsLabelerTaskName))
|
|
}
|
|
}
|
|
}
|
|
|
|
if c.IncludeUnexpandedArchives {
|
|
for coords := range s.Artifacts.FileMetadata {
|
|
unarchiver, notArchiveErr := archiver.ByExtension(coords.RealPath)
|
|
if unarchiver != nil && notArchiveErr == nil && !hasPackageReference(coords) {
|
|
s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], "archive not cataloged")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func formatUnknown(err string, task ...string) string {
|
|
return strings.Join(task, "/") + ": " + err
|
|
}
|
|
|
|
func coordinateReferenceLookup(resolver file.Resolver, s *sbom.SBOM) func(coords file.Coordinates) bool {
|
|
allPackageCoords := file.NewCoordinateSet()
|
|
|
|
// include all directly included locations that result in packages
|
|
for p := range s.Artifacts.Packages.Enumerate() {
|
|
allPackageCoords.Add(p.Locations.CoordinateSet().ToSlice()...)
|
|
}
|
|
|
|
// include owned files, for example specified by package managers.
|
|
// relationships for these owned files may be disabled, but we always want to include them
|
|
for p := range s.Artifacts.Packages.Enumerate() {
|
|
if f, ok := p.Metadata.(pkg.FileOwner); ok {
|
|
for _, ownedFilePath := range f.OwnedFiles() {
|
|
// resolve these owned files, as they may have symlinks
|
|
// but coordinates we will test against are always absolute paths
|
|
locations, err := resolver.FilesByPath(ownedFilePath)
|
|
if err != nil {
|
|
log.Debugf("unable to resolve owned file '%s': %v", ownedFilePath, err)
|
|
}
|
|
for _, loc := range locations {
|
|
allPackageCoords.Add(loc.Coordinates)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// include relationships
|
|
for _, r := range s.Relationships {
|
|
_, fromPkgOk := r.From.(pkg.Package)
|
|
fromFile, fromFileOk := r.From.(file.Coordinates)
|
|
_, toPkgOk := r.To.(pkg.Package)
|
|
toFile, toFileOk := r.To.(file.Coordinates)
|
|
if fromPkgOk && toFileOk {
|
|
allPackageCoords.Add(toFile)
|
|
} else if fromFileOk && toPkgOk {
|
|
allPackageCoords.Add(fromFile)
|
|
}
|
|
}
|
|
|
|
return allPackageCoords.Contains
|
|
}
|