github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/internal/task/file_tasks.go (about)

     1  package task
     2  
     3  import (
     4  	"context"
     5  	"crypto"
     6  	"fmt"
     7  
     8  	"github.com/anchore/syft/internal/sbomsync"
     9  	"github.com/anchore/syft/syft/artifact"
    10  	"github.com/anchore/syft/syft/file"
    11  	"github.com/anchore/syft/syft/file/cataloger/executable"
    12  	"github.com/anchore/syft/syft/file/cataloger/filecontent"
    13  	"github.com/anchore/syft/syft/file/cataloger/filedigest"
    14  	"github.com/anchore/syft/syft/file/cataloger/filemetadata"
    15  	"github.com/anchore/syft/syft/pkg"
    16  	"github.com/anchore/syft/syft/sbom"
    17  )
    18  
    19  func NewFileDigestCatalogerTask(selection file.Selection, hashers ...crypto.Hash) Task {
    20  	if selection == file.NoFilesSelection || len(hashers) == 0 {
    21  		return nil
    22  	}
    23  
    24  	digestsCataloger := filedigest.NewCataloger(hashers)
    25  
    26  	fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
    27  		accessor := builder.(sbomsync.Accessor)
    28  
    29  		coordinates, ok := coordinatesForSelection(selection, builder.(sbomsync.Accessor))
    30  		if !ok {
    31  			return nil
    32  		}
    33  
    34  		result, err := digestsCataloger.Catalog(ctx, resolver, coordinates...)
    35  		if err != nil {
    36  			return fmt.Errorf("unable to catalog file digests: %w", err)
    37  		}
    38  
    39  		accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
    40  			sbom.Artifacts.FileDigests = result
    41  		})
    42  
    43  		return nil
    44  	}
    45  
    46  	return NewTask("file-digest-cataloger", fn)
    47  }
    48  
    49  func NewFileMetadataCatalogerTask(selection file.Selection) Task {
    50  	if selection == file.NoFilesSelection {
    51  		return nil
    52  	}
    53  
    54  	metadataCataloger := filemetadata.NewCataloger()
    55  
    56  	fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
    57  		accessor := builder.(sbomsync.Accessor)
    58  
    59  		coordinates, ok := coordinatesForSelection(selection, builder.(sbomsync.Accessor))
    60  		if !ok {
    61  			return nil
    62  		}
    63  
    64  		result, err := metadataCataloger.Catalog(ctx, resolver, coordinates...)
    65  		if err != nil {
    66  			return err
    67  		}
    68  
    69  		accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
    70  			sbom.Artifacts.FileMetadata = result
    71  		})
    72  
    73  		return nil
    74  	}
    75  
    76  	return NewTask("file-metadata-cataloger", fn)
    77  }
    78  
    79  func NewFileContentCatalogerTask(cfg filecontent.Config) Task {
    80  	if len(cfg.Globs) == 0 {
    81  		return nil
    82  	}
    83  
    84  	cat := filecontent.NewCataloger(cfg)
    85  
    86  	fn := func(ctx context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
    87  		accessor := builder.(sbomsync.Accessor)
    88  
    89  		result, err := cat.Catalog(ctx, resolver)
    90  		if err != nil {
    91  			return err
    92  		}
    93  
    94  		accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
    95  			sbom.Artifacts.FileContents = result
    96  		})
    97  
    98  		return nil
    99  	}
   100  
   101  	return NewTask("file-content-cataloger", fn)
   102  }
   103  
   104  func NewExecutableCatalogerTask(selection file.Selection, cfg executable.Config) Task {
   105  	if selection == file.NoFilesSelection {
   106  		return nil
   107  	}
   108  
   109  	cat := executable.NewCataloger(cfg)
   110  
   111  	fn := func(_ context.Context, resolver file.Resolver, builder sbomsync.Builder) error {
   112  		accessor := builder.(sbomsync.Accessor)
   113  
   114  		result, err := cat.Catalog(resolver)
   115  		if err != nil {
   116  			return err
   117  		}
   118  
   119  		accessor.WriteToSBOM(func(sbom *sbom.SBOM) {
   120  			sbom.Artifacts.Executables = result
   121  		})
   122  
   123  		return nil
   124  	}
   125  
   126  	return NewTask("file-executable-cataloger", fn)
   127  }
   128  
   129  // TODO: this should be replaced with a fix that allows passing a coordinate or location iterator to the cataloger
   130  // Today internal to both cataloger this functions differently: a slice of coordinates vs a channel of locations
   131  func coordinatesForSelection(selection file.Selection, accessor sbomsync.Accessor) ([]file.Coordinates, bool) {
   132  	if selection == file.AllFilesSelection {
   133  		return nil, true
   134  	}
   135  
   136  	if selection == file.FilesOwnedByPackageSelection {
   137  		var coordinates []file.Coordinates
   138  
   139  		accessor.ReadFromSBOM(func(sbom *sbom.SBOM) {
   140  			for _, r := range sbom.Relationships {
   141  				if r.Type != artifact.ContainsRelationship {
   142  					continue
   143  				}
   144  				if _, ok := r.From.(pkg.Package); !ok {
   145  					continue
   146  				}
   147  				if c, ok := r.To.(file.Coordinates); ok {
   148  					coordinates = append(coordinates, c)
   149  				}
   150  			}
   151  		})
   152  
   153  		if len(coordinates) == 0 {
   154  			return nil, false
   155  		}
   156  
   157  		return coordinates, true
   158  	}
   159  
   160  	return nil, false
   161  }