github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/cmd/syft/cli/options/catalog.go (about)

     1  package options
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/iancoleman/strcase"
     9  	"github.com/mitchellh/go-homedir"
    10  
    11  	"github.com/anchore/clio"
    12  	"github.com/anchore/fangs"
    13  	"github.com/anchore/syft/internal"
    14  	"github.com/anchore/syft/internal/log"
    15  	"github.com/anchore/syft/syft/pkg/cataloger"
    16  	golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
    17  	"github.com/anchore/syft/syft/pkg/cataloger/kernel"
    18  	pythonCataloger "github.com/anchore/syft/syft/pkg/cataloger/python"
    19  	"github.com/anchore/syft/syft/source"
    20  )
    21  
    22  type Catalog struct {
    23  	Catalogers                      []string           `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
    24  	Package                         pkg                `yaml:"package" json:"package" mapstructure:"package"`
    25  	Golang                          golang             `yaml:"golang" json:"golang" mapstructure:"golang"`
    26  	LinuxKernel                     linuxKernel        `yaml:"linux-kernel" json:"linux-kernel" mapstructure:"linux-kernel"`
    27  	Python                          python             `yaml:"python" json:"python" mapstructure:"python"`
    28  	FileMetadata                    fileMetadata       `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
    29  	FileClassification              fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
    30  	FileContents                    fileContents       `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
    31  	Secrets                         secrets            `yaml:"secrets" json:"secrets" mapstructure:"secrets"`
    32  	Registry                        registry           `yaml:"registry" json:"registry" mapstructure:"registry"`
    33  	Exclusions                      []string           `yaml:"exclude" json:"exclude" mapstructure:"exclude"`
    34  	Platform                        string             `yaml:"platform" json:"platform" mapstructure:"platform"`
    35  	Name                            string             `yaml:"name" json:"name" mapstructure:"name"`
    36  	Source                          sourceCfg          `yaml:"source" json:"source" mapstructure:"source"`
    37  	Parallelism                     int                `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"`                                                                         // the number of catalog workers to run in parallel
    38  	DefaultImagePullSource          string             `yaml:"default-image-pull-source" json:"default-image-pull-source" mapstructure:"default-image-pull-source"`                               // specify default image pull source
    39  	BasePath                        string             `yaml:"base-path" json:"base-path" mapstructure:"base-path"`                                                                               // specify base path for all file paths
    40  	ExcludeBinaryOverlapByOwnership bool               `yaml:"exclude-binary-overlap-by-ownership" json:"exclude-binary-overlap-by-ownership" mapstructure:"exclude-binary-overlap-by-ownership"` // exclude synthetic binary packages owned by os package files
    41  }
    42  
    43  var _ interface {
    44  	clio.FlagAdder
    45  	clio.PostLoader
    46  } = (*Catalog)(nil)
    47  
    48  func DefaultCatalog() Catalog {
    49  	return Catalog{
    50  		Package:                         defaultPkg(),
    51  		LinuxKernel:                     defaultLinuxKernel(),
    52  		FileMetadata:                    defaultFileMetadata(),
    53  		FileClassification:              defaultFileClassification(),
    54  		FileContents:                    defaultFileContents(),
    55  		Secrets:                         defaultSecrets(),
    56  		Source:                          defaultSourceCfg(),
    57  		Parallelism:                     1,
    58  		ExcludeBinaryOverlapByOwnership: true,
    59  	}
    60  }
    61  
    62  func (cfg *Catalog) AddFlags(flags clio.FlagSet) {
    63  	var validScopeValues []string
    64  	for _, scope := range source.AllScopes {
    65  		validScopeValues = append(validScopeValues, strcase.ToDelimited(string(scope), '-'))
    66  	}
    67  	flags.StringVarP(&cfg.Package.Cataloger.Scope, "scope", "s",
    68  		fmt.Sprintf("selection of layers to catalog, options=%v", validScopeValues))
    69  
    70  	flags.StringVarP(&cfg.Platform, "platform", "",
    71  		"an optional platform specifier for container image sources (e.g. 'linux/arm64', 'linux/arm64/v8', 'arm64', 'linux')")
    72  
    73  	flags.StringArrayVarP(&cfg.Exclusions, "exclude", "",
    74  		"exclude paths from being scanned using a glob expression")
    75  
    76  	flags.StringArrayVarP(&cfg.Catalogers, "catalogers", "",
    77  		"enable one or more package catalogers")
    78  
    79  	flags.StringVarP(&cfg.Source.Name, "name", "",
    80  		"set the name of the target being analyzed")
    81  
    82  	if pfp, ok := flags.(fangs.PFlagSetProvider); ok {
    83  		flagSet := pfp.PFlagSet()
    84  		flagSet.Lookup("name").Deprecated = "use: source-name"
    85  	}
    86  
    87  	flags.StringVarP(&cfg.Source.Name, "source-name", "",
    88  		"set the name of the target being analyzed")
    89  
    90  	flags.StringVarP(&cfg.Source.Version, "source-version", "",
    91  		"set the version of the target being analyzed")
    92  
    93  	flags.StringVarP(&cfg.BasePath, "base-path", "",
    94  		"base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory")
    95  }
    96  
    97  func (cfg *Catalog) PostLoad() error {
    98  	// parse options on this struct
    99  	var catalogers []string
   100  	for _, c := range cfg.Catalogers {
   101  		for _, f := range strings.Split(c, ",") {
   102  			catalogers = append(catalogers, strings.TrimSpace(f))
   103  		}
   104  	}
   105  	sort.Strings(catalogers)
   106  	cfg.Catalogers = catalogers
   107  
   108  	if err := checkDefaultSourceValues(cfg.DefaultImagePullSource); err != nil {
   109  		return err
   110  	}
   111  
   112  	if cfg.Name != "" {
   113  		log.Warnf("name parameter is deprecated. please use: source-name. name will be removed in a future version")
   114  		if cfg.Source.Name == "" {
   115  			cfg.Source.Name = cfg.Name
   116  		}
   117  	}
   118  
   119  	return nil
   120  }
   121  
   122  func (cfg Catalog) ToCatalogerConfig() cataloger.Config {
   123  	return cataloger.Config{
   124  		Search: cataloger.SearchConfig{
   125  			IncludeIndexedArchives:   cfg.Package.SearchIndexedArchives,
   126  			IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
   127  			Scope:                    cfg.Package.Cataloger.GetScope(),
   128  		},
   129  		Catalogers:  cfg.Catalogers,
   130  		Parallelism: cfg.Parallelism,
   131  		Golang: golangCataloger.NewGoCatalogerOpts().
   132  			WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses).
   133  			WithLocalModCacheDir(cfg.Golang.LocalModCacheDir).
   134  			WithSearchRemoteLicenses(cfg.Golang.SearchRemoteLicenses).
   135  			WithProxy(cfg.Golang.Proxy).
   136  			WithNoProxy(cfg.Golang.NoProxy),
   137  		LinuxKernel: kernel.LinuxCatalogerConfig{
   138  			CatalogModules: cfg.LinuxKernel.CatalogModules,
   139  		},
   140  		Python: pythonCataloger.CatalogerConfig{
   141  			GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements,
   142  		},
   143  		ExcludeBinaryOverlapByOwnership: cfg.ExcludeBinaryOverlapByOwnership,
   144  	}
   145  }
   146  
   147  var validDefaultSourceValues = []string{"registry", "docker", "podman", ""}
   148  
   149  func checkDefaultSourceValues(source string) error {
   150  	validValues := internal.NewStringSet(validDefaultSourceValues...)
   151  	if !validValues.Contains(source) {
   152  		validValuesString := strings.Join(validDefaultSourceValues, ", ")
   153  		return fmt.Errorf("%s is not a valid default source; please use one of the following: %s''", source, validValuesString)
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  func expandFilePath(file string) (string, error) {
   160  	if file != "" {
   161  		expandedPath, err := homedir.Expand(file)
   162  		if err != nil {
   163  			return "", fmt.Errorf("unable to expand file path=%q: %w", file, err)
   164  		}
   165  		file = expandedPath
   166  	}
   167  	return file, nil
   168  }