github.com/anchore/syft@v1.38.2/internal/task/unknowns_tasks.go (about)

     1  package task
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	intFile "github.com/anchore/syft/internal/file"
     8  	"github.com/anchore/syft/internal/log"
     9  	"github.com/anchore/syft/internal/sbomsync"
    10  	"github.com/anchore/syft/syft/cataloging"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/pkg"
    13  	"github.com/anchore/syft/syft/sbom"
    14  )
    15  
    16  const unknownsLabelerTaskName = "unknowns-labeler"
    17  
    18  func NewUnknownsLabelerTask(cfg cataloging.UnknownsConfig) Task {
    19  	return NewTask(unknownsLabelerTaskName, unknownsLabelerTask{cfg}.processUnknowns)
    20  }
    21  
    22  type unknownsLabelerTask struct {
    23  	cataloging.UnknownsConfig
    24  }
    25  
    26  // processUnknowns removes unknown entries that have valid packages reported for the locations
    27  func (c unknownsLabelerTask) processUnknowns(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
    28  	accessor := builder.(sbomsync.Accessor)
    29  	accessor.WriteToSBOM(func(s *sbom.SBOM) {
    30  		c.finalize(resolver, s)
    31  	})
    32  	return nil
    33  }
    34  
    35  func (c unknownsLabelerTask) finalize(resolver file.Resolver, s *sbom.SBOM) {
    36  	hasPackageReference := coordinateReferenceLookup(resolver, s)
    37  
    38  	if c.RemoveWhenPackagesDefined {
    39  		for coords := range s.Artifacts.Unknowns {
    40  			if !hasPackageReference(coords) {
    41  				continue
    42  			}
    43  			delete(s.Artifacts.Unknowns, coords)
    44  		}
    45  	}
    46  
    47  	if s.Artifacts.Unknowns == nil {
    48  		s.Artifacts.Unknowns = map[file.Coordinates][]string{}
    49  	}
    50  
    51  	if c.IncludeExecutablesWithoutPackages {
    52  		for coords := range s.Artifacts.Executables {
    53  			if !hasPackageReference(coords) {
    54  				s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], formatUnknown("no package identified in executable file", unknownsLabelerTaskName))
    55  			}
    56  		}
    57  	}
    58  
    59  	if c.IncludeUnexpandedArchives {
    60  		ctx := context.Background()
    61  		for coords := range s.Artifacts.FileMetadata {
    62  			format, _, notArchiveErr := intFile.IdentifyArchive(ctx, coords.RealPath, nil)
    63  			if format != nil && notArchiveErr == nil && !hasPackageReference(coords) {
    64  				s.Artifacts.Unknowns[coords] = append(s.Artifacts.Unknowns[coords], "archive not cataloged")
    65  			}
    66  		}
    67  	}
    68  }
    69  
    70  func formatUnknown(err string, task ...string) string {
    71  	return strings.Join(task, "/") + ": " + err
    72  }
    73  
    74  func coordinateReferenceLookup(resolver file.Resolver, s *sbom.SBOM) func(coords file.Coordinates) bool {
    75  	allPackageCoords := file.NewCoordinateSet()
    76  
    77  	// include all directly included locations that result in packages
    78  	for p := range s.Artifacts.Packages.Enumerate() {
    79  		allPackageCoords.Add(p.Locations.CoordinateSet().ToSlice()...)
    80  	}
    81  
    82  	// include owned files, for example specified by package managers.
    83  	// relationships for these owned files may be disabled, but we always want to include them
    84  	for p := range s.Artifacts.Packages.Enumerate() {
    85  		if f, ok := p.Metadata.(pkg.FileOwner); ok {
    86  			for _, ownedFilePath := range f.OwnedFiles() {
    87  				// resolve these owned files, as they may have symlinks
    88  				// but coordinates we will test against are always absolute paths
    89  				locations, err := resolver.FilesByPath(ownedFilePath)
    90  				if err != nil {
    91  					log.Debugf("unable to resolve owned file '%s': %v", ownedFilePath, err)
    92  				}
    93  				for _, loc := range locations {
    94  					allPackageCoords.Add(loc.Coordinates)
    95  				}
    96  			}
    97  		}
    98  	}
    99  
   100  	// include relationships
   101  	for _, r := range s.Relationships {
   102  		_, fromPkgOk := r.From.(pkg.Package)
   103  		fromFile, fromFileOk := r.From.(file.Coordinates)
   104  		_, toPkgOk := r.To.(pkg.Package)
   105  		toFile, toFileOk := r.To.(file.Coordinates)
   106  		if fromPkgOk && toFileOk {
   107  			allPackageCoords.Add(toFile)
   108  		} else if fromFileOk && toPkgOk {
   109  			allPackageCoords.Add(fromFile)
   110  		}
   111  	}
   112  
   113  	return allPackageCoords.Contains
   114  }